summaryrefslogtreecommitdiff
path: root/Tools
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Tools
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Tools')
-rw-r--r--Tools/CMakeLists.txt48
-rw-r--r--Tools/DumpRenderTree/AccessibilityController.cpp16
-rw-r--r--Tools/DumpRenderTree/AccessibilityController.h6
-rw-r--r--Tools/DumpRenderTree/AccessibilityTextMarker.h8
-rw-r--r--Tools/DumpRenderTree/AccessibilityUIElement.cpp462
-rw-r--r--Tools/DumpRenderTree/AccessibilityUIElement.h60
-rw-r--r--Tools/DumpRenderTree/Bindings/CodeGeneratorDumpRenderTree.pm563
-rw-r--r--Tools/DumpRenderTree/CMakeLists.txt100
-rw-r--r--Tools/DumpRenderTree/DefaultPolicyDelegate.h13
-rw-r--r--Tools/DumpRenderTree/DerivedSources.make50
-rw-r--r--Tools/DumpRenderTree/DumpRenderTree.h23
-rw-r--r--Tools/DumpRenderTree/DumpRenderTreeCommon.cpp35
-rw-r--r--Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.h43
-rw-r--r--Tools/DumpRenderTree/DumpRenderTreePrefix.h13
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/runtime/ArrayBufferView.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/runtime/JSArrayBufferView.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/runtime/JSExportMacros.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/runtime/TypedArrayInlines.h1
-rw-r--r--Tools/DumpRenderTree/GCController.cpp2
-rw-r--r--Tools/DumpRenderTree/GCController.h4
-rw-r--r--Tools/DumpRenderTree/JavaScriptThreading.cpp157
-rw-r--r--Tools/DumpRenderTree/JavaScriptThreading.h2
-rw-r--r--Tools/DumpRenderTree/PixelDumpSupport.cpp18
-rw-r--r--Tools/DumpRenderTree/PixelDumpSupport.h14
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/CMakeLists.txt61
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npapi.h (renamed from Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npapi.h)0
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npfunctions.h (renamed from Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npfunctions.h)0
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npruntime.h (renamed from Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npruntime.h)0
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp44
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp19
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h7
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSWithinNPP_New.cpp56
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/InvokeDestroysPluginWithinNPP_New.cpp67
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PluginScriptableObjectOverridesAllProperties.cpp82
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/SlowNPPNew.cpp87
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/URLRedirect.cpp167
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp55
-rw-r--r--Tools/DumpRenderTree/TestOptions.h37
-rw-r--r--Tools/DumpRenderTree/TestRunner.cpp466
-rw-r--r--Tools/DumpRenderTree/TestRunner.h106
-rw-r--r--Tools/DumpRenderTree/TextInputController.h (renamed from Tools/DumpRenderTree/gtk/TextInputController.h)28
-rw-r--r--Tools/DumpRenderTree/WorkQueue.cpp7
-rw-r--r--Tools/DumpRenderTree/WorkQueue.h8
-rw-r--r--Tools/DumpRenderTree/WorkQueueItem.h2
-rw-r--r--Tools/DumpRenderTree/atk/AccessibilityCallbacks.h44
-rw-r--r--Tools/DumpRenderTree/atk/AccessibilityCallbacksAtk.cpp297
-rw-r--r--Tools/DumpRenderTree/atk/AccessibilityControllerAtk.cpp145
-rw-r--r--Tools/DumpRenderTree/atk/AccessibilityNotificationHandlerAtk.cpp55
-rw-r--r--Tools/DumpRenderTree/atk/AccessibilityNotificationHandlerAtk.h51
-rw-r--r--Tools/DumpRenderTree/atk/AccessibilityUIElementAtk.cpp1604
-rw-r--r--Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp2
-rw-r--r--Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.h13
-rw-r--r--Tools/DumpRenderTree/config.h45
-rw-r--r--Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp79
-rw-r--r--Tools/DumpRenderTree/gtk/DumpRenderTree.cpp1557
-rw-r--r--Tools/DumpRenderTree/gtk/DumpRenderTreeGtk.h50
-rw-r--r--Tools/DumpRenderTree/gtk/EditingCallbacks.cpp202
-rw-r--r--Tools/DumpRenderTree/gtk/EventSender.cpp1004
-rw-r--r--Tools/DumpRenderTree/gtk/EventSender.h42
-rw-r--r--Tools/DumpRenderTree/gtk/GCControllerGtk.cpp50
-rw-r--r--Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp115
-rw-r--r--Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.cpp78
-rw-r--r--Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.h51
-rw-r--r--Tools/DumpRenderTree/gtk/TestRunnerGtk.cpp914
-rw-r--r--Tools/DumpRenderTree/gtk/TextInputController.cpp215
-rw-r--r--Tools/DumpRenderTree/gtk/WorkQueueItemGtk.cpp102
-rw-r--r--Tools/GNUmakefile.am277
-rw-r--r--Tools/GtkLauncher/GNUmakefile.am42
-rw-r--r--Tools/GtkLauncher/LauncherInspectorWindow.c115
-rw-r--r--Tools/GtkLauncher/main.c564
-rw-r--r--Tools/ImageDiff/CMakeLists.txt14
-rw-r--r--Tools/ImageDiff/PlatformGTK.cmake11
-rw-r--r--Tools/ImageDiff/gtk/ImageDiff.cpp17
-rw-r--r--Tools/MiniBrowser/MBToolbarItem.h (renamed from Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.h)34
-rw-r--r--Tools/MiniBrowser/MiniBrowserWebProcessPlugIn.h34
-rw-r--r--Tools/MiniBrowser/gtk/BrowserDownloadsBar.c1
-rw-r--r--Tools/MiniBrowser/gtk/BrowserSearchBar.c12
-rw-r--r--Tools/MiniBrowser/gtk/BrowserSettingsDialog.c55
-rw-r--r--Tools/MiniBrowser/gtk/BrowserTab.c552
-rw-r--r--Tools/MiniBrowser/gtk/BrowserTab.h60
-rw-r--r--Tools/MiniBrowser/gtk/BrowserWindow.c898
-rw-r--r--Tools/MiniBrowser/gtk/BrowserWindow.h11
-rw-r--r--Tools/MiniBrowser/gtk/CMakeLists.txt64
-rw-r--r--Tools/MiniBrowser/gtk/GNUmakefile.am75
-rw-r--r--Tools/MiniBrowser/gtk/main.c307
-rw-r--r--Tools/Scripts/VCSUtils.pm2433
-rwxr-xr-xTools/Scripts/run-gtk-tests494
-rwxr-xr-xTools/Scripts/webkit-build-directory84
-rwxr-xr-xTools/Scripts/webkitdirs.pm2613
-rw-r--r--Tools/TestWebKitAPI/CMakeLists.txt232
-rw-r--r--Tools/TestWebKitAPI/Counters.cpp36
-rw-r--r--Tools/TestWebKitAPI/Counters.h99
-rw-r--r--Tools/TestWebKitAPI/ForwardingHeaders/WebCore/LayoutUnit.h4
-rw-r--r--Tools/TestWebKitAPI/GNUmakefile.am934
-rw-r--r--Tools/TestWebKitAPI/InjectedBundleController.cpp7
-rw-r--r--Tools/TestWebKitAPI/InjectedBundleController.h4
-rw-r--r--Tools/TestWebKitAPI/InjectedBundleMain.cpp9
-rw-r--r--Tools/TestWebKitAPI/InjectedBundleTest.h2
-rw-r--r--Tools/TestWebKitAPI/JavaScriptTest.cpp9
-rw-r--r--Tools/TestWebKitAPI/JavaScriptTest.h13
-rw-r--r--Tools/TestWebKitAPI/PlatformGTK.cmake158
-rw-r--r--Tools/TestWebKitAPI/PlatformJSCOnly.cmake21
-rw-r--r--Tools/TestWebKitAPI/PlatformUtilities.cpp12
-rw-r--r--Tools/TestWebKitAPI/PlatformUtilities.h33
-rw-r--r--Tools/TestWebKitAPI/PlatformWebView.h45
-rw-r--r--Tools/TestWebKitAPI/Test.h16
-rw-r--r--Tools/TestWebKitAPI/Tests/JavaScriptCore/VMInspector.cpp689
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/AtomicString.cpp9
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/BloomFilter.cpp250
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/CheckedArithmeticOperations.cpp554
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/Condition.cpp257
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/Consume.cpp141
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/CrossThreadTask.cpp150
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/DateMath.cpp208
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/DeletedAddressOfOperator.h84
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/Deque.cpp191
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/EnumTraits.cpp55
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/Expected.cpp512
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/Functional.cpp218
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/HashCountedSet.cpp468
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp780
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/HashSet.cpp354
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/LEBDecoder.cpp241
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/ListHashSet.cpp98
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/Lock.cpp189
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/MediaTime.cpp65
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/MetaAllocator.cpp6
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/NakedPtr.cpp238
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/OptionSet.cpp297
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/Optional.cpp150
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/ParkingLot.cpp273
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/RedBlackTree.cpp2
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/Ref.cpp57
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/RefCounter.cpp170
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/RefLogger.cpp37
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/RefLogger.h10
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/RefPtr.cpp58
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/RunLoop.cpp166
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/Scope.cpp53
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/ScopedLambda.cpp51
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/SetForScope.cpp (renamed from Tools/TestWebKitAPI/Tests/WTF/TemporaryChange.cpp)8
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/StringBuilder.cpp25
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/StringConcatenate.cpp121
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/StringHasher.cpp63
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/StringImpl.cpp550
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/StringOperators.cpp16
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/StringView.cpp928
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/SynchronizedFixedQueue.cpp229
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/TextBreakIterator.cpp146
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/Time.cpp318
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/UniqueRef.cpp93
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/Variant.cpp228
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/Vector.cpp430
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/WTFString.cpp364
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/WeakPtr.cpp193
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/WorkQueue.cpp236
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/darwin/OSObjectPtr.cpp66
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/glib/GUniquePtr.cpp (renamed from Tools/TestWebKitAPI/Tests/WTF/gobject/GUniquePtr.cpp)2
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/glib/WorkQueueGLib.cpp71
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/AffineTransform.cpp1024
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/CARingBuffer.cpp251
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/CSSParser.cpp84
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/CalculationValue.cpp283
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/Color.cpp190
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/ComplexTextController.cpp391
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp2795
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/DFACombiner.cpp121
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/DFAHelpers.h67
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/DFAMinimizer.cpp121
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/ExtendedColor.cpp162
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/FileSystem.cpp122
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/FloatPoint.cpp598
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/FloatRect.cpp783
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/FloatSize.cpp328
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/GridPosition.cpp73
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/HTMLParserIdioms.cpp164
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/IntPoint.cpp283
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/IntRect.cpp615
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/IntSize.cpp332
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/LayoutUnit.cpp42
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/ParsedContentRange.cpp98
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/PublicSuffix.cpp78
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/SampleMap.cpp224
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/SecurityOrigin.cpp146
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/SharedBuffer.cpp163
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/SharedBufferTest.cpp56
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/SharedBufferTest.h46
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/TimeRanges.cpp291
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/TransformationMatrix.cpp1317
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/URL.cpp54
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp1305
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/UserAgentQuirks.cpp96
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/YouTubePluginReplacement.cpp86
-rw-r--r--Tools/TestWebKitAPI/Tests/WebCore/gtk/UserAgentQuirks.cpp63
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/18-characters.html0
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/AboutBlankLoad.cpp5
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/Ahem.ttfbin0 -> 12480 bytes
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/CanHandleRequest.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/CanHandleRequest_Bundle.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/CloseFromWithinCreatePage.cpp94
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/CloseThenTerminate.cpp5
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/CookieManager.cpp9
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/WKViewIsActiveSetIsActive.cpp131
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/WKViewIsActiveSetIsActive_Bundle.cpp52
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/WKViewRestoreZoomAndScrollBackForward.cpp129
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/WKViewUserViewportToContents.cpp148
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/backforward1.html5
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/backforward2.html1
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/DOMWindowExtensionBasic.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/DOMWindowExtensionBasic_Bundle.cpp19
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/DOMWindowExtensionNoCache.cpp5
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/DOMWindowExtensionNoCache_Bundle.cpp19
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/DidAssociateFormControls.cpp5
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/DidAssociateFormControls_Bundle.cpp13
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/DidNotHandleKeyDown.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/DidRemoveFrameFromHiearchyInPageCache.cpp109
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/DidRemoveFrameFromHiearchyInPageCache_Bundle.cpp75
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash_Bundle.cpp13
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/DownloadDecideDestinationCrash.cpp9
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/EnumerateMediaDevices.cpp84
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/EphemeralSessionPushStateNoHistoryCallback.cpp87
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/EvaluateJavaScript.cpp9
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/EventModifiers.cpp82
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/FailedLoad.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/Find.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/ForceRepaint.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/FrameHandle.cpp70
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/FrameMIMETypeHTML.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/FrameMIMETypePNG.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/Geolocation.cpp55
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/GetInjectedBundleInitializationUserDataCallback.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/GetInjectedBundleInitializationUserDataCallback_Bundle.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/HitTestResultNodeHandle.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/HitTestResultNodeHandle_Bundle.cpp13
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleBasic.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleBasic_Bundle.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleFrameHitTest.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleFrameHitTest_Bundle.cpp17
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleInitializationUserDataCallbackWins.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleInitializationUserDataCallbackWins_Bundle.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleMakeAllShadowRootsOpen.cpp109
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleMakeAllShadowRootsOpen_Bundle.cpp98
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/LayoutMilestonesWithAllContentInFrame.cpp9
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/LimitTitleSize.cpp79
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/LoadAlternateHTMLStringWithNonDirectoryURL.cpp37
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/LoadCanceledNoServerRedirectCallback.cpp11
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/LoadCanceledNoServerRedirectCallback_Bundle.cpp11
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/LoadPageOnCrash.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/MenuTypesForMouseEvents.cpp149
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/ModalAlertsSPI.cpp123
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/MouseMoveAfterCrash.cpp9
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/MouseMoveAfterCrash_Bundle.cpp5
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayout.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFails.cpp9
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFails_Bundle.cpp9
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutForImages.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutForImages_Bundle.cpp9
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFrames.cpp11
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFrames_Bundle.cpp9
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayout_Bundle.cpp9
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/PageGroup.cpp80
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/PageLoadBasic.cpp27
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/PageLoadDidChangeLocationWithinPageForFrame.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/ParentFrame.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/ParentFrame_Bundle.cpp11
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/PasteboardNotifications_Bundle.cpp89
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/PendingAPIRequestURL.cpp167
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/PreventEmptyUserAgent.cpp9
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/PrivateBrowsingPushStateNoHistoryCallback.cpp32
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/ProvisionalURLAfterWillSendRequestCallback.cpp89
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/ProvisionalURLAfterWillSendRequestCallback_Bundle.cpp85
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/ReloadPageAfterCrash.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/ResizeReversePaginatedWebView.cpp11
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/ResizeWindowAfterCrash.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/ResponsivenessTimerDoesntFireEarly.cpp5
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/ResponsivenessTimerDoesntFireEarly_Bundle.cpp5
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/RestoreSessionStateContainingFormData.cpp17
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/RestoreSessionStateWithoutNavigation.cpp105
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/ScrollPinningBehaviors.cpp13
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/ShouldGoToBackForwardListItem.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/ShouldGoToBackForwardListItem_Bundle.cpp9
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/ShouldKeepCurrentBackForwardListItemInList.cpp163
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/SpacebarScrolling.cpp27
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/StopLoadingDuringDidFailProvisionalLoad.cpp83
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/StopLoadingDuringDidFailProvisionalLoad_bundle.cpp81
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/TerminateTwice.cpp4
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/TextFieldDidBeginAndEndEditing.cpp137
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/TextFieldDidBeginAndEndEditing_Bundle.cpp76
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/UserMedia.cpp85
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/UserMessage.cpp13
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/UserMessage_Bundle.cpp5
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/WKBundleFileHandle.cpp86
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/WKBundleFileHandle_Bundle.cpp99
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/WKImageCreateCGImageCrash.cpp41
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/WKPageConfiguration.cpp132
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/WKPageCopySessionStateWithFiltering.cpp136
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/WKPageGetScaleFactorNotZero.cpp15
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/WKPageIsPlayingAudio.cpp152
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/WKPreferences.cpp39
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/WKRetainPtr.cpp (renamed from Tools/GtkLauncher/LauncherInspectorWindow.h)43
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/WKString.cpp4
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/WKStringJSString.cpp7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/WebArchive.cpp135
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/WebArchive_Bundle.cpp (renamed from Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.cpp)65
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/WebCoreStatisticsWithNoWebProcess.cpp55
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/WillLoad.cpp11
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/WillLoad_Bundle.cpp15
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/WillSendSubmitEvent.cpp5
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/WillSendSubmitEvent_Bundle.cpp9
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/all-content-in-one-iframe.html1
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/associate-form-controls.html31
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/auto-submitting-form.html20
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/autoplay-check-frame.html16
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/autoplay-check-in-iframe.html16
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/autoplay-check.html20
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/autoplay-no-audio-check.html20
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/autoplay-with-controls.html19
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/bundle-file.html16
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/chinese-character-with-image.html15
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/close-from-within-create-page.html16
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/closed-shadow-tree-test.html28
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/contentBlockerCheck.html13
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/custom-protocol-sync-xhr.html6
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/enumerateMediaDevices.html24
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/execCopy.html15
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/file-with-anchor.html19
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/file-with-mse.html41
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/file-with-video.html18
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/find.html5
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/findRanges.html11
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/geolocationGetCurrentPosition.html3
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/geolocationGetCurrentPositionWithHighAccuracy.html3
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/geolocationWatchPosition.html3
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/geolocationWatchPositionWithHighAccuracy.html3
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/getUserMedia.html14
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/gtk/InputMethodFilter.cpp (renamed from Tools/TestWebKitAPI/Tests/gtk/InputMethodFilter.cpp)100
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/icon.pngbin0 -> 36541 bytes
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/input-focus-blur.html28
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/js-play-with-controls.html20
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/link-with-download-attribute.html10
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/link-with-title.html5
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/lots-of-iframes.html35
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/lots-of-images.html17
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/lots-of-text-vertical-lr.html3
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/lots-of-text.html3
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/many-iframes.html15
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/modal-alerts-in-new-about-blank-window.html13
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/mouse-button-listener.html30
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/mouse-move-listener.html16
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/no-autoplay-with-controls.html25
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/open-and-close-window.html11
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/push-state.html3
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/set-long-title.html10
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/should-open-external-schemes.html21
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/simple-accelerated-compositing.html5
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/simple-form.html11
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/simple-iframe.html6
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/simple-tall.html7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/simple.html5
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/simple2.html5
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/simple3.html5
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/spacebar-scrolling.html26
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/test-mse.mp4bin0 -> 80933 bytes
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/test-without-audio-track.mp4bin0 -> 189906 bytes
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/test.mp4bin0 -> 192844 bytes
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/webfont.html15
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/AllAhem.svg111
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ApplicationCache.dbbin0 -> 4096 bytes
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ApplicationCache.db-shmbin0 -> 32768 bytes
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ApplicationCache.db-walbin0 -> 168952 bytes
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/BundleEditingDelegateProtocol.h40
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/BundleRangeHandleProtocol.h35
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.h28
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.html6
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/CookieMessage.html4
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DownloadRequestBlobURL.html16
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DownloadRequestOriginalURL.html10
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DownloadRequestOriginalURL2.html6
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DownloadRequestOriginalURLFrame.html10
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/FullscreenDelegate.html31
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/FullscreenLayoutConstraints.html31
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/FullscreenTopContentInset.html31
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBDeleteRecovery.html14
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBDeleteRecovery.sqlite3bin0 -> 4096 bytes
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBDeleteRecovery.sqlite3-shmbin0 -> 32768 bytes
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBDeleteRecovery.sqlite3-walbin0 -> 164832 bytes
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBIndexUpgradeToV2.html21
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexUpgrade.blob1
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexUpgrade.sqlite3bin0 -> 65536 bytes
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBDatabaseProcessKill-1.html33
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBMultiProcess-1.html46
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBMultiProcess-2.html92
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBMultiProcess-3.html21
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence-1.html35
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence-2.html22
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LineBreaking.html45
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageClear.html6
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageNullEntries.html6
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageNullEntries.localstoragebin0 -> 12288 bytes
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageNullEntries.localstorage-shmbin0 -> 32768 bytes
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageQuirkEnabled.html10
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/RemoteObjectRegistry.h51
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/StoreBlobToBeDeleted.html41
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/UserContentWorldProtocol.h37
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WebProcessKillIDBCleanup-1.html67
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WebProcessKillIDBCleanup-2.html25
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/autofocused-text-input.html3
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/autoplaying-video-with-audio.html34
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/blinking-div.html23
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-click.html33
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-end.html35
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/duplicate-completion-handler-calls.html9
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/editable-body.html7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/enormous-video-with-sound.html15
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/focus-inputs.html15
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/full-size-autoplaying-video-with-audio.html23
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/input-field-in-scrollable-document.html36
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-input-field-focus-onload.html38
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-hides-controls-after-seek-to-end.html40
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-mutes-onplaying.html16
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-offscreen.html29
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-playing-scroll-away.html36
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-after-ending.html21
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-to-beginning-and-play-after-ending.html23
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-test-now-playing.html33
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-with-audio.html12
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-with-audio.mp4bin0 -> 1088986 bytes
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-without-audio.html29
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-click-to-pause.html47
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-scroll-to-video.html35
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-paused-video-hides-controls.html38
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-muted-video-hides-controls.html36
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-video-keeps-controls.html35
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-with-audio-autoplay.html18
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-with-audio.html18
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/open-multiple-external-url.html66
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/page-with-csp-iframe.html14
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/page-with-csp.html15
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/page-without-csp-iframe.html11
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/page-without-csp.html12
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/play-audio-on-click.html54
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/skinny-autoplaying-video-with-audio.html23
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/text-and-password-inputs.html39
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Cocoa/wide-autoplaying-video-with-audio.html23
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/AutocleanupsTest.cpp72
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/CMakeLists.txt135
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/DOMDOMWindowTest.cpp221
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/DOMNodeFilterTest.cpp204
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/DOMNodeTest.cpp122
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/DOMXPathNSResolverTest.cpp124
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/EditorTest.cpp131
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/FrameTest.cpp3
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestAuthentication.cpp36
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestAutocleanups.cpp70
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestBackForwardList.cpp137
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestConsoleMessage.cpp155
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestContextMenu.cpp370
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestCookieManager.cpp71
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDOMDOMWindow.cpp152
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDOMNode.cpp37
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDOMNodeFilter.cpp55
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDOMXPathNSResolver.cpp52
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDownloads.cpp351
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestEditor.cpp (renamed from Tools/TestWebKitAPI/Tests/WebKitGtk/testapplicationcache.c)35
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestFrame.cpp2
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestInspector.cpp17
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestInspectorServer.cpp12
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestLoaderClient.cpp211
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestMultiprocess.cpp77
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestPrinting.cpp207
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestResources.cpp108
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestSSL.cpp210
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestUIClient.cpp469
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebExtensions.cpp130
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitAccessibility.cpp5
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitFaviconDatabase.cpp69
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitFindController.cpp2
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitPolicyClient.cpp15
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitSecurityOrigin.cpp142
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitSettings.cpp23
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitUserContentManager.cpp360
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitWebContext.cpp412
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitWebView.cpp561
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitWebViewGroup.cpp206
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebViewEditor.cpp328
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebsiteData.cpp537
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebExtensionTest.cpp199
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebProcessTest.cpp33
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebProcessTest.h4
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/blank.icobin0 -> 198 bytes
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/boring.html1
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/link-title.js1
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/silence.mpgbin0 -> 33227 bytes
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/simple.json1
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/test-cert.pem13
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/test-key.pem16
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/track.oggbin0 -> 3869 bytes
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/webkit2gtk-tests.gresource.xml7
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2ObjC/CustomProtocolsInvalidScheme_Bundle.cpp66
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2ObjC/PreventImageLoadWithAutoResizing_Bundle.cpp69
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/test_utils.c51
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testatk.c1476
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testatkroles.c426
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testcontextmenu.c317
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testcopyandpaste.c266
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testdomdocument.c445
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testdomdomwindow.c258
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testdomnode.c219
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testdownload.c325
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testfavicondatabase.c279
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testglobals.c110
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testhittestresult.c171
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testhttpbackend.c75
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testkeyevents.c390
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testloading.c437
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testmimehandling.c206
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testnetworkrequest.c96
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testnetworkresponse.c97
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testwebbackforwardlist.c326
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testwebdatasource.c242
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testwebframe.c220
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testwebhistoryitem.c70
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testwebinspector.c173
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testwebplugindatabase.c78
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testwebresource.c334
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testwebsettings.c110
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testwebview.c749
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKitGtk/testwindow.c119
-rw-r--r--Tools/TestWebKitAPI/TestsController.cpp33
-rw-r--r--Tools/TestWebKitAPI/TestsController.h6
-rw-r--r--Tools/TestWebKitAPI/Utilities.h36
-rw-r--r--Tools/TestWebKitAPI/WKWebViewConfigurationExtras.h34
-rw-r--r--Tools/TestWebKitAPI/WTFStringUtilities.h13
-rw-r--r--Tools/TestWebKitAPI/config.h38
-rw-r--r--Tools/TestWebKitAPI/gtk/PlatformUtilitiesGtk.cpp6
-rw-r--r--Tools/TestWebKitAPI/gtk/PlatformWebViewGtk.cpp40
-rw-r--r--Tools/TestWebKitAPI/gtk/WebKit2Gtk/LoadTrackingTest.cpp83
-rw-r--r--Tools/TestWebKitAPI/gtk/WebKit2Gtk/LoadTrackingTest.h6
-rw-r--r--Tools/TestWebKitAPI/gtk/WebKit2Gtk/TestMain.cpp23
-rw-r--r--Tools/TestWebKitAPI/gtk/WebKit2Gtk/TestMain.h80
-rw-r--r--Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestBus.cpp59
-rw-r--r--Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestBus.h6
-rw-r--r--Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestServer.cpp26
-rw-r--r--Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestServer.h13
-rw-r--r--Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebViewTest.cpp100
-rw-r--r--Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebViewTest.h31
-rw-r--r--Tools/TestWebKitAPI/gtk/main.cpp2
-rw-r--r--Tools/TestWebKitAPI/jsconly/PlatformUtilitiesJSCOnly.cpp57
-rw-r--r--Tools/TestWebKitAPI/jsconly/main.cpp32
-rw-r--r--Tools/WebKitTestRunner/CMakeLists.txt121
-rw-r--r--Tools/WebKitTestRunner/DerivedSources.make62
-rw-r--r--Tools/WebKitTestRunner/EventSenderProxy.h27
-rw-r--r--Tools/WebKitTestRunner/FontWithFeatures.otfbin0 -> 14452 bytes
-rw-r--r--Tools/WebKitTestRunner/FontWithFeatures.ttfbin0 -> 12324 bytes
-rw-r--r--Tools/WebKitTestRunner/GNUmakefile.am175
-rw-r--r--Tools/WebKitTestRunner/GeolocationProviderMock.cpp4
-rw-r--r--Tools/WebKitTestRunner/GeolocationProviderMock.h4
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.cpp47
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.h31
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarker.cpp10
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarker.h17
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarkerRange.cpp10
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarkerRange.h17
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp195
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h129
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityController.idl45
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityTextMarker.idl29
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityTextMarkerRange.idl29
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl249
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm577
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/Bindings/EventSendingController.idl72
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/Bindings/GCController.idl (renamed from Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrappable.h)24
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl262
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/Bindings/TextInputController.idl32
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/EventSendingController.cpp332
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/EventSendingController.h25
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/GCController.cpp12
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/GCController.h9
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp373
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h58
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp4
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp557
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h7
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp853
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/TestRunner.h141
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/TextInputController.cpp14
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/TextInputController.h9
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityControllerAtk.cpp37
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.cpp72
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.h13
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp634
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/gtk/ActivateFontsGtk.cpp10
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/gtk/InjectedBundleUtilities.cpp6
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/gtk/InjectedBundleUtilities.h2
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/gtk/TestRunnerGtk.cpp25
-rw-r--r--Tools/WebKitTestRunner/Options.cpp43
-rw-r--r--Tools/WebKitTestRunner/Options.h9
-rw-r--r--Tools/WebKitTestRunner/PixelDumpSupport.cpp2
-rw-r--r--Tools/WebKitTestRunner/PixelDumpSupport.h2
-rw-r--r--Tools/WebKitTestRunner/PlatformGTK.cmake60
-rw-r--r--Tools/WebKitTestRunner/PlatformWebView.h74
-rw-r--r--Tools/WebKitTestRunner/StringFunctions.h10
-rw-r--r--Tools/WebKitTestRunner/TestController.cpp1648
-rw-r--r--Tools/WebKitTestRunner/TestController.h264
-rw-r--r--Tools/WebKitTestRunner/TestInvocation.cpp772
-rw-r--r--Tools/WebKitTestRunner/TestInvocation.h74
-rw-r--r--Tools/WebKitTestRunner/TestOptions.cpp76
-rw-r--r--Tools/WebKitTestRunner/TestOptions.h58
-rw-r--r--Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h7
-rw-r--r--Tools/WebKitTestRunner/WebNotificationProvider.cpp116
-rw-r--r--Tools/WebKitTestRunner/WebNotificationProvider.h16
-rw-r--r--Tools/WebKitTestRunner/WorkQueueManager.cpp22
-rw-r--r--Tools/WebKitTestRunner/WorkQueueManager.h5
-rw-r--r--Tools/WebKitTestRunner/cairo/TestInvocationCairo.cpp11
-rw-r--r--Tools/WebKitTestRunner/config.h (renamed from Tools/DumpRenderTree/gtk/EditingCallbacks.h)33
-rw-r--r--Tools/WebKitTestRunner/gtk/EventSenderProxyGtk.cpp43
-rw-r--r--Tools/WebKitTestRunner/gtk/PlatformWebViewGtk.cpp95
-rw-r--r--Tools/WebKitTestRunner/gtk/TestControllerGtk.cpp83
-rw-r--r--Tools/WebKitTestRunner/gtk/fonts/AHEM____.TTFbin0 -> 12480 bytes
-rw-r--r--Tools/WebKitTestRunner/gtk/fonts/FontWithNoValidEncoding.fonbin0 -> 8368 bytes
-rw-r--r--Tools/WebKitTestRunner/gtk/fonts/fonts.conf435
-rw-r--r--Tools/WebKitTestRunner/gtk/main.cpp9
-rw-r--r--Tools/gtk/GNUmakefile.am153
-rwxr-xr-xTools/gtk/check-for-webkitdom-api-breaks78
-rw-r--r--Tools/gtk/common.py52
-rwxr-xr-xTools/gtk/generate-feature-defines-files58
-rwxr-xr-xTools/gtk/generate-gtkdoc64
-rwxr-xr-xTools/gtk/generate-inspector-gresource-manifest.py14
-rw-r--r--Tools/gtk/gtkdoc.py28
-rwxr-xr-xTools/gtk/install-dependencies479
-rw-r--r--Tools/gtk/jhbuild.modules628
-rw-r--r--Tools/gtk/jhbuildrc44
-rwxr-xr-xTools/gtk/make-dist.py333
-rw-r--r--Tools/gtk/manifest.txt.in106
-rw-r--r--Tools/gtk/patches/fontconfig-C-11-requires-a-space-between-literal-and-identifier.patch30
-rw-r--r--Tools/gtk/patches/fontconfig-fix-osx-cache.diff207
-rw-r--r--Tools/gtk/patches/freetype6-2.4.11-truetype-font-height-fix.patch39
-rw-r--r--Tools/gtk/patches/gdate-suppress-string-format-literal-warning.patch29
-rw-r--r--Tools/gtk/patches/glib-warning-fix.patch34
-rw-r--r--Tools/gtk/patches/gst-plugins-bad-0001-dtls-port-to-OpenSSL-1.1.0.patch236
-rw-r--r--Tools/gtk/patches/gst-plugins-bad-0002-dtlscertificate-Fix-error-checking-in-RSA_generate_k.patch37
-rw-r--r--Tools/gtk/patches/gst-plugins-good-0001-rtpbin-pipeline-gets-an-EOS-when-any-rtpsources-byes.patch156
-rw-r--r--Tools/gtk/patches/gst-plugins-good-0002-rtpbin-avoid-generating-errors-when-rtcp-messages-ar.patch61
-rw-r--r--Tools/gtk/patches/gst-plugins-good-0003-rtpbin-receive-bundle-support.patch1018
-rw-r--r--Tools/gtk/patches/gst-plugins-good-0004-qtdemux-add-context-for-a-preferred-protection.patch320
-rw-r--r--Tools/gtk/patches/gst-plugins-good-Revert-qtdemux-expose-streams-with-first-moof-for-fr.patch133
-rw-r--r--Tools/gtk/patches/gst-plugins-good-use-the-tfdt-decode-time.patch89
-rw-r--r--Tools/gtk/patches/gstreamer-0001-protection-added-function-to-filter-system-ids.patch77
-rw-r--r--Tools/gtk/patches/gtk+-configure-fix-detecting-CUPS-2.x.patch11
-rw-r--r--Tools/gtk/patches/icudata-stdlibs.patch15
-rw-r--r--Tools/gtk/patches/libnice-0001-TURN-allow-REALM-to-be-empty.patch50
-rw-r--r--Tools/gtk/patches/libnice-0001-nicesrc-spin-the-agent-mainloop-in-a-separate-thread.patch253
-rw-r--r--Tools/gtk/patches/librsvg-2.36.1-bump-up-config.guess-to-support-aarch64.patch1581
-rw-r--r--Tools/gtk/patches/libsoup-auth-Fix-async-authentication-when-flag-SOUP_MESSAGE.patch130
-rw-r--r--Tools/gtk/patches/libsoup-auth-do-not-use-cached-credentials-in-lookup-method-.patch114
-rw-r--r--Tools/gtk/patches/mesa-gallivm-Fix-build-after-LLVM-commit-211259.patch29
-rw-r--r--Tools/gtk/patches/openh264-configure.patch12
-rw-r--r--Tools/gtk/patches/rtspsrc-timeout-on-udpsrc-is-in-nanoseconds.patch27
-rw-r--r--Tools/gtk/patches/shared-mime-info-xht-glob.patch21
-rw-r--r--Tools/gtk/patches/shared-mime-info-xhtml-magic.patch26
-rw-r--r--Tools/gtk/patches/udpsrc-improve-timeouts.patch53
-rw-r--r--Tools/gtk/patches/xserver-remove-bogus-dependencies.patch43
-rw-r--r--Tools/gtk/patches/xserver-search-for-DRI-drivers-at-LIBGL_DRIVERS_PATH-environ.patch84
-rwxr-xr-xTools/gtk/webkitdom.py285
-rw-r--r--Tools/gtk/ycm_extra_conf.py132
-rw-r--r--Tools/jhbuild/jhbuildutils.py56
667 files changed, 61301 insertions, 22753 deletions
diff --git a/Tools/CMakeLists.txt b/Tools/CMakeLists.txt
new file mode 100644
index 000000000..4b2edb8de
--- /dev/null
+++ b/Tools/CMakeLists.txt
@@ -0,0 +1,48 @@
+set_property(DIRECTORY . PROPERTY FOLDER "Tools")
+
+if ("${PORT}" STREQUAL "Efl")
+ if (DEVELOPER_MODE)
+ add_subdirectory(WebKitTestRunner)
+ add_subdirectory(ImageDiff)
+ if (ENABLE_X11_TARGET)
+ add_subdirectory(DumpRenderTree/TestNetscapePlugIn)
+ endif ()
+ endif ()
+
+ if (ENABLE_MINIBROWSER)
+ add_subdirectory(MiniBrowser/efl)
+ endif ()
+elseif ("${PORT}" STREQUAL "GTK")
+ if (DEVELOPER_MODE)
+ add_subdirectory(WebKitTestRunner)
+ add_subdirectory(ImageDiff)
+ if (ENABLE_API_TESTS)
+ add_subdirectory(TestWebKitAPI/Tests/WebKit2Gtk)
+ endif ()
+ if (ENABLE_X11_TARGET)
+ add_subdirectory(DumpRenderTree/TestNetscapePlugIn)
+ endif ()
+ endif ()
+
+ if (ENABLE_MINIBROWSER)
+ add_subdirectory(MiniBrowser/gtk)
+ endif ()
+elseif ("${PORT}" STREQUAL "Mac")
+ add_subdirectory(DumpRenderTree)
+ add_subdirectory(WebKitTestRunner)
+ add_subdirectory(MiniBrowser/mac)
+elseif ("${PORT}" STREQUAL "JSCOnly")
+ if (ENABLE_API_TESTS)
+ add_subdirectory(TestWebKitAPI)
+ endif ()
+endif ()
+
+if (WIN32)
+ add_subdirectory(DumpRenderTree)
+ add_subdirectory(TestWebKitAPI)
+ add_subdirectory(MiniBrowser/win)
+endif ()
+
+if (ENABLE_WEBKIT2 AND ENABLE_API_TESTS)
+ add_subdirectory(TestWebKitAPI)
+endif ()
diff --git a/Tools/DumpRenderTree/AccessibilityController.cpp b/Tools/DumpRenderTree/AccessibilityController.cpp
index dd9996be8..d035dea99 100644
--- a/Tools/DumpRenderTree/AccessibilityController.cpp
+++ b/Tools/DumpRenderTree/AccessibilityController.cpp
@@ -130,6 +130,20 @@ static JSValueRef removeNotificationListenerCallback(JSContextRef context, JSObj
return JSValueMakeUndefined(context);
}
+static JSValueRef enableEnhancedAccessibilityCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject));
+ if (argumentCount == 1)
+ controller->enableEnhancedAccessibility(JSValueToBoolean(context, arguments[0]));
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef getEnhancedAccessibilityEnabledCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject));
+ return JSValueMakeBoolean(context, controller->enhancedAccessibilityEnabled());
+}
+
static JSValueRef getPlatformNameCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
{
AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject));
@@ -150,12 +164,14 @@ JSClassRef AccessibilityController::getJSClass()
{ "accessibleElementById", getAccessibleElementByIdCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "addNotificationListener", addNotificationListenerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "removeNotificationListener", removeNotificationListenerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "enableEnhancedAccessibility", enableEnhancedAccessibilityCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ 0, 0, 0 }
};
static JSStaticValue staticValues[] = {
{ "focusedElement", getFocusedElementCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "rootElement", getRootElementCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "enhancedAccessibilityEnabled", getEnhancedAccessibilityEnabledCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "platformName", getPlatformNameCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ 0, 0, 0, 0 }
};
diff --git a/Tools/DumpRenderTree/AccessibilityController.h b/Tools/DumpRenderTree/AccessibilityController.h
index 2f4f6ae9e..9f66dd6ee 100644
--- a/Tools/DumpRenderTree/AccessibilityController.h
+++ b/Tools/DumpRenderTree/AccessibilityController.h
@@ -64,6 +64,10 @@ public:
bool addNotificationListener(JSObjectRef functionCallback);
void removeNotificationListener();
+ // Enhanced accessibility.
+ void enableEnhancedAccessibility(bool);
+ bool enhancedAccessibilityEnabled();
+
JSRetainPtr<JSStringRef> platformName() const;
#if PLATFORM(WIN)
@@ -89,7 +93,7 @@ private:
HashMap<PlatformUIElement, JSObjectRef> m_notificationListeners;
#endif
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA) || PLATFORM(IOS)
RetainPtr<NotificationHandler> m_globalNotificationHandler;
#endif
diff --git a/Tools/DumpRenderTree/AccessibilityTextMarker.h b/Tools/DumpRenderTree/AccessibilityTextMarker.h
index b890e28a9..7809ea459 100644
--- a/Tools/DumpRenderTree/AccessibilityTextMarker.h
+++ b/Tools/DumpRenderTree/AccessibilityTextMarker.h
@@ -28,13 +28,13 @@
#include <JavaScriptCore/JSObjectRef.h>
-#if PLATFORM(MAC) && !PLATFORM(IOS)
+#if PLATFORM(MAC) || PLATFORM(IOS)
#define SUPPORTS_AX_TEXTMARKERS 1
#else
#define SUPPORTS_AX_TEXTMARKERS 0
#endif
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
#include <wtf/RetainPtr.h>
typedef CFTypeRef PlatformTextMarker;
typedef CFTypeRef PlatformTextMarkerRange;
@@ -58,7 +58,7 @@ public:
private:
static JSClassRef getJSClass();
-#if SUPPORTS_AX_TEXTMARKERS
+#if SUPPORTS_AX_TEXTMARKERS && PLATFORM(MAC)
RetainPtr<PlatformTextMarker> m_textMarker;
#else
PlatformTextMarker m_textMarker;
@@ -78,7 +78,7 @@ public:
private:
static JSClassRef getJSClass();
-#if SUPPORTS_AX_TEXTMARKERS
+#if SUPPORTS_AX_TEXTMARKERS && PLATFORM(MAC)
RetainPtr<PlatformTextMarkerRange> m_textMarkerRange;
#else
PlatformTextMarkerRange m_textMarkerRange;
diff --git a/Tools/DumpRenderTree/AccessibilityUIElement.cpp b/Tools/DumpRenderTree/AccessibilityUIElement.cpp
index 793b3103d..1d77d7717 100644
--- a/Tools/DumpRenderTree/AccessibilityUIElement.cpp
+++ b/Tools/DumpRenderTree/AccessibilityUIElement.cpp
@@ -209,7 +209,8 @@ static JSValueRef uiElementCountForSearchPredicateCallback(JSContextRef context,
JSValueRef searchKey = nullptr;
JSRetainPtr<JSStringRef> searchText = nullptr;
bool visibleOnly = false;
- if (argumentCount == 5) {
+ bool immediateDescendantsOnly = false;
+ if (argumentCount >= 5 && argumentCount <= 6) {
if (JSValueIsObject(context, arguments[0]))
startElement = toAXElement(JSValueToObject(context, arguments[0], exception));
@@ -221,9 +222,12 @@ static JSValueRef uiElementCountForSearchPredicateCallback(JSContextRef context,
searchText.adopt(JSValueToStringCopy(context, arguments[3], exception));
visibleOnly = JSValueToBoolean(context, arguments[4]);
+
+ if (argumentCount == 6)
+ immediateDescendantsOnly = JSValueToBoolean(context, arguments[5]);
}
- return JSValueMakeNumber(context, toAXElement(thisObject)->uiElementCountForSearchPredicate(context, startElement, isDirectionNext, searchKey, searchText.get(), visibleOnly));
+ return JSValueMakeNumber(context, toAXElement(thisObject)->uiElementCountForSearchPredicate(context, startElement, isDirectionNext, searchKey, searchText.get(), visibleOnly, immediateDescendantsOnly));
}
static JSValueRef uiElementForSearchPredicateCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
@@ -233,7 +237,8 @@ static JSValueRef uiElementForSearchPredicateCallback(JSContextRef context, JSOb
JSValueRef searchKey = nullptr;
JSRetainPtr<JSStringRef> searchText = nullptr;
bool visibleOnly = false;
- if (argumentCount == 5) {
+ bool immediateDescendantsOnly = false;
+ if (argumentCount >= 5 && argumentCount <= 6) {
if (JSValueIsObject(context, arguments[0]))
startElement = toAXElement(JSValueToObject(context, arguments[0], exception));
@@ -245,9 +250,34 @@ static JSValueRef uiElementForSearchPredicateCallback(JSContextRef context, JSOb
searchText.adopt(JSValueToStringCopy(context, arguments[3], exception));
visibleOnly = JSValueToBoolean(context, arguments[4]);
+
+ if (argumentCount == 6)
+ immediateDescendantsOnly = JSValueToBoolean(context, arguments[5]);
}
- return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->uiElementForSearchPredicate(context, startElement, isDirectionNext, searchKey, searchText.get(), visibleOnly));
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->uiElementForSearchPredicate(context, startElement, isDirectionNext, searchKey, searchText.get(), visibleOnly, immediateDescendantsOnly));
+}
+
+static JSValueRef selectTextWithCriteriaCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 2 || argumentCount > 4)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> ambiguityResolution(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ JSValueRef searchStrings = arguments[1];
+ JSStringRef replacementString = nullptr;
+ if (argumentCount == 3)
+ replacementString = JSValueToStringCopy(context, arguments[2], exception);
+ JSStringRef activityString = nullptr;
+ if (argumentCount == 4)
+ activityString = JSValueToStringCopy(context, arguments[3], exception);
+
+ JSRetainPtr<JSStringRef> result(Adopt, toAXElement(thisObject)->selectTextWithCriteria(context, ambiguityResolution.get(), searchStrings, replacementString, activityString));
+ if (replacementString)
+ JSStringRelease(replacementString);
+ if (activityString)
+ JSStringRelease(activityString);
+ return JSValueMakeString(context, result.get());
}
static JSValueRef indexOfChildCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
@@ -287,12 +317,13 @@ static JSValueRef elementsForRangeCallback(JSContextRef context, JSObjectRef fun
Vector<AccessibilityUIElement> elements;
toAXElement(thisObject)->elementsForRange(location, length, elements);
+ JSValueRef arrayResult = JSObjectMakeArray(context, 0, 0, 0);
+ JSObjectRef arrayObj = JSValueToObject(context, arrayResult, 0);
unsigned elementsSize = elements.size();
- JSValueRef valueElements[elementsSize];
for (unsigned k = 0; k < elementsSize; ++k)
- valueElements[k] = AccessibilityUIElement::makeJSAccessibilityUIElement(context, elements[k]);
+ JSObjectSetPropertyAtIndex(context, arrayObj, k, AccessibilityUIElement::makeJSAccessibilityUIElement(context, elements[k]), 0);
- return JSObjectMakeArray(context, elementsSize, valueElements, 0);
+ return arrayResult;
}
static JSValueRef increaseTextSelectionCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
@@ -301,6 +332,26 @@ static JSValueRef increaseTextSelectionCallback(JSContextRef context, JSObjectRe
return JSValueMakeUndefined(context);
}
+static JSValueRef scrollPageUpCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->scrollPageUp());
+}
+
+static JSValueRef scrollPageDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->scrollPageDown());
+}
+
+static JSValueRef scrollPageLeftCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->scrollPageLeft());
+}
+
+static JSValueRef scrollPageRightCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->scrollPageRight());
+}
+
static JSValueRef decreaseTextSelectionCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
toAXElement(thisObject)->decreaseTextSelection();
@@ -313,6 +364,11 @@ static JSValueRef assistiveTechnologySimulatedFocusCallback(JSContextRef context
return JSValueMakeUndefined(context);
}
+static JSValueRef fieldsetAncestorElementCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->fieldsetAncestorElement());
+}
+
#endif
static JSValueRef childAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
@@ -369,6 +425,15 @@ static JSValueRef ariaFlowToElementAtIndexCallback(JSContextRef context, JSObjec
return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->ariaFlowToElementAtIndex(indexNumber));
}
+static JSValueRef ariaControlsElementAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int indexNumber = 0;
+ if (argumentCount == 1)
+ indexNumber = JSValueToNumber(context, arguments[0], exception);
+
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->ariaControlsElementAtIndex(indexNumber));
+}
+
static JSValueRef selectedRowAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
int indexNumber = 0;
@@ -398,6 +463,19 @@ static JSValueRef isEqualCallback(JSContextRef context, JSObjectRef function, JS
return JSValueMakeBoolean(context, toAXElement(thisObject)->isEqual(toAXElement(otherElement)));
}
+static JSValueRef setValueCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> valueText = 0;
+ if (argumentCount == 1) {
+ if (JSValueIsString(context, arguments[0]))
+ valueText.adopt(JSValueToStringCopy(context, arguments[0], exception));
+ }
+
+ toAXElement(thisObject)->setValue(valueText.get());
+
+ return JSValueMakeUndefined(context);
+}
+
static JSValueRef setSelectedChildCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
JSObjectRef element = 0;
@@ -409,6 +487,24 @@ static JSValueRef setSelectedChildCallback(JSContextRef context, JSObjectRef fun
return JSValueMakeUndefined(context);
}
+static JSValueRef setSelectedChildAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount == 1) {
+ unsigned indexNumber = JSValueToNumber(context, arguments[0], exception);
+ toAXElement(thisObject)->setSelectedChildAtIndex(indexNumber);
+ }
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef removeSelectionAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount == 1) {
+ unsigned indexNumber = JSValueToNumber(context, arguments[0], exception);
+ toAXElement(thisObject)->removeSelectionAtIndex(indexNumber);
+ }
+ return JSValueMakeUndefined(context);
+}
+
static JSValueRef elementAtPointCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
int x = 0;
@@ -470,6 +566,20 @@ static JSValueRef boolAttributeValueCallback(JSContextRef context, JSObjectRef f
return result;
}
+static JSValueRef setBoolAttributeValueCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSStringRef attribute = nullptr;
+ bool value = false;
+ if (argumentCount == 2) {
+ attribute = JSValueToStringCopy(context, arguments[0], exception);
+ value = JSValueToBoolean(context, arguments[1]);
+ }
+ toAXElement(thisObject)->setBoolAttributeValue(attribute, value);
+ if (attribute)
+ JSStringRelease(attribute);
+ return JSValueMakeUndefined(context);
+}
+
static JSValueRef stringAttributeValueCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
JSStringRef attribute = 0;
@@ -484,12 +594,14 @@ static JSValueRef stringAttributeValueCallback(JSContextRef context, JSObjectRef
static JSValueRef convertElementsToObjectArray(JSContextRef context, Vector<AccessibilityUIElement>& elements, JSValueRef* exception)
{
+ JSValueRef arrayResult = JSObjectMakeArray(context, 0, 0, 0);
+ JSObjectRef arrayObj = JSValueToObject(context, arrayResult, 0);
+
size_t elementCount = elements.size();
- auto valueElements = std::make_unique<JSValueRef[]>(elementCount);
for (size_t i = 0; i < elementCount; ++i)
- valueElements[i] = AccessibilityUIElement::makeJSAccessibilityUIElement(context, elements[i]);
-
- return JSObjectMakeArray(context, elementCount, valueElements.get(), exception);
+ JSObjectSetPropertyAtIndex(context, arrayObj, i, AccessibilityUIElement::makeJSAccessibilityUIElement(context, elements[i]), 0);
+
+ return arrayResult;
}
static JSValueRef columnHeadersCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
@@ -601,6 +713,36 @@ static JSValueRef pressCallback(JSContextRef context, JSObjectRef function, JSOb
return JSValueMakeUndefined(context);
}
+static JSValueRef scrollToMakeVisibleWithSubFocusCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ unsigned x = 0;
+ unsigned y = 0;
+ unsigned width = 0;
+ unsigned height = 0;
+ if (argumentCount == 4) {
+ x = JSValueToNumber(context, arguments[0], exception);
+ y = JSValueToNumber(context, arguments[1], exception);
+ width = JSValueToNumber(context, arguments[2], exception);
+ height = JSValueToNumber(context, arguments[3], exception);
+ }
+
+ toAXElement(thisObject)->scrollToMakeVisibleWithSubFocus(x, y, width, height);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef scrollToGlobalPointCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ unsigned x = 0;
+ unsigned y = 0;
+ if (argumentCount == 2) {
+ x = JSValueToNumber(context, arguments[0], exception);
+ y = JSValueToNumber(context, arguments[1], exception);
+ }
+
+ toAXElement(thisObject)->scrollToGlobalPoint(x, y);
+ return JSValueMakeUndefined(context);
+}
+
static JSValueRef scrollToMakeVisibleCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
toAXElement(thisObject)->scrollToMakeVisible();
@@ -631,6 +773,14 @@ static JSValueRef removeSelectionCallback(JSContextRef context, JSObjectRef func
return JSValueMakeUndefined(context);
}
+static JSValueRef lineTextMarkerRangeForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityTextMarker* textMarker = nullptr;
+ if (argumentCount == 1)
+ textMarker = toTextMarker(JSValueToObject(context, arguments[0], exception));
+ return AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange(context, toAXElement(thisObject)->lineTextMarkerRangeForTextMarker(textMarker));
+}
+
static JSValueRef textMarkerRangeForElementCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
AccessibilityUIElement* uiElement = 0;
@@ -640,6 +790,17 @@ static JSValueRef textMarkerRangeForElementCallback(JSContextRef context, JSObje
return AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange(context, toAXElement(thisObject)->textMarkerRangeForElement(uiElement));
}
+static JSValueRef selectedTextMarkerRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ return AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange(context, toAXElement(thisObject)->selectedTextMarkerRange());
+}
+
+static JSValueRef resetSelectedTextMarkerRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ toAXElement(thisObject)->resetSelectedTextMarkerRange();
+ return JSValueMakeUndefined(context);
+}
+
static JSValueRef attributedStringForTextMarkerRangeContainsAttributeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
AccessibilityTextMarkerRange* markerRange = 0;
@@ -813,6 +974,109 @@ static JSValueRef endTextMarkerCallback(JSContextRef context, JSObjectRef thisOb
return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->endTextMarker());
}
+static JSValueRef leftWordTextMarkerRangeForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityTextMarker* marker = nullptr;
+ if (argumentCount == 1)
+ marker = toTextMarker(JSValueToObject(context, arguments[0], exception));
+
+ return AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange(context, toAXElement(thisObject)->leftWordTextMarkerRangeForTextMarker(marker));
+}
+
+static JSValueRef rightWordTextMarkerRangeForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityTextMarker* marker = nullptr;
+ if (argumentCount == 1)
+ marker = toTextMarker(JSValueToObject(context, arguments[0], exception));
+
+ return AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange(context, toAXElement(thisObject)->rightWordTextMarkerRangeForTextMarker(marker));
+}
+
+static JSValueRef previousWordStartTextMarkerForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityTextMarker* marker = nullptr;
+ if (argumentCount == 1)
+ marker = toTextMarker(JSValueToObject(context, arguments[0], exception));
+
+ return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->previousWordStartTextMarkerForTextMarker(marker));
+}
+
+static JSValueRef nextWordEndTextMarkerForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityTextMarker* marker = nullptr;
+ if (argumentCount == 1)
+ marker = toTextMarker(JSValueToObject(context, arguments[0], exception));
+
+ return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->nextWordEndTextMarkerForTextMarker(marker));
+}
+
+static JSValueRef paragraphTextMarkerRangeForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityTextMarker* marker = nullptr;
+ if (argumentCount == 1)
+ marker = toTextMarker(JSValueToObject(context, arguments[0], exception));
+
+ return AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange(context, toAXElement(thisObject)->paragraphTextMarkerRangeForTextMarker(marker));
+}
+
+static JSValueRef previousParagraphStartTextMarkerForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityTextMarker* marker = nullptr;
+ if (argumentCount == 1)
+ marker = toTextMarker(JSValueToObject(context, arguments[0], exception));
+
+ return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->previousParagraphStartTextMarkerForTextMarker(marker));
+}
+
+static JSValueRef nextParagraphEndTextMarkerForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityTextMarker* marker = nullptr;
+ if (argumentCount == 1)
+ marker = toTextMarker(JSValueToObject(context, arguments[0], exception));
+
+ return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->nextParagraphEndTextMarkerForTextMarker(marker));
+}
+
+static JSValueRef sentenceTextMarkerRangeForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityTextMarker* marker = nullptr;
+ if (argumentCount == 1)
+ marker = toTextMarker(JSValueToObject(context, arguments[0], exception));
+
+ return AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange(context, toAXElement(thisObject)->sentenceTextMarkerRangeForTextMarker(marker));
+}
+
+static JSValueRef previousSentenceStartTextMarkerForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityTextMarker* marker = nullptr;
+ if (argumentCount == 1)
+ marker = toTextMarker(JSValueToObject(context, arguments[0], exception));
+
+ return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->previousSentenceStartTextMarkerForTextMarker(marker));
+}
+
+static JSValueRef nextSentenceEndTextMarkerForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityTextMarker* marker = nullptr;
+ if (argumentCount == 1)
+ marker = toTextMarker(JSValueToObject(context, arguments[0], exception));
+
+ return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->nextSentenceEndTextMarkerForTextMarker(marker));
+}
+
+static JSValueRef setSelectedVisibleTextRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityUIElement* uiElement = toAXElement(thisObject);
+ AccessibilityTextMarkerRange* textMarkerRange = nullptr;
+ if (argumentCount == 1)
+ textMarkerRange = toTextMarkerRange(JSValueToObject(context, arguments[0], exception));
+
+ if (uiElement)
+ return JSValueMakeBoolean(context, uiElement->setSelectedVisibleTextRange(textMarkerRange));
+
+ return JSValueMakeBoolean(context, false);
+}
+
// Static Value Getters
static JSValueRef getARIADropEffectsCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
@@ -861,6 +1125,12 @@ static JSValueRef getRoleDescriptionCallback(JSContextRef context, JSObjectRef t
return JSValueMakeString(context, roleDesc.get());
}
+static JSValueRef getComputedRoleStringCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> compRole(Adopt, toAXElement(thisObject)->computedRoleString());
+ return JSValueMakeString(context, compRole.get());
+}
+
static JSValueRef getTitleCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
{
JSRetainPtr<JSStringRef> title(Adopt, toAXElement(thisObject)->title());
@@ -1169,56 +1439,48 @@ static JSValueRef sentenceAtOffsetCallback(JSContextRef context, JSObjectRef fun
#elif PLATFORM(IOS)
-static JSValueRef stringForSelectionCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+static JSValueRef getIsSearchFieldCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
{
- JSRetainPtr<JSStringRef> labelString(Adopt, toAXElement(thisObject)->stringForSelection());
- return JSValueMakeString(context, labelString.get());
-}
-
-static JSValueRef getIPhoneLabelCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
-{
- JSRetainPtr<JSStringRef> labelString(Adopt, toAXElement(thisObject)->iphoneLabel());
- return JSValueMakeString(context, labelString.get());
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->isSearchField());
}
-static JSValueRef getIPhoneHintCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+static JSValueRef getIsTextAreaCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
{
- JSRetainPtr<JSStringRef> hintString(Adopt, toAXElement(thisObject)->iphoneHint());
- return JSValueMakeString(context, hintString.get());
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->isTextArea());
}
-static JSValueRef getIPhoneValueCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+static JSValueRef stringForSelectionCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
{
- JSRetainPtr<JSStringRef> valueString(Adopt, toAXElement(thisObject)->iphoneValue());
- return JSValueMakeString(context, valueString.get());
+ JSRetainPtr<JSStringRef> labelString(Adopt, toAXElement(thisObject)->stringForSelection());
+ return JSValueMakeString(context, labelString.get());
}
-static JSValueRef getIPhoneIdentifierCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+static JSValueRef getIdentifierCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
{
- JSRetainPtr<JSStringRef> valueString(Adopt, toAXElement(thisObject)->iphoneIdentifier());
+ JSRetainPtr<JSStringRef> valueString(Adopt, toAXElement(thisObject)->identifier());
return JSValueMakeString(context, valueString.get());
}
-static JSValueRef getIPhoneTraitsCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+static JSValueRef getTraitsCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
{
- JSRetainPtr<JSStringRef> valueString(Adopt, toAXElement(thisObject)->iphoneTraits());
+ JSRetainPtr<JSStringRef> valueString(Adopt, toAXElement(thisObject)->traits());
return JSValueMakeString(context, valueString.get());
}
-static JSValueRef getIPhoneIsElementCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+static JSValueRef getElementTextPositionCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
{
- return JSValueMakeBoolean(context, toAXElement(thisObject)->iphoneIsElement());
+ return JSValueMakeNumber(context, toAXElement(thisObject)->elementTextPosition());
}
-static JSValueRef getIPhoneElementTextPositionCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+static JSValueRef getElementTextLengthCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
{
- return JSValueMakeNumber(context, toAXElement(thisObject)->iphoneElementTextPosition());
+ return JSValueMakeNumber(context, toAXElement(thisObject)->elementTextLength());
}
-static JSValueRef getIPhoneElementTextLengthCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+static JSValueRef hasContainedByFieldsetTraitCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*)
{
- return JSValueMakeNumber(context, toAXElement(thisObject)->iphoneElementTextLength());
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->hasContainedByFieldsetTrait());
}
#endif // PLATFORM(IOS)
@@ -1252,8 +1514,8 @@ JSStringRef AccessibilityUIElement::speak() { return 0; }
JSStringRef AccessibilityUIElement::rangeForLine(int line) { return 0; }
JSStringRef AccessibilityUIElement::rangeForPosition(int, int) { return 0; }
void AccessibilityUIElement::setSelectedChild(AccessibilityUIElement*) const { }
-unsigned AccessibilityUIElement::selectedChildrenCount() const { return 0; }
-AccessibilityUIElement AccessibilityUIElement::selectedChildAtIndex(unsigned) const { return 0; }
+void AccessibilityUIElement::setSelectedChildAtIndex(unsigned) const { }
+void AccessibilityUIElement::removeSelectionAtIndex(unsigned) const { }
AccessibilityUIElement AccessibilityUIElement::horizontalScrollbar() const { return 0; }
AccessibilityUIElement AccessibilityUIElement::verticalScrollbar() const { return 0; }
AccessibilityUIElement AccessibilityUIElement::uiElementAttributeValue(JSStringRef) const { return 0; }
@@ -1261,12 +1523,11 @@ AccessibilityUIElement AccessibilityUIElement::uiElementAttributeValue(JSStringR
#if !PLATFORM(MAC) && !PLATFORM(IOS)
JSStringRef AccessibilityUIElement::pathDescription() const { return 0; }
+void AccessibilityUIElement::setValue(JSStringRef) { }
#endif
-#if !PLATFORM(MAC)
+#if !PLATFORM(COCOA)
void AccessibilityUIElement::uiElementArrayAttributeValue(JSStringRef, Vector<AccessibilityUIElement>&) const { }
-void AccessibilityUIElement::columnHeaders(Vector<AccessibilityUIElement>&) const { }
-void AccessibilityUIElement::rowHeaders(Vector<AccessibilityUIElement>&) const { }
#endif
#if !PLATFORM(WIN)
@@ -1278,13 +1539,31 @@ bool AccessibilityUIElement::isEqual(AccessibilityUIElement* otherElement)
}
#endif
+#if !PLATFORM(MAC)
+void AccessibilityUIElement::setBoolAttributeValue(JSStringRef, bool) { }
+#endif
+
#if !SUPPORTS_AX_TEXTMARKERS
+AccessibilityTextMarkerRange AccessibilityUIElement::lineTextMarkerRangeForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
AccessibilityTextMarkerRange AccessibilityUIElement::textMarkerRangeForElement(AccessibilityUIElement*)
{
return 0;
}
+AccessibilityTextMarkerRange AccessibilityUIElement::selectedTextMarkerRange()
+{
+ return nullptr;
+}
+
+void AccessibilityUIElement::resetSelectedTextMarkerRange()
+{
+}
+
int AccessibilityUIElement::textMarkerRangeLength(AccessibilityTextMarkerRange*)
{
return 0;
@@ -1370,6 +1649,61 @@ AccessibilityTextMarker AccessibilityUIElement::endTextMarker()
return nullptr;
}
+bool AccessibilityUIElement::setSelectedVisibleTextRange(AccessibilityTextMarkerRange*)
+{
+ return false;
+}
+
+AccessibilityTextMarkerRange AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
+AccessibilityTextMarkerRange AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
+AccessibilityTextMarkerRange AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
+AccessibilityTextMarkerRange AccessibilityUIElement::sentenceTextMarkerRangeForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::previousSentenceStartTextMarkerForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::nextSentenceEndTextMarkerForTextMarker(AccessibilityTextMarker*)
+{
+ return nullptr;
+}
+
#endif
// Destruction
@@ -1396,6 +1730,7 @@ JSClassRef AccessibilityUIElement::getJSClass()
{ "role", getRoleCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "subrole", getSubroleCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "roleDescription", getRoleDescriptionCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "computedRoleString", getComputedRoleStringCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "title", getTitleCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "description", getDescriptionCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "language", getLanguageCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
@@ -1449,15 +1784,14 @@ JSClassRef AccessibilityUIElement::getJSClass()
{ "startTextMarker", startTextMarkerCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "endTextMarker", endTextMarkerCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
#if PLATFORM(IOS)
- { "iphoneLabel", getIPhoneLabelCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "iphoneHint", getIPhoneHintCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "iphoneValue", getIPhoneValueCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "iphoneIdentifier", getIPhoneIdentifierCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "iphoneTraits", getIPhoneTraitsCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "iphoneIsElement", getIPhoneIsElementCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "iphoneElementTextPosition", getIPhoneElementTextPositionCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "iphoneElementTextLength", getIPhoneElementTextLengthCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "identifier", getIdentifierCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "traits", getTraitsCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "elementTextPosition", getElementTextPositionCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "elementTextLength", getElementTextLengthCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "stringForSelection", stringForSelectionCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "hasContainedByFieldsetTrait", hasContainedByFieldsetTraitCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isSearchField", getIsSearchFieldCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isTextArea", getIsTextAreaCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
#endif // PLATFORM(IOS)
#if PLATFORM(MAC) && !PLATFORM(IOS)
{ "supportedActions", supportedActionsCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
@@ -1480,8 +1814,9 @@ JSClassRef AccessibilityUIElement::getJSClass()
{ "stringForRange", stringForRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "attributedStringForRange", attributedStringForRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "attributedStringRangeIsMisspelled", attributedStringRangeIsMisspelledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "uiElementCountForSearchPredicate", uiElementCountForSearchPredicateCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeReadOnly },
+ { "uiElementCountForSearchPredicate", uiElementCountForSearchPredicateCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "uiElementForSearchPredicate", uiElementForSearchPredicateCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "selectTextWithCriteria", selectTextWithCriteriaCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "childAtIndex", childAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "linkedUIElementAtIndex", linkedUIElementAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "indexOfChild", indexOfChildCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
@@ -1505,6 +1840,7 @@ JSClassRef AccessibilityUIElement::getJSClass()
{ "uiElementAttributeValue", uiElementAttributeValueCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "numberAttributeValue", numberAttributeValueCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "boolAttributeValue", boolAttributeValueCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setBoolAttributeValue", setBoolAttributeValueCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "isAttributeSupported", isAttributeSupportedCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "isAttributeSettable", isAttributeSettableCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "isPressActionSupported", isPressActionSupportedCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
@@ -1519,6 +1855,7 @@ JSClassRef AccessibilityUIElement::getJSClass()
{ "disclosedRowAtIndex", disclosedRowAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "ariaOwnsElementAtIndex", ariaOwnsElementAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "ariaFlowToElementAtIndex", ariaFlowToElementAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "ariaControlsElementAtIndex", ariaControlsElementAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "selectedRowAtIndex", selectedRowAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "rowAtIndex", rowAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "isEqual", isEqualCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
@@ -1528,7 +1865,10 @@ JSClassRef AccessibilityUIElement::getJSClass()
{ "takeSelection", takeSelectionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "addSelection", addSelectionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "removeSelection", removeSelectionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "lineTextMarkerRangeForTextMarker", lineTextMarkerRangeForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "textMarkerRangeForElement", textMarkerRangeForElementCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "selectedTextMarkerRange", selectedTextMarkerRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "resetSelectedTextMarkerRange", resetSelectedTextMarkerRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "attributedStringForTextMarkerRangeContainsAttribute", attributedStringForTextMarkerRangeContainsAttributeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "indexForTextMarker", indexForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "isTextMarkerValid", isTextMarkerValidCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
@@ -1544,9 +1884,25 @@ JSClassRef AccessibilityUIElement::getJSClass()
{ "nextTextMarker", nextTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "previousTextMarker", previousTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "stringForTextMarkerRange", stringForTextMarkerRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "leftWordTextMarkerRangeForTextMarker", leftWordTextMarkerRangeForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "rightWordTextMarkerRangeForTextMarker", rightWordTextMarkerRangeForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "previousWordStartTextMarkerForTextMarker", previousWordStartTextMarkerForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "nextWordEndTextMarkerForTextMarker", nextWordEndTextMarkerForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "paragraphTextMarkerRangeForTextMarker", paragraphTextMarkerRangeForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "previousParagraphStartTextMarkerForTextMarker", previousParagraphStartTextMarkerForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "nextParagraphEndTextMarkerForTextMarker", nextParagraphEndTextMarkerForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "sentenceTextMarkerRangeForTextMarker", sentenceTextMarkerRangeForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "previousSentenceStartTextMarkerForTextMarker", previousSentenceStartTextMarkerForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "nextSentenceEndTextMarkerForTextMarker", nextSentenceEndTextMarkerForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setSelectedChild", setSelectedChildCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setSelectedChildAtIndex", setSelectedChildAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "removeSelectionAtIndex", removeSelectionAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setValue", setValueCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setSelectedVisibleTextRange", setSelectedVisibleTextRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "selectedChildAtIndex", selectedChildAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "scrollToMakeVisible", scrollToMakeVisibleCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "scrollToGlobalPoint", scrollToGlobalPointCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "scrollToMakeVisibleWithSubFocus", scrollToMakeVisibleWithSubFocusCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
#if PLATFORM(GTK) || PLATFORM(EFL)
{ "characterAtOffset", characterAtOffsetCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "wordAtOffset", wordAtOffsetCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
@@ -1558,8 +1914,12 @@ JSClassRef AccessibilityUIElement::getJSClass()
{ "elementsForRange", elementsForRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "increaseTextSelection", increaseTextSelectionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "decreaseTextSelection", decreaseTextSelectionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "scrollPageUp", scrollPageUpCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "scrollPageDown", scrollPageDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "scrollPageLeft", scrollPageLeftCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "scrollPageRight", scrollPageRightCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "assistiveTechnologySimulatedFocus", assistiveTechnologySimulatedFocusCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
-
+ { "fieldsetAncestorElement", fieldsetAncestorElementCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
#endif
{ 0, 0, 0 }
};
diff --git a/Tools/DumpRenderTree/AccessibilityUIElement.h b/Tools/DumpRenderTree/AccessibilityUIElement.h
index f1f21b69b..349e40976 100644
--- a/Tools/DumpRenderTree/AccessibilityUIElement.h
+++ b/Tools/DumpRenderTree/AccessibilityUIElement.h
@@ -31,7 +31,7 @@
#include <wtf/Platform.h>
#include <wtf/Vector.h>
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
#ifdef __OBJC__
typedef id PlatformUIElement;
#else
@@ -53,7 +53,7 @@ typedef AtkObject* PlatformUIElement;
typedef void* PlatformUIElement;
#endif
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
#ifdef __OBJC__
typedef id NotificationHandler;
#else
@@ -109,6 +109,7 @@ public:
void uiElementArrayAttributeValue(JSStringRef attribute, Vector<AccessibilityUIElement>& elements) const;
AccessibilityUIElement uiElementAttributeValue(JSStringRef attribute) const;
bool boolAttributeValue(JSStringRef attribute);
+ void setBoolAttributeValue(JSStringRef attribute, bool value);
bool isAttributeSupported(JSStringRef attribute);
bool isAttributeSettable(JSStringRef attribute);
bool isPressActionSupported();
@@ -117,11 +118,13 @@ public:
JSStringRef role();
JSStringRef subrole();
JSStringRef roleDescription();
+ JSStringRef computedRoleString();
JSStringRef title();
JSStringRef description();
JSStringRef language();
JSStringRef stringValue();
JSStringRef accessibilityValue() const;
+ void setValue(JSStringRef);
JSStringRef helpText() const;
JSStringRef orientation() const;
double x();
@@ -147,6 +150,9 @@ public:
void setSelectedChild(AccessibilityUIElement*) const;
unsigned selectedChildrenCount() const;
AccessibilityUIElement selectedChildAtIndex(unsigned) const;
+ void setSelectedChildAtIndex(unsigned) const;
+ void removeSelectionAtIndex(unsigned) const;
+ void clearSelectedChildren() const;
bool isExpanded() const;
bool isChecked() const;
@@ -154,6 +160,8 @@ public:
bool isOffScreen() const;
bool isCollapsed() const;
bool isIgnored() const;
+ bool isSingleLine() const;
+ bool isMultiLine() const;
bool isIndeterminate() const;
bool hasPopup() const;
int hierarchicalLevel() const;
@@ -191,6 +199,7 @@ public:
// ARIA specific
AccessibilityUIElement ariaOwnsElementAtIndex(unsigned);
AccessibilityUIElement ariaFlowToElementAtIndex(unsigned);
+ AccessibilityUIElement ariaControlsElementAtIndex(unsigned);
// ARIA Drag and Drop
bool ariaIsGrabbed() const;
@@ -206,14 +215,23 @@ public:
JSStringRef stringForRange(unsigned location, unsigned length);
JSStringRef attributedStringForRange(unsigned location, unsigned length);
bool attributedStringRangeIsMisspelled(unsigned location, unsigned length);
- unsigned uiElementCountForSearchPredicate(JSContextRef, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly);
- AccessibilityUIElement uiElementForSearchPredicate(JSContextRef, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly);
+ unsigned uiElementCountForSearchPredicate(JSContextRef, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly);
+ AccessibilityUIElement uiElementForSearchPredicate(JSContextRef, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly);
+ JSStringRef selectTextWithCriteria(JSContextRef, JSStringRef ambiguityResolution, JSValueRef searchStrings, JSStringRef replacementString, JSStringRef activity);
#if PLATFORM(IOS)
void elementsForRange(unsigned location, unsigned length, Vector<AccessibilityUIElement>& elements);
JSStringRef stringForSelection();
void increaseTextSelection();
void decreaseTextSelection();
AccessibilityUIElement linkedElement();
+
+ bool scrollPageUp();
+ bool scrollPageDown();
+ bool scrollPageLeft();
+ bool scrollPageRight();
+
+ bool hasContainedByFieldsetTrait();
+ AccessibilityUIElement fieldsetAncestorElement();
#endif
#if PLATFORM(GTK) || PLATFORM(EFL)
@@ -232,6 +250,7 @@ public:
AccessibilityUIElement verticalScrollbar() const;
// Text markers.
+ AccessibilityTextMarkerRange lineTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
AccessibilityTextMarkerRange textMarkerRangeForElement(AccessibilityUIElement*);
AccessibilityTextMarkerRange textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker);
AccessibilityTextMarker startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange*);
@@ -244,6 +263,19 @@ public:
AccessibilityUIElement accessibilityElementForTextMarker(AccessibilityTextMarker*);
AccessibilityTextMarker startTextMarker();
AccessibilityTextMarker endTextMarker();
+ AccessibilityTextMarkerRange leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
+ AccessibilityTextMarkerRange rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
+ AccessibilityTextMarker previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*);
+ AccessibilityTextMarker nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*);
+ AccessibilityTextMarkerRange paragraphTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
+ AccessibilityTextMarker previousParagraphStartTextMarkerForTextMarker(AccessibilityTextMarker*);
+ AccessibilityTextMarker nextParagraphEndTextMarkerForTextMarker(AccessibilityTextMarker*);
+ AccessibilityTextMarkerRange sentenceTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
+ AccessibilityTextMarker previousSentenceStartTextMarkerForTextMarker(AccessibilityTextMarker*);
+ AccessibilityTextMarker nextSentenceEndTextMarkerForTextMarker(AccessibilityTextMarker*);
+ AccessibilityTextMarkerRange selectedTextMarkerRange();
+ void resetSelectedTextMarkerRange();
+ bool setSelectedVisibleTextRange(AccessibilityTextMarkerRange*);
JSStringRef stringForTextMarkerRange(AccessibilityTextMarkerRange*);
int textMarkerRangeLength(AccessibilityTextMarkerRange*);
@@ -263,17 +295,17 @@ public:
void removeNotificationListener();
#if PLATFORM(IOS)
- JSStringRef iphoneLabel();
- JSStringRef iphoneValue();
- JSStringRef iphoneTraits();
- JSStringRef iphoneHint();
- JSStringRef iphoneIdentifier();
- bool iphoneIsElement();
- int iphoneElementTextPosition();
- int iphoneElementTextLength();
+ JSStringRef traits();
+ JSStringRef identifier();
+ int elementTextPosition();
+ int elementTextLength();
AccessibilityUIElement headerElementAtIndex(unsigned);
// This will simulate the accessibilityDidBecomeFocused API in UIKit.
void assistiveTechnologySimulatedFocus();
+
+ bool isTextArea() const;
+ bool isSearchField() const;
+
#endif // PLATFORM(IOS)
#if PLATFORM(MAC) && !PLATFORM(IOS)
@@ -289,9 +321,7 @@ private:
static JSClassRef getJSClass();
PlatformUIElement m_element;
-#if PLATFORM(IOS)
- JSObjectRef m_notificationFunctionCallback;
-#elif PLATFORM(MAC)
+#if PLATFORM(COCOA)
// A retained, platform specific object used to help manage notifications for this object.
NotificationHandler m_notificationHandler;
#endif
diff --git a/Tools/DumpRenderTree/Bindings/CodeGeneratorDumpRenderTree.pm b/Tools/DumpRenderTree/Bindings/CodeGeneratorDumpRenderTree.pm
new file mode 100644
index 000000000..d39d68a0f
--- /dev/null
+++ b/Tools/DumpRenderTree/Bindings/CodeGeneratorDumpRenderTree.pm
@@ -0,0 +1,563 @@
+# Copyright (C) 2016 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+use strict;
+use warnings;
+use File::Spec;
+
+package CodeGeneratorDumpRenderTree;
+
+sub new
+{
+ my ($class, $codeGenerator, $writeDependencies, $verbose, $idlFilePath) = @_;
+
+ my $reference = {
+ codeGenerator => $codeGenerator,
+ idlFilePath => $idlFilePath,
+ };
+
+ bless($reference, $class);
+ return $reference;
+}
+
+sub GenerateInterface
+{
+}
+
+sub WriteData
+{
+ my ($self, $interface, $outputDir) = @_;
+
+ foreach my $file ($self->_generateHeaderFile($interface), $self->_generateImplementationFile($interface)) {
+ $$self{codeGenerator}->UpdateFile(File::Spec->catfile($outputDir, $$file{name}), join("", @{$$file{contents}}));
+ }
+}
+
+sub _className
+{
+ my ($type) = @_;
+
+ return "JS" . _implementationClassName($type);
+}
+
+sub _classRefGetter
+{
+ my ($self, $type) = @_;
+
+ return $$self{codeGenerator}->WK_lcfirst(_implementationClassName($type)) . "Class";
+}
+
+sub _parseLicenseBlock
+{
+ my ($fileHandle) = @_;
+
+ my ($copyright, $readCount, $buffer, $currentCharacter, $previousCharacter);
+ my $startSentinel = "/*";
+ my $lengthOfStartSentinel = length($startSentinel);
+ $readCount = read($fileHandle, $buffer, $lengthOfStartSentinel);
+ return "" if ($readCount < $lengthOfStartSentinel || $buffer ne $startSentinel);
+ $copyright = $buffer;
+
+ while ($readCount = read($fileHandle, $currentCharacter, 1)) {
+ $copyright .= $currentCharacter;
+ return $copyright if $currentCharacter eq "/" && $previousCharacter eq "*";
+ $previousCharacter = $currentCharacter;
+ }
+
+ return "";
+}
+
+sub _parseLicenseBlockFromFile
+{
+ my ($path) = @_;
+ open my $fileHandle, "<", $path or die "Failed to open $path for reading: $!";
+ my $licenseBlock = _parseLicenseBlock($fileHandle);
+ close($fileHandle);
+ return $licenseBlock;
+}
+
+sub _defaultLicenseBlock
+{
+ return <<EOF;
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+EOF
+}
+
+sub _licenseBlock
+{
+ my ($self) = @_;
+ return $self->{licenseBlock} if $self->{licenseBlock};
+
+ my $licenseBlock = _parseLicenseBlockFromFile($self->{idlFilePath}) || _defaultLicenseBlock();
+ $self->{licenseBlock} = $licenseBlock;
+ return $licenseBlock;
+}
+
+sub _generateHeaderFile
+{
+ my ($self, $interface) = @_;
+
+ my @contents = ();
+
+ my $type = $interface->type;
+ my $className = _className($type);
+ my $implementationClassName = _implementationClassName($type);
+ my $filename = $className . ".h";
+
+ push(@contents, $self->_licenseBlock());
+
+ my $parentClassName = _parentClassName($interface);
+
+ push(@contents, <<EOF);
+
+#ifndef ${className}_h
+#define ${className}_h
+
+#include "${parentClassName}.h"
+EOF
+ push(@contents, <<EOF);
+
+namespace WTR {
+
+class ${implementationClassName};
+
+class ${className} : public ${parentClassName} {
+public:
+ static JSClassRef @{[$self->_classRefGetter($type)]}();
+
+private:
+ static const JSStaticFunction* staticFunctions();
+ static const JSStaticValue* staticValues();
+EOF
+
+ if (my @functions = @{$interface->functions}) {
+ push(@contents, "\n // Functions\n\n");
+ foreach my $function (@functions) {
+ push(@contents, " static JSValueRef @{[$function->name]}(JSContextRef, JSObjectRef, JSObjectRef, size_t, const JSValueRef[], JSValueRef*);\n");
+ }
+ }
+
+ if (my @attributes = @{$interface->attributes}) {
+ push(@contents, "\n // Attributes\n\n");
+ foreach my $attribute (@attributes) {
+ push(@contents, " static JSValueRef @{[$self->_getterName($attribute)]}(JSContextRef, JSObjectRef, JSStringRef, JSValueRef*);\n");
+ push(@contents, " static bool @{[$self->_setterName($attribute)]}(JSContextRef, JSObjectRef, JSStringRef, JSValueRef, JSValueRef*);\n") unless $attribute->isReadOnly;
+ }
+ }
+
+ push(@contents, <<EOF);
+};
+
+${implementationClassName}* to${implementationClassName}(JSContextRef, JSValueRef);
+
+} // namespace WTR
+
+#endif // ${className}_h
+EOF
+
+ return { name => $filename, contents => \@contents };
+}
+
+sub _generateImplementationFile
+{
+ my ($self, $interface) = @_;
+
+ my @contentsPrefix = ();
+ my %contentsIncludes = ();
+ my @contents = ();
+
+ my $type = $interface->type;
+ my $className = _className($type);
+ my $implementationClassName = _implementationClassName($type);
+ my $filename = $className . ".cpp";
+
+ push(@contentsPrefix, $self->_licenseBlock());
+
+ my $classRefGetter = $self->_classRefGetter($type);
+ my $parentClassName = _parentClassName($interface);
+
+ $contentsIncludes{"${className}.h"} = 1;
+ $contentsIncludes{"${implementationClassName}.h"} = 1;
+
+ push(@contentsPrefix, <<EOF);
+
+EOF
+
+ push(@contents, <<EOF);
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <wtf/GetPtr.h>
+
+namespace WTR {
+
+${implementationClassName}* to${implementationClassName}(JSContextRef context, JSValueRef value)
+{
+ if (!context || !value || !${className}::${classRefGetter}() || !JSValueIsObjectOfClass(context, value, ${className}::${classRefGetter}()))
+ return 0;
+ return static_cast<${implementationClassName}*>(JSWrapper::unwrap(context, value));
+}
+
+JSClassRef ${className}::${classRefGetter}()
+{
+ static JSClassRef jsClass;
+ if (!jsClass) {
+ JSClassDefinition definition = kJSClassDefinitionEmpty;
+ definition.className = "@{[$type->name]}";
+ definition.parentClass = @{[$self->_parentClassRefGetterExpression($interface)]};
+ definition.staticValues = staticValues();
+ definition.staticFunctions = staticFunctions();
+EOF
+
+ push(@contents, " definition.initialize = initialize;\n") unless _parentInterface($interface);
+ push(@contents, " definition.finalize = finalize;\n") unless _parentInterface($interface);
+
+ push(@contents, <<EOF);
+ jsClass = JSClassCreate(&definition);
+ }
+ return jsClass;
+}
+
+EOF
+
+ push(@contents, $self->_staticFunctionsGetterImplementation($interface), "\n");
+ push(@contents, $self->_staticValuesGetterImplementation($interface));
+
+ if (my @functions = @{$interface->functions}) {
+ push(@contents, "\n// Functions\n");
+
+ foreach my $function (@functions) {
+ push(@contents, <<EOF);
+
+JSValueRef ${className}::@{[$function->name]}(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ ${implementationClassName}* impl = to${implementationClassName}(context, thisObject);
+ if (!impl)
+ return JSValueMakeUndefined(context);
+
+EOF
+ my $functionCall;
+ if ($function->extendedAttributes->{"CustomArgumentHandling"}) {
+ $functionCall = "impl->" . $function->name . "(context, argumentCount, arguments, exception)";
+ } else {
+ my @arguments = ();
+ my @specifiedArguments = @{$function->arguments};
+
+ $self->_includeHeaders(\%contentsIncludes, $function->type);
+
+ if ($function->extendedAttributes->{"PassContext"}) {
+ push(@arguments, "context");
+ }
+
+ foreach my $i (0..$#specifiedArguments) {
+ my $argument = $specifiedArguments[$i];
+
+ $self->_includeHeaders(\%contentsIncludes, $type);
+
+ push(@contents, " " . $self->_platformTypeVariableDeclaration($argument->type, $argument->name, "arguments[$i]", "argumentCount > $i") . "\n");
+
+ push(@arguments, $self->_argumentExpression($argument));
+ }
+
+ $functionCall = "impl->" . $function->name . "(" . join(", ", @arguments) . ")";
+ }
+
+ push(@contents, " ${functionCall};\n\n") if $function->type->name eq "void";
+ push(@contents, " return " . $self->_returnExpression($function->type, $functionCall) . ";\n}\n");
+ }
+ }
+
+ if (my @attributes = @{$interface->attributes}) {
+ push(@contents, "\n// Attributes\n");
+ foreach my $attribute (@attributes) {
+ $self->_includeHeaders(\%contentsIncludes, $attribute->type);
+
+ my $getterName = $self->_getterName($attribute);
+ my $getterExpression = "impl->${getterName}()";
+
+ push(@contents, <<EOF);
+
+JSValueRef ${className}::${getterName}(JSContextRef context, JSObjectRef object, JSStringRef, JSValueRef* exception)
+{
+ ${implementationClassName}* impl = to${implementationClassName}(context, object);
+ if (!impl)
+ return JSValueMakeUndefined(context);
+
+ return @{[$self->_returnExpression($attribute->type, $getterExpression)]};
+}
+EOF
+
+ unless ($attribute->isReadOnly) {
+ push(@contents, <<EOF);
+
+bool ${className}::@{[$self->_setterName($attribute)]}(JSContextRef context, JSObjectRef object, JSStringRef, JSValueRef value, JSValueRef* exception)
+{
+ ${implementationClassName}* impl = to${implementationClassName}(context, object);
+ if (!impl)
+ return false;
+
+EOF
+
+ my $platformValue = $self->_platformTypeConstructor($attribute->type, "value");
+
+ push(@contents, <<EOF);
+ impl->@{[$self->_setterName($attribute)]}(${platformValue});
+
+ return true;
+}
+EOF
+ }
+ }
+ }
+
+ push(@contents, <<EOF);
+
+} // namespace WTR
+
+EOF
+
+ unshift(@contents, map { "#include \"$_\"\n" } sort keys(%contentsIncludes));
+ unshift(@contents, "#include \"config.h\"\n");
+ unshift(@contents, @contentsPrefix);
+
+ return { name => $filename, contents => \@contents };
+}
+
+sub _getterName
+{
+ my ($self, $attribute) = @_;
+
+ return $attribute->name;
+}
+
+sub _includeHeaders
+{
+ my ($self, $headers, $type) = @_;
+
+ return unless defined $type;
+ return if $type->name eq "boolean";
+ return if $type->name eq "object";
+ return if $$self{codeGenerator}->IsNonPointerType($type);
+ return if $$self{codeGenerator}->IsStringType($type);
+
+ $$headers{_className($type) . ".h"} = 1;
+ $$headers{_implementationClassName($type) . ".h"} = 1;
+}
+
+sub _implementationClassName
+{
+ my ($type) = @_;
+
+ return $type->name;
+}
+
+sub _parentClassName
+{
+ my ($interface) = @_;
+
+ my $parentInterface = _parentInterface($interface);
+ return $parentInterface ? _className($parentInterface) : "JSWrapper";
+}
+
+sub _parentClassRefGetterExpression
+{
+ my ($self, $interface) = @_;
+
+ my $parentInterface = _parentInterface($interface);
+ return $parentInterface ? $self->_classRefGetter($parentInterface) . "()" : "0";
+}
+
+sub _parentInterface
+{
+ my ($interface) = @_;
+ return $interface->parentType;
+}
+
+sub _platformType
+{
+ my ($self, $type) = @_;
+
+ return undef unless defined $type;
+
+ return "bool" if $type->name eq "boolean";
+ return "JSValueRef" if $type->name eq "object";
+ return "JSRetainPtr<JSStringRef>" if $$self{codeGenerator}->IsStringType($type);
+ return "double" if $$self{codeGenerator}->IsNonPointerType($type);
+ return _implementationClassName($type);
+}
+
+sub _platformTypeConstructor
+{
+ my ($self, $type, $argumentName) = @_;
+
+ return "JSValueToNullableBoolean(context, $argumentName)" if $type->name eq "boolean" && $type->isNullable;
+ return "JSValueToBoolean(context, $argumentName)" if $type->name eq "boolean";
+ return "$argumentName" if $type->name eq "object";
+ return "JSRetainPtr<JSStringRef>(Adopt, JSValueToStringCopy(context, $argumentName, 0))" if $$self{codeGenerator}->IsStringType($type);
+ return "JSValueToNumber(context, $argumentName, 0)" if $$self{codeGenerator}->IsNonPointerType($type);
+ return "to" . _implementationClassName($type) . "(context, $argumentName)";
+}
+
+sub _platformTypeVariableDeclaration
+{
+ my ($self, $type, $variableName, $argumentName, $condition) = @_;
+
+ my $platformType = $self->_platformType($type);
+ my $constructor = $self->_platformTypeConstructor($type, $argumentName);
+
+ my %nonPointerTypes = (
+ "bool" => 1,
+ "double" => 1,
+ "JSRetainPtr<JSStringRef>" => 1,
+ "JSValueRef" => 1,
+ );
+
+ my $nullValue = "0";
+ if ($platformType eq "JSValueRef") {
+ $nullValue = "JSValueMakeUndefined(context)";
+ } elsif (defined $nonPointerTypes{$platformType} && $platformType ne "double") {
+ $nullValue = "$platformType()";
+ }
+
+ $platformType .= "*" unless defined $nonPointerTypes{$platformType};
+
+ return "$platformType $variableName = $condition && $constructor;" if $condition && $platformType eq "bool";
+ return "$platformType $variableName = $condition ? $constructor : $nullValue;" if $condition;
+ return "$platformType $variableName = $constructor;";
+}
+
+sub _returnExpression
+{
+ my ($self, $returnType, $expression) = @_;
+
+ return "JSValueMakeUndefined(context)" if $returnType->name eq "void";
+ return "JSValueMakeBooleanOrNull(context, ${expression})" if $returnType->name eq "boolean" && $returnType->isNullable;
+ return "JSValueMakeBoolean(context, ${expression})" if $returnType->name eq "boolean";
+ return "${expression}" if $returnType->name eq "object";
+ return "JSValueMakeNumber(context, ${expression})" if $$self{codeGenerator}->IsNonPointerType($returnType);
+ return "JSValueMakeStringOrNull(context, ${expression}.get())" if $$self{codeGenerator}->IsStringType($returnType);
+ return "toJS(context, WTF::getPtr(${expression}))";
+}
+
+sub _argumentExpression
+{
+ my ($self, $argument) = @_;
+
+ my $type = $argument->type;
+ my $name = $argument->name;
+
+ return "${name}.get()" if $$self{codeGenerator}->IsStringType($type);
+ return $name;
+}
+
+sub _setterName
+{
+ my ($self, $attribute) = @_;
+
+ my $name = $attribute->name;
+
+ return "set" . $$self{codeGenerator}->WK_ucfirst($name);
+}
+
+sub _staticFunctionsGetterImplementation
+{
+ my ($self, $interface) = @_;
+
+ my $mapFunction = sub {
+ my $name = $_->name;
+ my @attributes = qw(kJSPropertyAttributeDontDelete kJSPropertyAttributeReadOnly);
+ push(@attributes, "kJSPropertyAttributeDontEnum") if $_->extendedAttributes->{"DontEnum"};
+
+ return "{ \"$name\", $name, " . join(" | ", @attributes) . " }";
+ };
+
+ return $self->_staticFunctionsOrValuesGetterImplementation($interface, "function", "{ 0, 0, 0 }", $mapFunction, $interface->functions);
+}
+
+sub _staticFunctionsOrValuesGetterImplementation
+{
+ my ($self, $interface, $functionOrValue, $arrayTerminator, $mapFunction, $functionsOrAttributes) = @_;
+
+ my $className = _className($interface->type);
+ my $uppercaseFunctionOrValue = $$self{codeGenerator}->WK_ucfirst($functionOrValue);
+
+ my $result = <<EOF;
+const JSStatic${uppercaseFunctionOrValue}* ${className}::static${uppercaseFunctionOrValue}s()
+{
+EOF
+
+ my @initializers = map(&$mapFunction, @{$functionsOrAttributes});
+ return $result . " return 0;\n}\n" unless @initializers;
+
+ $result .= <<EOF
+ static const JSStatic${uppercaseFunctionOrValue} ${functionOrValue}s[] = {
+ @{[join(",\n ", @initializers)]},
+ ${arrayTerminator}
+ };
+ return ${functionOrValue}s;
+}
+EOF
+}
+
+sub _staticValuesGetterImplementation
+{
+ my ($self, $interface) = @_;
+
+ my $mapFunction = sub {
+ return if $_->extendedAttributes->{"NoImplementation"};
+
+ my $attributeName = $_->name;
+ my $getterName = $self->_getterName($_);
+ my $setterName = $_->isReadOnly ? "0" : $self->_setterName($_);
+ my @attributes = qw(kJSPropertyAttributeDontDelete);
+ push(@attributes, "kJSPropertyAttributeReadOnly") if $_->isReadOnly;
+ push(@attributes, "kJSPropertyAttributeDontEnum") if $_->extendedAttributes->{"DontEnum"};
+
+ return "{ \"$attributeName\", $getterName, $setterName, " . join(" | ", @attributes) . " }";
+ };
+
+ return $self->_staticFunctionsOrValuesGetterImplementation($interface, "value", "{ 0, 0, 0, 0 }", $mapFunction, $interface->attributes);
+}
+
+1;
diff --git a/Tools/DumpRenderTree/CMakeLists.txt b/Tools/DumpRenderTree/CMakeLists.txt
new file mode 100644
index 000000000..a34ba0a44
--- /dev/null
+++ b/Tools/DumpRenderTree/CMakeLists.txt
@@ -0,0 +1,100 @@
+set(WEBKIT_TESTRUNNER_SHARED_DIR "${TOOLS_DIR}/TestRunnerShared/")
+set(WEBKIT_TESTRUNNER_UISCRIPTCONTEXT_DIR "${TOOLS_DIR}/TestRunnerShared/UIScriptContext")
+set(DUMP_RENDER_TREE_BINDINGS_DIR "${TOOLS_DIR}/DumpRenderTree/Bindings")
+
+file(MAKE_DIRECTORY ${DERIVED_SOURCES_DIR}/DumpRenderTree)
+
+set(DumpRenderTree_SOURCES
+ AccessibilityController.cpp
+ AccessibilityTextMarker.cpp
+ AccessibilityUIElement.cpp
+ CyclicRedundancyCheck.cpp
+ DumpRenderTreeCommon.cpp
+ GCController.cpp
+ JavaScriptThreading.cpp
+ PixelDumpSupport.cpp
+ TestRunner.cpp
+ WorkQueue.cpp
+ ${WEBKIT_TESTRUNNER_UISCRIPTCONTEXT_DIR}/UIScriptContext.cpp
+ ${WEBKIT_TESTRUNNER_UISCRIPTCONTEXT_DIR}/UIScriptController.cpp
+ ${WEBKIT_TESTRUNNER_SHARED_DIR}/Bindings/JSWrapper.cpp
+)
+
+set(DumpRenderTree_LIBRARIES
+ WebCoreTestSupport
+ JavaScriptCore
+)
+
+set(DumpRenderTree_INCLUDE_DIRECTORIES
+ ${DERIVED_SOURCES_DIR}/DumpRenderTree
+ ${WEBKIT_TESTRUNNER_UISCRIPTCONTEXT_DIR}
+ ${WEBKIT_TESTRUNNER_SHARED_DIR}/Bindings
+ ${TOOLS_DIR}/DumpRenderTree
+ ${CMAKE_SOURCE_DIR}/Source
+ ${WEBCORE_DIR}/testing/js
+)
+
+set(TestNetscapePlugIn_SOURCES
+ TestNetscapePlugIn/PluginObject.cpp
+ TestNetscapePlugIn/PluginTest.cpp
+ TestNetscapePlugIn/TestObject.cpp
+ TestNetscapePlugIn/main.cpp
+
+ TestNetscapePlugIn/Tests/DocumentOpenInDestroyStream.cpp
+ TestNetscapePlugIn/Tests/EvaluateJSAfterRemovingPluginElement.cpp
+ TestNetscapePlugIn/Tests/FormValue.cpp
+ TestNetscapePlugIn/Tests/GetURLNotifyWithURLThatFailsToLoad.cpp
+ TestNetscapePlugIn/Tests/GetURLWithJavaScriptURL.cpp
+ TestNetscapePlugIn/Tests/GetURLWithJavaScriptURLDestroyingPlugin.cpp
+ TestNetscapePlugIn/Tests/GetUserAgentWithNullNPPFromNPPNew.cpp
+ TestNetscapePlugIn/Tests/LogNPPSetWindow.cpp
+ TestNetscapePlugIn/Tests/NPDeallocateCalledBeforeNPShutdown.cpp
+ TestNetscapePlugIn/Tests/NPPNewFails.cpp
+ TestNetscapePlugIn/Tests/NPPSetWindowCalledDuringDestruction.cpp
+ TestNetscapePlugIn/Tests/NPRuntimeCallsWithNullNPP.cpp
+ TestNetscapePlugIn/Tests/NPRuntimeObjectFromDestroyedPlugin.cpp
+ TestNetscapePlugIn/Tests/NPRuntimeRemoveProperty.cpp
+ TestNetscapePlugIn/Tests/NullNPPGetValuePointer.cpp
+ TestNetscapePlugIn/Tests/PassDifferentNPPStruct.cpp
+ TestNetscapePlugIn/Tests/PluginScriptableNPObjectInvokeDefault.cpp
+ TestNetscapePlugIn/Tests/PluginScriptableObjectOverridesAllProperties.cpp
+ TestNetscapePlugIn/Tests/PrivateBrowsing.cpp
+ TestNetscapePlugIn/Tests/ToStringAndValueOfObject.cpp
+ TestNetscapePlugIn/Tests/URLRedirect.cpp
+)
+
+set(TestNetscapePlugIn_LIBRARIES
+ JavaScriptCore
+ WTF
+ WebCoreTestSupport
+)
+
+set(DumpRenderTree_IDL_FILES
+ "${WEBKIT_TESTRUNNER_UISCRIPTCONTEXT_DIR}/Bindings/UIScriptController.idl"
+)
+
+GENERATE_BINDINGS(DumpRenderTreeBindings
+ OUTPUT_SOURCE DumpRenderTree_SOURCES
+ INPUT_FILES ${DumpRenderTree_IDL_FILES}
+ BASE_DIR ${DUMP_RENDER_TREE_BINDINGS_DIR}
+ IDL_INCLUDES Bindings
+ FEATURES ${FEATURE_DEFINES_WITH_SPACE_SEPARATOR}
+ DESTINATION ${DERIVED_SOURCES_DIR}/DumpRenderTree
+ GENERATOR DumpRenderTree)
+
+WEBKIT_INCLUDE_CONFIG_FILES_IF_EXISTS()
+
+include_directories(${DumpRenderTree_INCLUDE_DIRECTORIES})
+
+add_executable(DumpRenderTree ${DumpRenderTree_SOURCES})
+target_link_libraries(DumpRenderTree ${DumpRenderTree_LIBRARIES})
+add_dependencies(DumpRenderTree DumpRenderTreeBindings)
+
+if (ENABLE_NETSCAPE_PLUGIN_API)
+ add_library(TestNetscapePlugIn SHARED ${TestNetscapePlugIn_SOURCES})
+ target_link_libraries(TestNetscapePlugIn ${TestNetscapePlugIn_LIBRARIES})
+endif ()
+
+if (WIN32)
+ add_dependencies(DumpRenderTree DumpRenderTreeLib)
+endif ()
diff --git a/Tools/DumpRenderTree/DefaultPolicyDelegate.h b/Tools/DumpRenderTree/DefaultPolicyDelegate.h
new file mode 100644
index 000000000..6ff5becca
--- /dev/null
+++ b/Tools/DumpRenderTree/DefaultPolicyDelegate.h
@@ -0,0 +1,13 @@
+//
+// DefaultPolicyDelegate.h
+// DumpRenderTree
+//
+// Created by Anders Carlsson on 7/9/13.
+//
+//
+
+#import <WebKit/WebDefaultPolicyDelegate.h>
+
+@interface DefaultPolicyDelegate : WebDefaultPolicyDelegate
+
+@end
diff --git a/Tools/DumpRenderTree/DerivedSources.make b/Tools/DumpRenderTree/DerivedSources.make
new file mode 100644
index 000000000..05bffef75
--- /dev/null
+++ b/Tools/DumpRenderTree/DerivedSources.make
@@ -0,0 +1,50 @@
+# Copyright (C) 2016 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+UISCRIPTCONTEXT_DIR = $(DumpRenderTree)/../TestRunnerShared/UIScriptContext/Bindings
+
+VPATH = \
+ $(UISCRIPTCONTEXT_DIR) \
+#
+
+UICONTEXT_INTERFACES = \
+ UIScriptController \
+#
+
+SCRIPTS = \
+ $(WebCoreScripts)/CodeGenerator.pm \
+ $(DumpRenderTree)/Bindings/CodeGeneratorDumpRenderTree.pm \
+ $(WebCoreScripts)/IDLParser.pm \
+ $(WebCoreScripts)/generate-bindings.pl \
+#
+
+.PHONY : all
+
+JS%.h JS%.cpp : %.idl $(SCRIPTS)
+ @echo Generating bindings for $*...
+ @perl -I $(WebCoreScripts) -I $(UISCRIPTCONTEXT_DIR) -I $(DumpRenderTree)/Bindings $(WebCoreScripts)/generate-bindings.pl --defines "" --include $(UISCRIPTCONTEXT_DIR) --outputDir . --generator DumpRenderTree $<
+
+all : \
+ $(UICONTEXT_INTERFACES:%=JS%.h) \
+ $(UICONTEXT_INTERFACES:%=JS%.cpp) \
+#
diff --git a/Tools/DumpRenderTree/DumpRenderTree.h b/Tools/DumpRenderTree/DumpRenderTree.h
index 3e6323525..743e68255 100644
--- a/Tools/DumpRenderTree/DumpRenderTree.h
+++ b/Tools/DumpRenderTree/DumpRenderTree.h
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -26,15 +26,9 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef DumpRenderTree_h
-#define DumpRenderTree_h
+#pragma once
-// FIXME: Remove this when all platforms are using config.h
-#ifndef Config_H
-#include <wtf/Platform.h>
-#endif
-
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
#include "DumpRenderTreeMac.h"
#elif PLATFORM(WIN)
#include "DumpRenderTreeWin.h"
@@ -45,6 +39,7 @@
#endif
#include <string>
+#include <wtf/Platform.h>
#include <wtf/RefPtr.h>
#if !OS(OPENBSD)
@@ -62,14 +57,12 @@ void dump();
void displayWebView();
struct TestCommand {
- TestCommand() : shouldDumpPixels(false), timeout(30000) { }
-
std::string pathOrURL;
- bool shouldDumpPixels;
+ std::string absolutePath;
+ bool shouldDumpPixels { false };
std::string expectedPixelHash;
- int timeout; // in ms
+ int timeout { 30000 }; // in ms
+ bool dumpJSConsoleLogInStdErr { false };
};
TestCommand parseInputLine(const std::string&);
-
-#endif // DumpRenderTree_h
diff --git a/Tools/DumpRenderTree/DumpRenderTreeCommon.cpp b/Tools/DumpRenderTree/DumpRenderTreeCommon.cpp
index 3cb97ebfd..3c7aa61e8 100644
--- a/Tools/DumpRenderTree/DumpRenderTreeCommon.cpp
+++ b/Tools/DumpRenderTree/DumpRenderTreeCommon.cpp
@@ -1,3 +1,28 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
#include "config.h"
#include "DumpRenderTree.h"
@@ -70,14 +95,18 @@ TestCommand parseInputLine(const std::string& inputLine)
result.pathOrURL = arg;
while (tokenizer.hasNext()) {
arg = tokenizer.next();
- if (arg == std::string("--timeout")) {
+ if (arg == "--timeout") {
std::string timeoutToken = tokenizer.next();
result.timeout = atoi(timeoutToken.c_str());
- } else if (arg == std::string("-p") || arg == std::string("--pixel-test")) {
+ } else if (arg == "-p" || arg == "--pixel-test") {
result.shouldDumpPixels = true;
if (tokenizer.hasNext())
result.expectedPixelHash = tokenizer.next();
- } else
+ } else if (arg == "--dump-jsconsolelog-in-stderr")
+ result.dumpJSConsoleLogInStdErr = true;
+ else if (arg == std::string("--absolutePath"))
+ result.absolutePath = tokenizer.next();
+ else
die(inputLine);
}
diff --git a/Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.h b/Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.h
new file mode 100644
index 000000000..1d42a474c
--- /dev/null
+++ b/Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2009, Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#if !PLATFORM(IOS)
+
+#import <Cocoa/Cocoa.h>
+
+// An implementation of NSDraggingSource for use with DumpRenderTreeDraggingInfo when dragging files
+// Used by -[EventSendingController beginDragWithFiles:]
+
+@interface DumpRenderTreeFileDraggingSource : NSObject {
+}
+
+- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)flag;
+
+@end
+
+#endif
diff --git a/Tools/DumpRenderTree/DumpRenderTreePrefix.h b/Tools/DumpRenderTree/DumpRenderTreePrefix.h
index 64eae0704..105b54356 100644
--- a/Tools/DumpRenderTree/DumpRenderTreePrefix.h
+++ b/Tools/DumpRenderTree/DumpRenderTreePrefix.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2005 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -26,8 +26,17 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H && defined(BUILDING_WITH_CMAKE)
+#include "cmakeconfig.h"
+#endif
+
#include <wtf/Platform.h>
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#endif
+
+#if OS(WINDOWS)
+#undef WEBCORE_EXPORT
+#define WEBCORE_EXPORT WTF_IMPORT_DECLARATION
+#endif
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/runtime/ArrayBufferView.h b/Tools/DumpRenderTree/ForwardingHeaders/runtime/ArrayBufferView.h
new file mode 100644
index 000000000..7731671c8
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/runtime/ArrayBufferView.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/ArrayBufferView.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/runtime/JSArrayBufferView.h b/Tools/DumpRenderTree/ForwardingHeaders/runtime/JSArrayBufferView.h
new file mode 100644
index 000000000..e38a8040f
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/runtime/JSArrayBufferView.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/JSArrayBufferView.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/runtime/JSExportMacros.h b/Tools/DumpRenderTree/ForwardingHeaders/runtime/JSExportMacros.h
new file mode 100644
index 000000000..4c5dcb983
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/runtime/JSExportMacros.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/JSExportMacros.h> \ No newline at end of file
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/runtime/TypedArrayInlines.h b/Tools/DumpRenderTree/ForwardingHeaders/runtime/TypedArrayInlines.h
new file mode 100644
index 000000000..6a61945ea
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/runtime/TypedArrayInlines.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/TypedArrayInlines.h>
diff --git a/Tools/DumpRenderTree/GCController.cpp b/Tools/DumpRenderTree/GCController.cpp
index 06a04fbca..781a828eb 100644
--- a/Tools/DumpRenderTree/GCController.cpp
+++ b/Tools/DumpRenderTree/GCController.cpp
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
diff --git a/Tools/DumpRenderTree/GCController.h b/Tools/DumpRenderTree/GCController.h
index afc1de087..79ceafc9f 100644
--- a/Tools/DumpRenderTree/GCController.h
+++ b/Tools/DumpRenderTree/GCController.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
diff --git a/Tools/DumpRenderTree/JavaScriptThreading.cpp b/Tools/DumpRenderTree/JavaScriptThreading.cpp
new file mode 100644
index 000000000..e2f9bade6
--- /dev/null
+++ b/Tools/DumpRenderTree/JavaScriptThreading.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * (C) 2007 Graham Dennis (graham.dennis@gmail.com)
+ * (C) 2007 Eric Seidel <eric@webkit.org>
+ * (C) 2012 Patrick Ganstere <paroga@paroga.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JavaScriptThreading.h"
+
+#include <JavaScriptCore/JavaScriptCore.h>
+#include <stdlib.h>
+#include <wtf/Assertions.h>
+#include <wtf/HashSet.h>
+#include <wtf/Lock.h>
+#include <wtf/Threading.h>
+#include <wtf/ThreadingPrimitives.h>
+#include <wtf/Vector.h>
+
+static const size_t javaScriptThreadsCount = 4;
+static bool javaScriptThreadsShouldTerminate;
+static JSContextGroupRef javaScriptThreadsGroup;
+
+static Lock& javaScriptThreadsMutex()
+{
+ DEPRECATED_DEFINE_STATIC_LOCAL(Lock, staticMutex, ());
+ return staticMutex;
+}
+
+typedef HashSet<ThreadIdentifier> ThreadSet;
+static ThreadSet& javaScriptThreads()
+{
+ DEPRECATED_DEFINE_STATIC_LOCAL(ThreadSet, staticJavaScriptThreads, ());
+ ASSERT(!javaScriptThreadsMutex().tryLock());
+ return staticJavaScriptThreads;
+}
+
+// This function exercises JSC in a loop until javaScriptThreadsShouldTerminate
+// becomes true or it probabilistically decides to spawn a replacement thread and exit.
+void runJavaScriptThread(void*)
+{
+ static const char* const script =
+ "var array = [];"
+ "for (var i = 0; i < 1024; i++) {"
+ " array.push(String(i));"
+ "}";
+
+ JSGlobalContextRef ctx;
+ {
+ LockHolder locker(javaScriptThreadsMutex());
+ ctx = JSGlobalContextCreateInGroup(javaScriptThreadsGroup, 0);
+ }
+
+ JSStringRef scriptRef;
+ {
+ LockHolder locker(javaScriptThreadsMutex());
+ scriptRef = JSStringCreateWithUTF8CString(script);
+ }
+
+ while (true) {
+ {
+ LockHolder locker(javaScriptThreadsMutex());
+ JSValueRef exception = 0;
+ JSEvaluateScript(ctx, scriptRef, 0, 0, 1, &exception);
+ ASSERT(!exception);
+ }
+
+ {
+ LockHolder locker(javaScriptThreadsMutex());
+ const size_t valuesCount = 1024;
+ JSValueRef values[valuesCount];
+ for (size_t i = 0; i < valuesCount; ++i)
+ values[i] = JSObjectMake(ctx, 0, 0);
+ }
+
+ {
+ LockHolder locker(javaScriptThreadsMutex());
+ if (javaScriptThreadsShouldTerminate)
+ break;
+ }
+
+ // Respawn probabilistically.
+ if (rand() % 5)
+ continue;
+
+ LockHolder locker(javaScriptThreadsMutex());
+ ThreadIdentifier thread = currentThread();
+ detachThread(thread);
+ javaScriptThreads().remove(thread);
+ javaScriptThreads().add(createThread(&runJavaScriptThread, 0, 0));
+ break;
+ }
+
+ LockHolder locker(javaScriptThreadsMutex());
+ JSStringRelease(scriptRef);
+ JSGarbageCollect(ctx);
+ JSGlobalContextRelease(ctx);
+}
+
+void startJavaScriptThreads()
+{
+ javaScriptThreadsGroup = JSContextGroupCreate();
+
+ LockHolder locker(javaScriptThreadsMutex());
+
+ for (size_t i = 0; i < javaScriptThreadsCount; ++i)
+ javaScriptThreads().add(createThread(&runJavaScriptThread, 0, 0));
+}
+
+void stopJavaScriptThreads()
+{
+ {
+ LockHolder locker(javaScriptThreadsMutex());
+ javaScriptThreadsShouldTerminate = true;
+ }
+
+ Vector<ThreadIdentifier, javaScriptThreadsCount> threads;
+ {
+ LockHolder locker(javaScriptThreadsMutex());
+ copyToVector(javaScriptThreads(), threads);
+ ASSERT(threads.size() == javaScriptThreadsCount);
+ }
+
+ for (size_t i = 0; i < javaScriptThreadsCount; ++i)
+ waitForThreadCompletion(threads[i]);
+
+ {
+ LockHolder locker(javaScriptThreadsMutex());
+ javaScriptThreads().clear();
+ }
+
+ JSContextGroupRelease(javaScriptThreadsGroup);
+}
diff --git a/Tools/DumpRenderTree/JavaScriptThreading.h b/Tools/DumpRenderTree/JavaScriptThreading.h
index 43795a1a2..5bbe9cafe 100644
--- a/Tools/DumpRenderTree/JavaScriptThreading.h
+++ b/Tools/DumpRenderTree/JavaScriptThreading.h
@@ -12,7 +12,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
diff --git a/Tools/DumpRenderTree/PixelDumpSupport.cpp b/Tools/DumpRenderTree/PixelDumpSupport.cpp
index ba619bbea..5160444bf 100644
--- a/Tools/DumpRenderTree/PixelDumpSupport.cpp
+++ b/Tools/DumpRenderTree/PixelDumpSupport.cpp
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -43,7 +43,6 @@
#include "PixelDumpSupportCairo.h"
#endif
-#if !PLATFORM(IOS)
void dumpWebViewAsPixelsAndCompareWithExpected(const std::string& expectedHash)
{
RefPtr<BitmapContext> context;
@@ -58,14 +57,14 @@ void dumpWebViewAsPixelsAndCompareWithExpected(const std::string& expectedHash)
// Compute the hash of the bitmap context pixels
char actualHash[33];
computeMD5HashStringForBitmapContext(context.get(), actualHash);
- printf("\nActualHash: %s\n", actualHash); // FIXME: No need for the leading newline.
+ fprintf(testResult, "\nActualHash: %s\n", actualHash); // FIXME: No need for the leading newline.
// Check the computed hash against the expected one and dump image on mismatch
bool dumpImage = true;
if (expectedHash.length() > 0) {
ASSERT(expectedHash.length() == 32);
- printf("\nExpectedHash: %s\n", expectedHash.c_str()); // FIXME: No need for the leading newline.
+ fprintf(testResult, "\nExpectedHash: %s\n", expectedHash.c_str()); // FIXME: No need for the leading newline.
if (expectedHash == actualHash) // FIXME: do case insensitive compare
dumpImage = false;
@@ -74,7 +73,6 @@ void dumpWebViewAsPixelsAndCompareWithExpected(const std::string& expectedHash)
if (dumpImage)
dumpBitmap(context.get(), actualHash);
}
-#endif
static void appendIntToVector(unsigned number, Vector<unsigned char>& vector)
{
@@ -116,20 +114,20 @@ void printPNG(const unsigned char* data, const size_t dataLength, const char* ch
Vector<unsigned char> bytesToAdd;
convertChecksumToPNGComment(checksum, bytesToAdd);
- printf("Content-Type: %s\n", "image/png");
- printf("Content-Length: %lu\n", static_cast<unsigned long>(dataLength + bytesToAdd.size()));
+ fprintf(testResult, "Content-Type: image/png\n");
+ fprintf(testResult, "Content-Length: %lu\n", static_cast<unsigned long>(dataLength + bytesToAdd.size()));
size_t insertOffset = offsetAfterIHDRChunk(data, dataLength);
- fwrite(data, 1, insertOffset, stdout);
- fwrite(bytesToAdd.data(), 1, bytesToAdd.size(), stdout);
+ fwrite(data, 1, insertOffset, testResult);
+ fwrite(bytesToAdd.data(), 1, bytesToAdd.size(), testResult);
const size_t bytesToWriteInOneChunk = 1 << 15;
data += insertOffset;
size_t dataRemainingToWrite = dataLength - insertOffset;
while (dataRemainingToWrite) {
size_t bytesToWriteInThisChunk = std::min(dataRemainingToWrite, bytesToWriteInOneChunk);
- size_t bytesWritten = fwrite(data, 1, bytesToWriteInThisChunk, stdout);
+ size_t bytesWritten = fwrite(data, 1, bytesToWriteInThisChunk, testResult);
if (bytesWritten != bytesToWriteInThisChunk)
break;
dataRemainingToWrite -= bytesWritten;
diff --git a/Tools/DumpRenderTree/PixelDumpSupport.h b/Tools/DumpRenderTree/PixelDumpSupport.h
index 3bd8820c7..1885b3569 100644
--- a/Tools/DumpRenderTree/PixelDumpSupport.h
+++ b/Tools/DumpRenderTree/PixelDumpSupport.h
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -26,20 +26,16 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef PixelDumpSupport_h
-#define PixelDumpSupport_h
+#pragma once
#include <string>
-
-#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
class BitmapContext;
void computeMD5HashStringForBitmapContext(BitmapContext*, char hashString[33]);
-PassRefPtr<BitmapContext> createPagedBitmapContext();
-PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool onscreen, bool incrementalRepaint, bool sweepHorizontally, bool drawSelectionRect);
+RefPtr<BitmapContext> createPagedBitmapContext();
+RefPtr<BitmapContext> createBitmapContextFromWebView(bool onscreen, bool incrementalRepaint, bool sweepHorizontally, bool drawSelectionRect);
void dumpBitmap(BitmapContext*, const char* checksum);
void dumpWebViewAsPixelsAndCompareWithExpected(const std::string& expectedHash);
void printPNG(const unsigned char* data, const size_t dataLength, const char* checksum);
-
-#endif // PixelDumpSupport_h
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/CMakeLists.txt b/Tools/DumpRenderTree/TestNetscapePlugIn/CMakeLists.txt
new file mode 100644
index 000000000..a5391b534
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/CMakeLists.txt
@@ -0,0 +1,61 @@
+set(WEBKIT_TESTNETSCAPEPLUGIN_DIR "${TOOLS_DIR}/DumpRenderTree/TestNetscapePlugIn")
+
+set(WebKitTestNetscapePlugIn_SOURCES
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/PluginObject.cpp
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/PluginTest.cpp
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/TestObject.cpp
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/main.cpp
+
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/DocumentOpenInDestroyStream.cpp
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/EvaluateJSAfterRemovingPluginElement.cpp
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/FormValue.cpp
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/GetURLNotifyWithURLThatFailsToLoad.cpp
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/GetURLWithJavaScriptURL.cpp
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/GetURLWithJavaScriptURLDestroyingPlugin.cpp
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/GetUserAgentWithNullNPPFromNPPNew.cpp
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/LogNPPSetWindow.cpp
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/NPDeallocateCalledBeforeNPShutdown.cpp
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/NPPNewFails.cpp
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/NPPSetWindowCalledDuringDestruction.cpp
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/NPRuntimeCallsWithNullNPP.cpp
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/NPRuntimeObjectFromDestroyedPlugin.cpp
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/NPRuntimeRemoveProperty.cpp
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/NullNPPGetValuePointer.cpp
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/PassDifferentNPPStruct.cpp
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/PluginScriptableNPObjectInvokeDefault.cpp
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/PluginScriptableObjectOverridesAllProperties.cpp
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/PrivateBrowsing.cpp
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/ToStringAndValueOfObject.cpp
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/URLRedirect.cpp
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/Tests/x11/CallInvalidateRectWithNullNPPArgument.cpp
+)
+
+set(WebKitTestNetscapePlugIn_INCLUDE_DIRECTORIES
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}
+ ${WEBKIT_TESTNETSCAPEPLUGIN_DIR}/ForwardingHeaders
+ ${WEBCORE_DIR}
+ ${WTF_DIR}
+)
+
+set(WebKitTestNetscapePlugIn_SYSTEM_INCLUDE_DIRECTORIES
+ ${X11_INCLUDE_DIR}
+)
+
+include_directories(${WebKitTestNetscapePlugIn_INCLUDE_DIRECTORIES})
+include_directories(SYSTEM ${WebKitTestNetscapePlugIn_SYSTEM_INCLUDE_DIRECTORIES})
+
+set(WebKitTestNetscapePlugIn_LIBRARIES
+ ${X11_LIBRARIES}
+)
+
+if (WTF_OS_UNIX)
+ add_definitions(-DXP_UNIX)
+endif ()
+
+add_library(TestNetscapePlugIn SHARED ${WebKitTestNetscapePlugIn_SOURCES})
+target_link_libraries(TestNetscapePlugIn ${WebKitTestNetscapePlugIn_LIBRARIES})
+set_target_properties(TestNetscapePlugIn PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/plugins)
+WEBKIT_SET_EXTRA_COMPILER_FLAGS(TestNetscapePlugIn)
+
+# Suppress unused parameter warnings for sources in WebKit2.
+ADD_TARGET_PROPERTIES(TestNetscapePlugIn COMPILE_FLAGS "-Wno-unused-parameter")
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npapi.h b/Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npapi.h
index 627bc97a9..627bc97a9 100644
--- a/Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npapi.h
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npapi.h
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npfunctions.h b/Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npfunctions.h
index 54a603dbb..54a603dbb 100644
--- a/Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npfunctions.h
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npfunctions.h
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npruntime.h b/Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npruntime.h
index e435ae2ab..e435ae2ab 100644
--- a/Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npruntime.h
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npruntime.h
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp
index 75631842f..982452b68 100644
--- a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp
@@ -30,10 +30,14 @@
#include "PluginTest.h"
#include "TestObject.h"
#include <assert.h>
+#include <memory>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <wtf/Platform.h>
+#include <wtf/ExportMacros.h>
+#include <wtf/Assertions.h>
// Helper function which takes in the plugin window object for logging to the console object.
static void pluginLogWithWindowObject(NPObject* windowObject, NPP instance, const char* message)
@@ -60,6 +64,7 @@ static void pluginLogWithWindowObject(NPObject* windowObject, NPP instance, cons
browser->releaseobject(consoleObject);
}
+WTF_ATTRIBUTE_PRINTF(2, 0)
void pluginLogWithArguments(NPP instance, const char* format, va_list args)
{
const size_t messageBufferSize = 2048;
@@ -80,6 +85,7 @@ void pluginLogWithArguments(NPP instance, const char* format, va_list args)
}
// Helper function to log to the console object.
+WTF_ATTRIBUTE_PRINTF(2, 3)
void pluginLog(NPP instance, const char* format, ...)
{
va_list args;
@@ -770,11 +776,15 @@ static bool testGetPropertyReturnValue(PluginObject* obj, const NPVariant* args,
return true;
}
-static char* toCString(const NPString& string)
+static std::unique_ptr<char[]> toCString(const NPString& string)
{
- char* result = static_cast<char*>(malloc(string.UTF8Length + 1));
- memcpy(result, string.UTF8Characters, string.UTF8Length);
- result[string.UTF8Length] = '\0';
+ size_t length = string.UTF8Length;
+ std::unique_ptr<char[]> result(new char[length + 1]);
+ if (!result)
+ return result;
+
+ memcpy(result.get(), string.UTF8Characters, length);
+ result[length] = '\0';
return result;
}
@@ -785,30 +795,27 @@ static bool testPostURLFile(PluginObject* obj, const NPVariant* args, uint32_t a
return false;
NPString urlString = NPVARIANT_TO_STRING(args[0]);
- char* url = toCString(urlString);
+ auto url = toCString(urlString);
NPString targetString = NPVARIANT_TO_STRING(args[1]);
- char* target = toCString(targetString);
+ auto target = toCString(targetString);
NPString pathString = NPVARIANT_TO_STRING(args[2]);
- char* path = toCString(pathString);
+ auto path = toCString(pathString);
NPString contentsString = NPVARIANT_TO_STRING(args[3]);
- FILE* tempFile = fopen(path, "w");
+ FILE* tempFile = fopen(path.get(), "w");
if (!tempFile)
return false;
- if (!fwrite(contentsString.UTF8Characters, contentsString.UTF8Length, 1, tempFile))
- return false;
-
+ size_t count = fwrite(contentsString.UTF8Characters, contentsString.UTF8Length, 1, tempFile);
fclose(tempFile);
- NPError error = browser->posturl(obj->npp, url, target, pathString.UTF8Length, path, TRUE);
+ if (!count)
+ return false;
- free(path);
- free(target);
- free(url);
+ NPError error = browser->posturl(obj->npp, url.get(), target.get(), pathString.UTF8Length, path.get(), TRUE);
BOOLEAN_TO_NPVARIANT(error == NPERR_NO_ERROR, *result);
return true;
@@ -967,15 +974,14 @@ bool testWindowOpen(NPP npp)
static bool testSetStatus(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
- char* message = 0;
+ std::unique_ptr<char[]> message;
if (argCount && NPVARIANT_IS_STRING(args[0])) {
NPString statusString = NPVARIANT_TO_STRING(args[0]);
message = toCString(statusString);
}
-
- browser->status(obj->npp, message);
- free(message);
+ browser->status(obj->npp, message.get());
+
return true;
}
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp
index c2195c5b1..da78148d4 100644
--- a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp
@@ -28,6 +28,9 @@
#include "PluginObject.h"
#include <assert.h>
#include <string.h>
+#include <wtf/Platform.h>
+#include <wtf/ExportMacros.h>
+#include <wtf/Assertions.h>
#if defined(XP_UNIX) || defined(ANDROID)
#include <unistd.h>
@@ -133,6 +136,11 @@ bool PluginTest::NPP_URLNotify(const char* url, NPReason, void* notifyData)
return false;
}
+void PluginTest::NPP_URLRedirectNotify(const char*, int32_t, void* notifyData)
+{
+ NPN_URLRedirectResponse(notifyData, true);
+}
+
NPError PluginTest::NPP_GetValue(NPPVariable variable, void *value)
{
// We don't know anything about plug-in values so just return NPERR_GENERIC_ERROR.
@@ -156,6 +164,11 @@ NPError PluginTest::NPN_GetURLNotify(const char *url, const char *target, void *
return browser->geturlnotify(m_npp, url, target, notifyData);
}
+NPError PluginTest::NPN_PostURLNotify(const char *url, const char *target, uint32_t len, const char* buf, NPBool file, void *notifyData)
+{
+ return browser->posturlnotify(m_npp, url, target, len, buf, file, notifyData);
+}
+
NPError PluginTest::NPN_GetValue(NPNVariable variable, void* value)
{
return browser->getvalue(m_npp, variable, value);
@@ -228,6 +241,11 @@ void PluginTest::NPN_ReleaseVariantValue(NPVariant* variant)
browser->releasevariantvalue(variant);
}
+void PluginTest::NPN_URLRedirectResponse(void* notifyData, NPBool allow)
+{
+ browser->urlredirectresponse(m_npp, notifyData, allow);
+}
+
#ifdef XP_MACOSX
bool PluginTest::NPN_ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace)
{
@@ -254,6 +272,7 @@ void PluginTest::executeScript(const char* script)
browser->releasevariantvalue(&browserResult);
}
+WTF_ATTRIBUTE_PRINTF(2, 3)
void PluginTest::log(const char* format, ...)
{
va_list args;
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h
index f8a9aaee3..d7a5163ff 100644
--- a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h
@@ -31,6 +31,10 @@
#include <map>
#include <string>
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#define snprintf _snprintf
+#endif
+
// Helper classes for implementing has_member
typedef char (&no_tag)[1];
typedef char (&yes_tag)[2];
@@ -68,12 +72,14 @@ public:
virtual int16_t NPP_HandleEvent(void* event);
virtual bool NPP_URLNotify(const char* url, NPReason, void* notifyData);
+ virtual void NPP_URLRedirectNotify(const char* url, int32_t status, void* notifyData);
virtual NPError NPP_GetValue(NPPVariable, void* value);
virtual NPError NPP_SetValue(NPNVariable, void *value);
// NPN functions.
NPError NPN_GetURL(const char* url, const char* target);
NPError NPN_GetURLNotify(const char* url, const char* target, void* notifyData);
+ NPError NPN_PostURLNotify(const char *url, const char *target, uint32_t len, const char* buf, NPBool file, void *notifyData);
NPError NPN_GetValue(NPNVariable, void* value);
void NPN_InvalidateRect(NPRect* invalidRect);
bool NPN_Invoke(NPObject *, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result);
@@ -91,6 +97,7 @@ public:
void NPN_ReleaseObject(NPObject*);
bool NPN_RemoveProperty(NPObject*, NPIdentifier propertyName);
void NPN_ReleaseVariantValue(NPVariant*);
+ void NPN_URLRedirectResponse(void* notifyData, NPBool allow);
#ifdef XP_MACOSX
bool NPN_ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSWithinNPP_New.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSWithinNPP_New.cpp
new file mode 100644
index 000000000..c066db59f
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSWithinNPP_New.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "PluginTest.h"
+
+#include "PluginObject.h"
+
+using namespace std;
+
+// Executing JS within NPP_New when initializing asynchronously should not be able to deadlock with the WebProcess
+
+class EvaluteJSWithinNPP_New : public PluginTest {
+public:
+ EvaluteJSWithinNPP_New(NPP, const string& identifier);
+
+private:
+ virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData *);
+
+};
+
+EvaluteJSWithinNPP_New::EvaluteJSWithinNPP_New(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+{
+}
+
+NPError EvaluteJSWithinNPP_New::NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData *saved)
+{
+ // Give the WebProcess enough time to be deadlocked waiting for the PluginProcess.
+ usleep(15000);
+ executeScript("var theLocation = window.location;");
+ return NPERR_NO_ERROR;
+}
+
+static PluginTest::Register<EvaluteJSWithinNPP_New> registrar("evalute-js-within-npp-new");
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/InvokeDestroysPluginWithinNPP_New.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/InvokeDestroysPluginWithinNPP_New.cpp
new file mode 100644
index 000000000..0e2dbdce7
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/InvokeDestroysPluginWithinNPP_New.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "PluginTest.h"
+
+#include "PluginObject.h"
+
+using namespace std;
+
+// Executing JS within NPP_New when initializing asynchronously should not be able to deadlock with the WebProcess
+
+class InvokeDestroysPluginWithinNPP_New : public PluginTest {
+public:
+ InvokeDestroysPluginWithinNPP_New(NPP, const string& identifier);
+
+private:
+ virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData *);
+
+};
+
+InvokeDestroysPluginWithinNPP_New::InvokeDestroysPluginWithinNPP_New(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+{
+}
+
+NPError InvokeDestroysPluginWithinNPP_New::NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData *saved)
+{
+ // Give the WebProcess enough time to be deadlocked waiting for the PluginProcess if things aren't working correctly.
+ usleep(15000);
+
+ NPObject* windowObject = 0;
+ if (NPN_GetValue(NPNVWindowNPObject, &windowObject) != NPERR_NO_ERROR)
+ return NPERR_GENERIC_ERROR;
+
+ if (!windowObject)
+ return NPERR_GENERIC_ERROR;
+
+ NPVariant result;
+ if (!NPN_Invoke(windowObject, NPN_GetStringIdentifier("removePluginElement"), 0, 0, &result))
+ return NPERR_GENERIC_ERROR;
+
+ return NPERR_NO_ERROR;
+}
+
+static PluginTest::Register<InvokeDestroysPluginWithinNPP_New> registrar("invoke-destroys-plugin-within-npp-new");
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PluginScriptableObjectOverridesAllProperties.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PluginScriptableObjectOverridesAllProperties.cpp
new file mode 100644
index 000000000..ca399a816
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PluginScriptableObjectOverridesAllProperties.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "PluginTest.h"
+
+#include <string.h>
+
+using namespace std;
+
+class PluginScriptableObjectOverridesAllProperties : public PluginTest {
+public:
+ PluginScriptableObjectOverridesAllProperties(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ {
+ }
+
+private:
+ class PluginObject : public Object<PluginObject> {
+ public:
+ PluginObject()
+ {
+ }
+
+ ~PluginObject()
+ {
+ }
+
+ bool hasProperty(NPIdentifier propertyName)
+ {
+ return true;
+ }
+
+ bool getProperty(NPIdentifier propertyName, NPVariant* result)
+ {
+ static const char* message = "My name is ";
+ char* propertyString = pluginTest()->NPN_UTF8FromIdentifier(propertyName);
+
+ int bufferLength = strlen(propertyString) + strlen(message) + 1;
+ char* resultBuffer = static_cast<char*>(pluginTest()->NPN_MemAlloc(bufferLength));
+ snprintf(resultBuffer, bufferLength, "%s%s", message, propertyString);
+
+ STRINGZ_TO_NPVARIANT(resultBuffer, *result);
+
+ return true;
+ }
+ };
+
+ virtual NPError NPP_GetValue(NPPVariable variable, void *value)
+ {
+ if (variable != NPPVpluginScriptableNPObject)
+ return NPERR_GENERIC_ERROR;
+
+ *(NPObject**)value = PluginObject::create(this);
+
+ return NPERR_NO_ERROR;
+ }
+
+};
+
+static PluginTest::Register<PluginScriptableObjectOverridesAllProperties> pluginScriptableObjectOverridesAllProperties("plugin-scriptable-object-overrides-all-properties");
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/SlowNPPNew.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/SlowNPPNew.cpp
new file mode 100644
index 000000000..8c80d55a5
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/SlowNPPNew.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "PluginTest.h"
+
+#include <string.h>
+
+using namespace std;
+
+class SlowNPPNew : public PluginTest {
+public:
+ SlowNPPNew(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ {
+ }
+
+private:
+ class PluginObject : public Object<PluginObject> {
+ public:
+ PluginObject()
+ {
+ }
+
+ ~PluginObject()
+ {
+ }
+
+ bool hasProperty(NPIdentifier propertyName)
+ {
+ return true;
+ }
+
+ bool getProperty(NPIdentifier propertyName, NPVariant* result)
+ {
+ static const char* message = "My name is ";
+ char* propertyString = pluginTest()->NPN_UTF8FromIdentifier(propertyName);
+
+ int bufferLength = strlen(propertyString) + strlen(message) + 1;
+ char* resultBuffer = static_cast<char*>(pluginTest()->NPN_MemAlloc(bufferLength));
+ snprintf(resultBuffer, bufferLength, "%s%s", message, propertyString);
+
+ STRINGZ_TO_NPVARIANT(resultBuffer, *result);
+
+ return true;
+ }
+ };
+
+ virtual NPError NPP_GetValue(NPPVariable variable, void *value)
+ {
+ if (variable != NPPVpluginScriptableNPObject)
+ return NPERR_GENERIC_ERROR;
+
+ *(NPObject**)value = PluginObject::create(this);
+
+ return NPERR_NO_ERROR;
+ }
+
+ virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData *saved)
+ {
+ usleep(550000);
+ return NPERR_NO_ERROR;
+ }
+};
+
+static PluginTest::Register<SlowNPPNew> slowNPPNew("slow-npp-new");
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/URLRedirect.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/URLRedirect.cpp
new file mode 100644
index 000000000..b834703da
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/URLRedirect.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "PluginTest.h"
+
+#include <string.h>
+
+using namespace std;
+
+class URLRedirect : public PluginTest {
+public:
+ URLRedirect(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ {
+ }
+
+ struct Redirect {
+ int redirectsRemaining;
+ bool async;
+ bool hasFired;
+ };
+
+ std::map<void*, Redirect> redirects;
+
+private:
+ // This is the test object.
+ class TestObject : public Object<TestObject> { };
+
+ // This is the scriptable object. It has a single "testObject" property and an "evaluate" function.
+ class ScriptableObject : public Object<ScriptableObject> {
+ public:
+ bool hasMethod(NPIdentifier methodName)
+ {
+ return identifierIs(methodName, "get") || identifierIs(methodName, "getAsync") || identifierIs(methodName, "serviceAsync");
+ }
+
+ bool get(const NPVariant* args, uint32_t argCount, NPVariant* result, bool async)
+ {
+ if (argCount != 3 || !NPVARIANT_IS_STRING(args[0]) || !(NPVARIANT_IS_BOOLEAN(args[1]) || NPVARIANT_IS_DOUBLE(args[1]) || NPVARIANT_IS_INT32(args[1])) || !NPVARIANT_IS_STRING(args[2]))
+ return false;
+
+ const NPString* notifyString = &NPVARIANT_TO_STRING(args[2]);
+ basic_string<NPUTF8> notify(notifyString->UTF8Characters, notifyString->UTF8Length);
+ NPIdentifier notifyMethod = pluginTest()->NPN_GetStringIdentifier(notify.c_str());
+
+ Redirect& redirect = static_cast<URLRedirect*>(pluginTest())->redirects[reinterpret_cast<void*>(notifyMethod)];
+ if (NPVARIANT_IS_DOUBLE(args[1]))
+ redirect.redirectsRemaining = NPVARIANT_TO_DOUBLE(args[1]);
+ else if (NPVARIANT_IS_INT32(args[1]))
+ redirect.redirectsRemaining = NPVARIANT_TO_INT32(args[1]);
+ else if (NPVARIANT_IS_BOOLEAN(args[1]))
+ redirect.redirectsRemaining = NPVARIANT_TO_BOOLEAN(args[1]);
+ redirect.async = async;
+ redirect.hasFired = true;
+
+ const NPString* urlString = &NPVARIANT_TO_STRING(args[0]);
+ basic_string<NPUTF8> url(urlString->UTF8Characters, urlString->UTF8Length);
+
+ pluginTest()->NPN_GetURLNotify(url.c_str(), 0, reinterpret_cast<void*>(notifyMethod));
+
+ VOID_TO_NPVARIANT(*result);
+ return true;
+ }
+
+ bool serviceAsync(const NPVariant* args, uint32_t argCount, NPVariant* result)
+ {
+ if (argCount)
+ return false;
+
+ NPBool seen = 0;
+ URLRedirect* plugin = static_cast<URLRedirect*>(pluginTest());
+ for (auto& redirect : plugin->redirects) {
+ if (redirect.second.hasFired)
+ continue;
+ redirect.second.hasFired = true;
+ plugin->NPN_URLRedirectResponse(redirect.first, redirect.second.redirectsRemaining);
+ if (redirect.second.redirectsRemaining)
+ --redirect.second.redirectsRemaining;
+ seen = 1;
+ }
+
+ BOOLEAN_TO_NPVARIANT(seen, *result);
+ return true;
+ }
+
+ bool invoke(NPIdentifier methodName, const NPVariant* args, uint32_t argCount, NPVariant* result)
+ {
+ if (identifierIs(methodName, "get"))
+ return get(args, argCount, result, false);
+
+ if (identifierIs(methodName, "getAsync"))
+ return get(args, argCount, result, true);
+
+ if (identifierIs(methodName, "serviceAsync"))
+ return serviceAsync(args, argCount, result);
+
+ return false;
+ }
+ };
+
+ virtual NPError NPP_GetValue(NPPVariable variable, void *value)
+ {
+ if (variable != NPPVpluginScriptableNPObject)
+ return NPERR_GENERIC_ERROR;
+
+ *(NPObject**)value = ScriptableObject::create(this);
+
+ return NPERR_NO_ERROR;
+ }
+
+ virtual bool NPP_URLNotify(const char* url, NPReason reason, void* notifyData)
+ {
+ NPVariant args[2];
+
+ NPObject* windowScriptObject;
+ NPN_GetValue(NPNVWindowNPObject, &windowScriptObject);
+
+ NPIdentifier callbackIdentifier = notifyData;
+
+ INT32_TO_NPVARIANT(reason, args[0]);
+ STRINGZ_TO_NPVARIANT(url, args[1]);
+
+ NPVariant browserResult;
+ if (NPN_Invoke(windowScriptObject, callbackIdentifier, args, 2, &browserResult))
+ NPN_ReleaseVariantValue(&browserResult);
+
+ return true;
+ }
+
+ virtual void NPP_URLRedirectNotify(const char*, int32_t, void* notifyData)
+ {
+ Redirect& redirect = redirects[notifyData];
+ if (redirect.async) {
+ redirect.hasFired = false;
+ return;
+ }
+
+ NPN_URLRedirectResponse(notifyData, redirect.redirectsRemaining);
+ if (redirect.redirectsRemaining)
+ --redirect.redirectsRemaining;
+ }
+};
+
+static PluginTest::Register<URLRedirect> urlRedirect("url-redirect");
+
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp
index 85cd41d2c..ca9cec8ef 100644
--- a/Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp
@@ -41,10 +41,17 @@ extern "C" void GlobalToLocal(Point*);
using namespace std;
+#if defined(__GNUC__)
+#define CRASH() do { \
+ *(int *)(uintptr_t)0xbbadbeef = 0; \
+ __builtin_trap(); /* More reliable, but doesn't say BBADBEEF. */ \
+} while (false)
+#else
#define CRASH() do { \
*(int *)(uintptr_t)0xbbadbeef = 0; \
((void(*)())0)(); /* More reliable, but doesn't say BBADBEEF */ \
-} while(false)
+} while (false)
+#endif
static bool getEntryPointsWasCalled;
static bool initializeWasCalled;
@@ -116,6 +123,7 @@ NPError STDCALL NP_GetEntryPoints(NPPluginFuncs *pluginFuncs)
pluginFuncs->print = NPP_Print;
pluginFuncs->event = NPP_HandleEvent;
pluginFuncs->urlnotify = NPP_URLNotify;
+ pluginFuncs->urlredirectnotify = NPP_URLRedirectNotify;
pluginFuncs->getvalue = NPP_GetValue;
pluginFuncs->setvalue = NPP_SetValue;
@@ -256,6 +264,8 @@ NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc
#endif
} else if (!strcasecmp(argn[i], "src") && strstr(argv[i], "plugin-document-has-focus.pl"))
obj->testKeyboardFocusForPlugins = TRUE;
+ else if (!strcasecmp(argn[i], "src") && strstr(argv[i], "plugin-document-alert-and-notify-done.pl"))
+ executeScript(obj, "alert('Plugin Loaded!'); testRunner.notifyDone();");
else if (!strcasecmp(argn[i], "evaluatescript")) {
char* script = argv[i];
if (script == strstr(script, "mouse::")) {
@@ -348,29 +358,30 @@ NPError NPP_SetWindow(NPP instance, NPWindow *window)
{
PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
- if (obj) {
- obj->lastWindow = *window;
+ if (!obj)
+ return NPERR_GENERIC_ERROR;
- if (obj->logSetWindow) {
- pluginLog(instance, "NPP_SetWindow: %d %d", (int)window->width, (int)window->height);
- obj->logSetWindow = FALSE;
- executeScript(obj, "testRunner.notifyDone();");
- }
+ obj->lastWindow = *window;
- if (obj->onSetWindow)
- executeScript(obj, obj->onSetWindow);
+ if (obj->logSetWindow) {
+ pluginLog(instance, "NPP_SetWindow: %d %d", (int)window->width, (int)window->height);
+ obj->logSetWindow = FALSE;
+ executeScript(obj, "testRunner.notifyDone();");
+ }
- if (obj->testWindowOpen) {
- testWindowOpen(instance);
- obj->testWindowOpen = FALSE;
- }
+ if (obj->onSetWindow)
+ executeScript(obj, obj->onSetWindow);
- if (obj->testKeyboardFocusForPlugins) {
- obj->eventLogging = true;
- executeScript(obj, "eventSender.keyDown('A');");
- }
+ if (obj->testWindowOpen) {
+ testWindowOpen(instance);
+ obj->testWindowOpen = FALSE;
}
-
+
+ if (obj->testKeyboardFocusForPlugins) {
+ obj->eventLogging = true;
+ executeScript(obj, "eventSender.keyDown('A');");
+ }
+
return obj->pluginTest->NPP_SetWindow(window);
}
@@ -799,6 +810,12 @@ void NPP_URLNotify(NPP instance, const char *url, NPReason reason, void *notifyD
handleCallback(obj, url, reason, notifyData);
}
+void NPP_URLRedirectNotify(NPP instance, const char *url, int32_t status, void *notifyData)
+{
+ PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+ obj->pluginTest->NPP_URLRedirectNotify(url, status, notifyData);
+}
+
NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value)
{
#ifdef XP_UNIX
diff --git a/Tools/DumpRenderTree/TestOptions.h b/Tools/DumpRenderTree/TestOptions.h
new file mode 100644
index 000000000..0aeb02210
--- /dev/null
+++ b/Tools/DumpRenderTree/TestOptions.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+#include "DumpRenderTree.h"
+
+@class NSURL;
+
+struct TestOptions {
+ bool enableIntersectionObserver { false };
+ bool enableModernMediaControls { true };
+ bool enablePointerLock { false };
+
+ TestOptions(NSURL*, const TestCommand&);
+};
diff --git a/Tools/DumpRenderTree/TestRunner.cpp b/Tools/DumpRenderTree/TestRunner.cpp
index 7b249770e..46b8df45e 100644
--- a/Tools/DumpRenderTree/TestRunner.cpp
+++ b/Tools/DumpRenderTree/TestRunner.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008, 2009, 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2007-2016 Apple Inc. All rights reserved.
* Copyright (C) 2010 Joone Hur <joone@kldp.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -11,7 +11,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -30,36 +30,50 @@
#include "config.h"
#include "TestRunner.h"
+#include "WebCoreTestSupport.h"
#include "WorkQueue.h"
#include "WorkQueueItem.h"
#include <JavaScriptCore/APICast.h>
-#include <JavaScriptCore/JSContextRef.h>
+#include <JavaScriptCore/ArrayBufferView.h>
+#include <JavaScriptCore/HeapInlines.h>
+#include <JavaScriptCore/JSArrayBufferView.h>
#include <JavaScriptCore/JSCTestRunnerUtils.h>
+#include <JavaScriptCore/JSContextRef.h>
#include <JavaScriptCore/JSObjectRef.h>
#include <JavaScriptCore/JSRetainPtr.h>
+#include <JavaScriptCore/TypedArrayInlines.h>
+#include <JavaScriptCore/VMInlines.h>
+#include <WebCore/LogInitialization.h>
#include <cstring>
#include <locale.h>
-#include <runtime/ArrayBufferView.h>
-#include <runtime/JSArrayBufferView.h>
-#include <runtime/TypedArrayInlines.h>
#include <stdio.h>
#include <wtf/Assertions.h>
#include <wtf/CurrentTime.h>
+#include <wtf/LoggingAccumulator.h>
#include <wtf/MathExtras.h>
#include <wtf/RefPtr.h>
+#include <wtf/RunLoop.h>
#include <wtf/StdLibExtras.h>
+#include <wtf/text/WTFString.h>
+
+#if PLATFORM(IOS)
+#include <WebCore/WebCoreThreadRun.h>
+#include <wtf/BlockPtr.h>
+#endif
#if PLATFORM(MAC) && !PLATFORM(IOS)
#include <Carbon/Carbon.h>
#endif
+FILE* testResult = stdout;
+
const unsigned TestRunner::viewWidth = 800;
const unsigned TestRunner::viewHeight = 600;
const unsigned TestRunner::w3cSVGViewWidth = 480;
const unsigned TestRunner::w3cSVGViewHeight = 360;
-TestRunner::TestRunner(const std::string& testPathOrURL, const std::string& expectedPixelHash)
+TestRunner::TestRunner(const std::string& testURL, const std::string& expectedPixelHash)
: m_disallowIncreaseForApplicationCacheQuota(false)
, m_dumpApplicationCacheDelegateCallbacks(false)
, m_dumpAsAudio(false)
@@ -81,7 +95,6 @@ TestRunner::TestRunner(const std::string& testPathOrURL, const std::string& expe
, m_dumpSourceAsWebArchive(false)
, m_dumpStatusCallbacks(false)
, m_dumpTitleChanges(false)
- , m_dumpIconChanges(false)
, m_dumpVisitedLinksCallback(false)
, m_dumpWillCacheResponse(false)
, m_generatePixelResults(true)
@@ -101,9 +114,9 @@ TestRunner::TestRunner(const std::string& testPathOrURL, const std::string& expe
, m_globalFlag(false)
, m_isGeolocationPermissionSet(false)
, m_geolocationPermission(false)
+ , m_rejectsProtectionSpaceAndContinueForAuthenticationChallenges(false)
, m_handlesAuthenticationChallenges(false)
, m_isPrinting(false)
- , m_deferMainResourceDataLoad(true)
, m_useDeferredFrameLoading(false)
, m_shouldPaintBrokenImage(true)
, m_shouldStayOnPageAfterHandlingBeforeUnload(false)
@@ -112,15 +125,16 @@ TestRunner::TestRunner(const std::string& testPathOrURL, const std::string& expe
, m_hasPendingWebNotificationClick(false)
, m_databaseDefaultQuota(-1)
, m_databaseMaxQuota(-1)
- , m_testPathOrURL(testPathOrURL)
+ , m_testURL(testURL)
, m_expectedPixelHash(expectedPixelHash)
, m_titleTextDirection("ltr")
+ , m_timeout(0)
{
}
-PassRefPtr<TestRunner> TestRunner::create(const std::string& testPathOrURL, const std::string& expectedPixelHash)
+Ref<TestRunner> TestRunner::create(const std::string& testURL, const std::string& expectedPixelHash)
{
- return adoptRef(new TestRunner(testPathOrURL, expectedPixelHash));
+ return adoptRef(*new TestRunner(testURL, expectedPixelHash));
}
// Static Functions
@@ -262,13 +276,6 @@ static JSValueRef dumpTitleChangesCallback(JSContextRef context, JSObjectRef fun
return JSValueMakeUndefined(context);
}
-static JSValueRef dumpIconChangesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
- controller->setDumpIconChanges(true);
- return JSValueMakeUndefined(context);
-}
-
static JSValueRef dumpWillCacheResponseCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
@@ -340,9 +347,12 @@ static JSValueRef setAudioResultCallback(JSContextRef context, JSObjectRef funct
return JSValueMakeUndefined(context);
// FIXME (123058): Use a JSC API to get buffer contents once such is exposed.
- JSC::JSArrayBufferView* jsBufferView = JSC::jsDynamicCast<JSC::JSArrayBufferView*>(toJS(toJS(context), arguments[0]));
+ JSC::VM& vm = toJS(context)->vm();
+ JSC::JSLockHolder lock(vm);
+
+ JSC::JSArrayBufferView* jsBufferView = JSC::jsDynamicCast<JSC::JSArrayBufferView*>(vm, toJS(toJS(context), arguments[0]));
ASSERT(jsBufferView);
- RefPtr<JSC::ArrayBufferView> bufferView = jsBufferView->impl();
+ RefPtr<JSC::ArrayBufferView> bufferView = jsBufferView->unsharedImpl();
const char* buffer = static_cast<const char*>(bufferView->baseAddress());
std::vector<char> audioData(buffer, buffer + bufferView->byteLength());
@@ -466,73 +476,6 @@ static JSValueRef clearAllDatabasesCallback(JSContextRef context, JSObjectRef fu
return JSValueMakeUndefined(context);
}
-static JSValueRef syncLocalStorageCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
-
- controller->syncLocalStorage();
-
- return JSValueMakeUndefined(context);
-}
-
-static JSValueRef observeStorageTrackerNotificationsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
-
- if (argumentCount < 1)
- return JSValueMakeUndefined(context);
-
- unsigned numNotifications = JSValueToNumber(context, arguments[0], exception);
-
- ASSERT(!*exception);
-
- controller->observeStorageTrackerNotifications(numNotifications);
-
- return JSValueMakeUndefined(context);
-}
-
-static JSValueRef deleteAllLocalStorageCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
- controller->deleteAllLocalStorage();
-
- return JSValueMakeUndefined(context);
-}
-
-static JSValueRef deleteLocalStorageForOriginCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
-
- if (argumentCount < 1)
- return JSValueMakeUndefined(context);
-
- JSRetainPtr<JSStringRef> url(Adopt, JSValueToStringCopy(context, arguments[0], exception));
- ASSERT(!*exception);
-
- controller->deleteLocalStorageForOrigin(url.get());
-
- return JSValueMakeUndefined(context);
-}
-
-static JSValueRef localStorageDiskUsageForOriginCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
-
- if (argumentCount < 1)
- return JSValueMakeUndefined(context);
-
- JSRetainPtr<JSStringRef> originURL(Adopt, JSValueToStringCopy(context, arguments[0], exception));
- ASSERT(!*exception);
-
- return JSValueMakeNumber(context, controller->localStorageDiskUsageForOrigin(originURL.get()));
-}
-
-static JSValueRef originsWithLocalStorageCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
- return controller->originsWithLocalStorage(context);
-}
-
static JSValueRef clearBackForwardListCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
// Has mac & windows implementation
@@ -712,6 +655,12 @@ static JSValueRef numberOfPendingGeolocationPermissionRequestsCallback(JSContext
return JSValueMakeNumber(context, controller->numberOfPendingGeolocationPermissionRequests());
}
+static JSValueRef isGeolocationProviderActiveCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
+ return JSValueMakeBoolean(context, controller->isGeolocationProviderActive());
+}
+
static JSValueRef queueBackNavigationCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
// Has mac & windows implementation
@@ -977,18 +926,6 @@ static JSValueRef setDatabaseQuotaCallback(JSContextRef context, JSObjectRef fun
return JSValueMakeUndefined(context);
}
-static JSValueRef setDeferMainResourceDataLoadCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- // Has Mac and Windows implementation
- if (argumentCount < 1)
- return JSValueMakeUndefined(context);
-
- TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
- controller->setDeferMainResourceDataLoad(JSValueToBoolean(context, arguments[0]));
-
- return JSValueMakeUndefined(context);
-}
-
static JSValueRef setDefersLoadingCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
if (argumentCount < 1)
@@ -1104,38 +1041,6 @@ static JSValueRef setMockGeolocationPositionUnavailableErrorCallback(JSContextRe
return JSValueMakeUndefined(context);
}
-static JSValueRef addMockSpeechInputResultCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- if (argumentCount < 3)
- return JSValueMakeUndefined(context);
-
- JSRetainPtr<JSStringRef> result(Adopt, JSValueToStringCopy(context, arguments[0], exception));
- ASSERT(!*exception);
-
- double confidence = JSValueToNumber(context, arguments[1], exception);
-
- JSRetainPtr<JSStringRef> language(Adopt, JSValueToStringCopy(context, arguments[2], exception));
- ASSERT(!*exception);
-
- TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
- controller->addMockSpeechInputResult(result.get(), confidence, language.get());
-
- return JSValueMakeUndefined(context);
-}
-
-static JSValueRef setMockSpeechInputDumpRectCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- if (argumentCount < 1)
- return JSValueMakeUndefined(context);
-
- bool dumpRect = JSValueToBoolean(context, arguments[0]);
-
- TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
- controller->setMockSpeechInputDumpRect(dumpRect);
-
- return JSValueMakeUndefined(context);
-}
-
static JSValueRef setNewWindowsCopyBackForwardListCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
// Has mac implementation
@@ -1160,6 +1065,18 @@ static JSValueRef setGeolocationPermissionCallback(JSContextRef context, JSObjec
return JSValueMakeUndefined(context);
}
+static JSValueRef setRejectsProtectionSpaceAndContinueForAuthenticationChallengesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
+ controller->setRejectsProtectionSpaceAndContinueForAuthenticationChallenges(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
static JSValueRef setHandlesAuthenticationChallengesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
// Has mac & windows implementation
@@ -1279,6 +1196,15 @@ static JSValueRef setPrintingCallback(JSContextRef context, JSObjectRef function
return JSValueMakeUndefined(context);
}
+static JSValueRef setAllowsAnySSLCertificateCallback(JSContextRef context, JSObjectRef, JSObjectRef, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ bool allowAnyCertificate = false;
+ if (argumentCount == 1)
+ allowAnyCertificate = JSValueToBoolean(context, arguments[0]);
+
+ TestRunner::setAllowsAnySSLCertificate(allowAnyCertificate);
+ return JSValueMakeUndefined(context);
+}
static JSValueRef setAllowUniversalAccessFromFileURLsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
@@ -1304,6 +1230,18 @@ static JSValueRef setAllowFileAccessFromFileURLsCallback(JSContextRef context, J
return JSValueMakeUndefined(context);
}
+static JSValueRef setNeedsStorageAccessFromFileURLsQuirkCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
+ controller->setNeedsStorageAccessFromFileURLsQuirk(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
static JSValueRef setTabKeyCyclesThroughElementsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
// Has mac & windows implementation
@@ -1340,19 +1278,6 @@ static JSValueRef setPagePausedCallback(JSContextRef context, JSObjectRef functi
}
#endif
-#if ENABLE(IOS_TEXT_AUTOSIZING)
-static JSValueRef setTextAutosizingEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- if (argumentCount < 1)
- return JSValueMakeUndefined(context);
-
- TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
- controller->setTextAutosizingEnabled(JSValueToBoolean(context, arguments[0]));
-
- return JSValueMakeUndefined(context);
-}
-#endif
-
static JSValueRef setUseDashboardCompatibilityModeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
// Has mac implementation
@@ -1477,6 +1402,22 @@ static JSValueRef setWindowIsKeyCallback(JSContextRef context, JSObjectRef funct
return JSValueMakeUndefined(context);
}
+static JSValueRef setViewSizeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 2)
+ return JSValueMakeUndefined(context);
+
+ double width = JSValueToNumber(context, arguments[0], exception);
+ ASSERT(!*exception);
+ double height = JSValueToNumber(context, arguments[1], exception);
+ ASSERT(!*exception);
+
+ TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
+ controller->setViewSize(width, height);
+
+ return JSValueMakeUndefined(context);
+}
+
static JSValueRef waitUntilDoneCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
// Has mac & windows implementation
@@ -1579,12 +1520,10 @@ static JSValueRef closeWebInspectorCallback(JSContextRef context, JSObjectRef fu
static JSValueRef evaluateInWebInspectorCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
- double callId = JSValueToNumber(context, arguments[0], exception);
- ASSERT(!*exception);
- JSRetainPtr<JSStringRef> script(Adopt, JSValueToStringCopy(context, arguments[1], exception));
+ JSRetainPtr<JSStringRef> script(Adopt, JSValueToStringCopy(context, arguments[0], exception));
ASSERT(!*exception);
- controller->evaluateInWebInspector(static_cast<long>(callId), script.get());
+ controller->evaluateInWebInspector(script.get());
return JSValueMakeUndefined(context);
}
@@ -1842,8 +1781,31 @@ static JSValueRef preciseTimeCallback(JSContextRef context, JSObjectRef, JSObjec
return JSValueMakeNumber(context, WTF::currentTime());
}
+static JSValueRef imageCountInGeneralPasteboardCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
+
+ return JSValueMakeNumber(context, controller->imageCountInGeneralPasteboard());
+}
+
+static JSValueRef setSpellCheckerLoggingEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+ TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
+ controller->setSpellCheckerLoggingEnabled(JSValueToBoolean(context, arguments[0]));
+ return JSValueMakeUndefined(context);
+}
+
// Static Values
+static JSValueRef getTimeoutCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
+ return JSValueMakeNumber(context, controller->timeout());
+}
+
static JSValueRef getGlobalFlagCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
{
TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
@@ -1884,6 +1846,13 @@ static JSValueRef getTitleTextDirectionCallback(JSContextRef context, JSObjectRe
return JSValueMakeString(context, titleDirection.get());
}
+static JSValueRef getInspectorTestStubURLCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
+ JSRetainPtr<JSStringRef> url(Adopt, controller->inspectorTestStubURL());
+ return JSValueMakeString(context, url.get());
+}
+
static bool setGlobalFlagCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
{
TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
@@ -2020,11 +1989,16 @@ static JSValueRef simulateWebNotificationClickCallback(JSContextRef context, JSO
return JSValueMakeUndefined(context);
}
-static JSValueRef numberOfDFGCompiles(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+static JSValueRef failNextNewCodeBlock(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
if (argumentCount < 1)
return JSValueMakeUndefined(context);
+ return JSC::failNextNewCodeBlock(context);
+}
+
+static JSValueRef numberOfDFGCompiles(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
return JSC::numberOfDFGCompiles(context, arguments[0]);
}
@@ -2036,6 +2010,34 @@ static JSValueRef neverInlineFunction(JSContextRef context, JSObjectRef function
return JSC::setNeverInline(context, arguments[0]);
}
+static JSValueRef accummulateLogsForChannel(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> channel(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
+ controller->setAccummulateLogsForChannel(channel.get());
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef runUIScriptCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> script = argumentCount > 0 ? JSRetainPtr<JSStringRef>(Adopt, JSValueToStringCopy(context, arguments[0], 0)) : JSRetainPtr<JSStringRef>();
+ JSValueRef callback = argumentCount > 1 ? arguments[1] : JSValueMakeUndefined(context);
+
+ TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
+ controller->runUIScript(context, script.get(), callback);
+
+ return JSValueMakeUndefined(context);
+}
+
static void testRunnerObjectFinalize(JSObjectRef object)
{
TestRunner* controller = static_cast<TestRunner*>(JSObjectGetPrivate(object));
@@ -2071,12 +2073,14 @@ JSClassRef TestRunner::getJSClass()
JSStaticValue* TestRunner::staticValues()
{
static JSStaticValue staticValues[] = {
+ { "timeout", getTimeoutCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "globalFlag", getGlobalFlagCallback, setGlobalFlagCallback, kJSPropertyAttributeNone },
{ "webHistoryItemCount", getWebHistoryItemCountCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "secureEventInputIsEnabled", getSecureEventInputIsEnabledCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "titleTextDirection", getTitleTextDirectionCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "databaseDefaultQuota", getDatabaseDefaultQuotaCallback, setDatabaseDefaultQuotaCallback, kJSPropertyAttributeNone },
{ "databaseMaxQuota", getDatabaseMaxQuotaCallback, setDatabaseMaxQuotaCallback, kJSPropertyAttributeNone },
+ { "inspectorTestStubURL", getInspectorTestStubURLCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ 0, 0, 0, 0 }
};
return staticValues;
@@ -2122,7 +2126,6 @@ JSStaticFunction* TestRunner::staticFunctions()
{ "dumpSourceAsWebArchive", dumpSourceAsWebArchiveCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "dumpStatusCallbacks", dumpStatusCallbacksCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "dumpTitleChanges", dumpTitleChangesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "dumpIconChanges", dumpIconChangesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "dumpWillCacheResponse", dumpWillCacheResponseCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "encodeHostName", encodeHostNameCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "evaluateInWebInspector", evaluateInWebInspectorCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
@@ -2133,6 +2136,7 @@ JSStaticFunction* TestRunner::staticFunctions()
{ "originsWithApplicationCache", originsWithApplicationCacheCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "goBack", goBackCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "ignoreLegacyWebNotificationPermissionRequests", ignoreLegacyWebNotificationPermissionRequestsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isGeolocationProviderActive", isGeolocationProviderActiveCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "isCommandEnabled", isCommandEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "keepWebHistory", keepWebHistoryCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "numberOfPendingGeolocationPermissionRequests", numberOfPendingGeolocationPermissionRequestsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
@@ -2154,6 +2158,8 @@ JSStaticFunction* TestRunner::staticFunctions()
{ "setAcceptsEditing", setAcceptsEditingCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setAllowUniversalAccessFromFileURLs", setAllowUniversalAccessFromFileURLsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setAllowFileAccessFromFileURLs", setAllowFileAccessFromFileURLsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setNeedsStorageAccessFromFileURLsQuirk", setNeedsStorageAccessFromFileURLsQuirkCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setAllowsAnySSLCertificate", setAllowsAnySSLCertificateCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setAlwaysAcceptCookies", setAlwaysAcceptCookiesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setAppCacheMaximumSize", setAppCacheMaximumSizeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setAudioResult", setAudioResultCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
@@ -2166,11 +2172,11 @@ JSStaticFunction* TestRunner::staticFunctions()
{ "setCloseRemainingWindowsWhenComplete", setCloseRemainingWindowsWhenCompleteCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setCustomPolicyDelegate", setCustomPolicyDelegateCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setDatabaseQuota", setDatabaseQuotaCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "setDeferMainResourceDataLoad", setDeferMainResourceDataLoadCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setDefersLoading", setDefersLoadingCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setUseDeferredFrameLoading", setUseDeferredFrameLoadingCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setDomainRelaxationForbiddenForURLScheme", setDomainRelaxationForbiddenForURLSchemeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setGeolocationPermission", setGeolocationPermissionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setRejectsProtectionSpaceAndContinueForAuthenticationChallenges", setRejectsProtectionSpaceAndContinueForAuthenticationChallengesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setHandlesAuthenticationChallenges", setHandlesAuthenticationChallengesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setIconDatabaseEnabled", setIconDatabaseEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setAutomaticLinkDetectionEnabled", setAutomaticLinkDetectionEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
@@ -2178,8 +2184,6 @@ JSStaticFunction* TestRunner::staticFunctions()
{ "setMockDeviceOrientation", setMockDeviceOrientationCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setMockGeolocationPositionUnavailableError", setMockGeolocationPositionUnavailableErrorCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setMockGeolocationPosition", setMockGeolocationPositionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "addMockSpeechInputResult", addMockSpeechInputResultCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "setMockSpeechInputDumpRect", setMockSpeechInputDumpRectCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setNewWindowsCopyBackForwardList", setNewWindowsCopyBackForwardListCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setPageVisibility", setPageVisibilityCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setPOSIXLocale", setPOSIXLocaleCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
@@ -2196,9 +2200,6 @@ JSStaticFunction* TestRunner::staticFunctions()
{ "setTelephoneNumberParsingEnabled", setTelephoneNumberParsingEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setPagePaused", setPagePausedCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
#endif
-#if ENABLE(IOS_TEXT_AUTOSIZING)
- { "setTextAutosizingEnabled", setTextAutosizingEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
-#endif
{ "setUseDashboardCompatibilityMode", setUseDashboardCompatibilityModeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setUserStyleSheetEnabled", setUserStyleSheetEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setUserStyleSheetLocation", setUserStyleSheetLocationCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
@@ -2209,6 +2210,7 @@ JSStaticFunction* TestRunner::staticFunctions()
{ "setWillSendRequestReturnsNull", setWillSendRequestReturnsNullCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setWillSendRequestReturnsNullOnRedirect", setWillSendRequestReturnsNullOnRedirectCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setWindowIsKey", setWindowIsKeyCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setViewSize", setViewSizeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setJavaScriptCanAccessClipboard", setJavaScriptCanAccessClipboardCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setXSSAuditorEnabled", setXSSAuditorEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "showWebInspector", showWebInspectorCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
@@ -2221,12 +2223,6 @@ JSStaticFunction* TestRunner::staticFunctions()
{ "addOriginAccessWhitelistEntry", addOriginAccessWhitelistEntryCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setScrollbarPolicy", setScrollbarPolicyCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "authenticateSession", authenticateSessionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "deleteAllLocalStorage", deleteAllLocalStorageCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "syncLocalStorage", syncLocalStorageCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "observeStorageTrackerNotifications", observeStorageTrackerNotificationsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "deleteLocalStorageForOrigin", deleteLocalStorageForOriginCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "localStorageDiskUsageForOrigin", localStorageDiskUsageForOriginCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "originsWithLocalStorage", originsWithLocalStorageCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setShouldPaintBrokenImage", setShouldPaintBrokenImageCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setTextDirection", setTextDirectionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setShouldStayOnPageAfterHandlingBeforeUnload", setShouldStayOnPageAfterHandlingBeforeUnloadCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
@@ -2242,8 +2238,13 @@ JSStaticFunction* TestRunner::staticFunctions()
{ "denyWebNotificationPermission", denyWebNotificationPermissionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "removeAllWebNotificationPermissions", removeAllWebNotificationPermissionsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "simulateWebNotificationClick", simulateWebNotificationClickCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "failNextNewCodeBlock", failNextNewCodeBlock, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "numberOfDFGCompiles", numberOfDFGCompiles, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "neverInlineFunction", neverInlineFunction, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "accummulateLogsForChannel", accummulateLogsForChannel, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "runUIScript", runUIScriptCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "imageCountInGeneralPasteboard", imageCountInGeneralPasteboardCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setSpellCheckerLoggingEnabled", setSpellCheckerLoggingEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ 0, 0, 0 }
};
@@ -2252,37 +2253,37 @@ JSStaticFunction* TestRunner::staticFunctions()
void TestRunner::queueLoadHTMLString(JSStringRef content, JSStringRef baseURL)
{
- WorkQueue::shared()->queue(new LoadHTMLStringItem(content, baseURL));
+ WorkQueue::singleton().queue(new LoadHTMLStringItem(content, baseURL));
}
void TestRunner::queueLoadAlternateHTMLString(JSStringRef content, JSStringRef baseURL, JSStringRef unreachableURL)
{
- WorkQueue::shared()->queue(new LoadHTMLStringItem(content, baseURL, unreachableURL));
+ WorkQueue::singleton().queue(new LoadHTMLStringItem(content, baseURL, unreachableURL));
}
void TestRunner::queueBackNavigation(int howFarBack)
{
- WorkQueue::shared()->queue(new BackItem(howFarBack));
+ WorkQueue::singleton().queue(new BackItem(howFarBack));
}
void TestRunner::queueForwardNavigation(int howFarForward)
{
- WorkQueue::shared()->queue(new ForwardItem(howFarForward));
+ WorkQueue::singleton().queue(new ForwardItem(howFarForward));
}
void TestRunner::queueLoadingScript(JSStringRef script)
{
- WorkQueue::shared()->queue(new LoadingScriptItem(script));
+ WorkQueue::singleton().queue(new LoadingScriptItem(script));
}
void TestRunner::queueNonLoadingScript(JSStringRef script)
{
- WorkQueue::shared()->queue(new NonLoadingScriptItem(script));
+ WorkQueue::singleton().queue(new NonLoadingScriptItem(script));
}
void TestRunner::queueReload()
{
- WorkQueue::shared()->queue(new ReloadItem);
+ WorkQueue::singleton().queue(new ReloadItem);
}
void TestRunner::ignoreLegacyWebNotificationPermissionRequests()
@@ -2293,8 +2294,14 @@ void TestRunner::ignoreLegacyWebNotificationPermissionRequests()
void TestRunner::waitToDumpWatchdogTimerFired()
{
const char* message = "FAIL: Timed out waiting for notifyDone to be called\n";
- fprintf(stderr, "%s", message);
- fprintf(stdout, "%s", message);
+ fprintf(testResult, "%s", message);
+
+ auto accumulatedLogs = getAndResetAccumulatedLogs();
+ if (!accumulatedLogs.isEmpty()) {
+ const char* message = "Logs accumulated during test run:\n";
+ fprintf(testResult, "%s%s\n", message, accumulatedLogs.utf8().data());
+ }
+
notifyDone();
}
@@ -2325,3 +2332,118 @@ void TestRunner::setShouldPaintBrokenImage(bool shouldPaintBrokenImage)
{
m_shouldPaintBrokenImage = shouldPaintBrokenImage;
}
+
+void TestRunner::setAccummulateLogsForChannel(JSStringRef channel)
+{
+ size_t maxLength = JSStringGetMaximumUTF8CStringSize(channel);
+ auto buffer = std::make_unique<char[]>(maxLength + 1);
+ JSStringGetUTF8CString(channel, buffer.get(), maxLength + 1);
+
+ WebCoreTestSupport::setLogChannelToAccumulate({ buffer.get() });
+}
+
+typedef WTF::HashMap<unsigned, JSValueRef> CallbackMap;
+static CallbackMap& callbackMap()
+{
+ static CallbackMap& map = *new CallbackMap;
+ return map;
+}
+
+void TestRunner::cacheTestRunnerCallback(unsigned index, JSValueRef callback)
+{
+ if (!callback)
+ return;
+
+ if (callbackMap().contains(index)) {
+ fprintf(stderr, "FAIL: Tried to install a second TestRunner callback for the same event (id %d)\n", index);
+ return;
+ }
+
+ JSContextRef context = mainFrameJSContext();
+ JSValueProtect(context, callback);
+ callbackMap().add(index, callback);
+}
+
+void TestRunner::callTestRunnerCallback(unsigned index, size_t argumentCount, const JSValueRef arguments[])
+{
+ if (!callbackMap().contains(index))
+ return;
+
+ JSContextRef context = mainFrameJSContext();
+ if (JSObjectRef callback = JSValueToObject(context, callbackMap().take(index), 0)) {
+ JSObjectCallAsFunction(context, callback, JSContextGetGlobalObject(context), argumentCount, arguments, 0);
+ JSValueUnprotect(context, callback);
+ }
+}
+
+void TestRunner::clearTestRunnerCallbacks()
+{
+ JSContextRef context = mainFrameJSContext();
+
+ for (auto& iter : callbackMap()) {
+ if (JSObjectRef callback = JSValueToObject(context, iter.value, 0))
+ JSValueUnprotect(context, callback);
+ }
+
+ callbackMap().clear();
+}
+
+enum {
+ FirstUIScriptCallbackID = 100
+};
+
+static unsigned nextUIScriptCallbackID()
+{
+ static unsigned callbackID = FirstUIScriptCallbackID;
+ return callbackID++;
+}
+
+void TestRunner::runUIScript(JSContextRef context, JSStringRef script, JSValueRef callback)
+{
+ m_pendingUIScriptInvocationData = nullptr;
+
+ unsigned callbackID = nextUIScriptCallbackID();
+ cacheTestRunnerCallback(callbackID, callback);
+
+ if (!m_UIScriptContext)
+ m_UIScriptContext = std::make_unique<WTR::UIScriptContext>(*this);
+
+ String scriptString(JSStringGetCharactersPtr(script), JSStringGetLength(script));
+ m_UIScriptContext->runUIScript(scriptString, callbackID);
+}
+
+void TestRunner::callUIScriptCallback(unsigned callbackID, JSStringRef result)
+{
+ JSRetainPtr<JSStringRef> protectedResult(result);
+#if !PLATFORM(IOS)
+ RunLoop::main().dispatch([protectedThis = makeRef(*this), callbackID, protectedResult]() mutable {
+ JSContextRef context = protectedThis->mainFrameJSContext();
+ JSValueRef resultValue = JSValueMakeString(context, protectedResult.get());
+ protectedThis->callTestRunnerCallback(callbackID, 1, &resultValue);
+ });
+#else
+ WebThreadRun(
+ BlockPtr<void()>::fromCallable([protectedThis = makeRef(*this), callbackID, protectedResult] {
+ JSContextRef context = protectedThis->mainFrameJSContext();
+ JSValueRef resultValue = JSValueMakeString(context, protectedResult.get());
+ protectedThis->callTestRunnerCallback(callbackID, 1, &resultValue);
+ }).get()
+ );
+#endif
+}
+
+void TestRunner::uiScriptDidComplete(const String& result, unsigned callbackID)
+{
+ JSRetainPtr<JSStringRef> stringRef(Adopt, JSStringCreateWithUTF8CString(result.utf8().data()));
+ callUIScriptCallback(callbackID, stringRef.get());
+}
+
+void TestRunner::setAllowsAnySSLCertificate(bool allowsAnySSLCertificate)
+{
+ WebCoreTestSupport::setAllowsAnySSLCertificate(allowsAnySSLCertificate);
+}
+
+void TestRunner::cleanup()
+{
+ clearTestRunnerCallbacks();
+}
diff --git a/Tools/DumpRenderTree/TestRunner.h b/Tools/DumpRenderTree/TestRunner.h
index 882c0e96c..57c401003 100644
--- a/Tools/DumpRenderTree/TestRunner.h
+++ b/Tools/DumpRenderTree/TestRunner.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008, 2009, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2007-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -25,21 +25,23 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
-#ifndef TestRunner_h
-#define TestRunner_h
+#pragma once
+
+#include "UIScriptContext.h"
#include <JavaScriptCore/JSObjectRef.h>
#include <map>
#include <set>
#include <string>
#include <vector>
-#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
-class TestRunner : public RefCounted<TestRunner> {
+extern FILE* testResult;
+
+class TestRunner : public WTR::UIScriptContextDelegate, public RefCounted<TestRunner> {
+ WTF_MAKE_NONCOPYABLE(TestRunner);
public:
- static PassRefPtr<TestRunner> create(const std::string& testPathOrURL, const std::string& expectedPixelHash);
+ static Ref<TestRunner> create(const std::string& testURL, const std::string& expectedPixelHash);
static const unsigned viewWidth;
static const unsigned viewHeight;
@@ -47,11 +49,15 @@ public:
static const unsigned w3cSVGViewWidth;
static const unsigned w3cSVGViewHeight;
- ~TestRunner();
+ virtual ~TestRunner();
+
+ void cleanup();
void makeWindowObject(JSContextRef, JSObjectRef windowObject, JSValueRef* exception);
void addDisallowedURL(JSStringRef url);
+ const std::set<std::string>& allowedHosts() const { return m_allowedHosts; }
+ void setAllowedHosts(std::set<std::string> hosts) { m_allowedHosts = WTFMove(hosts); }
void addURLToRedirect(std::string origin, std::string destination);
const std::string& redirectionDestinationForURL(std::string);
void clearAllApplicationCaches();
@@ -74,6 +80,7 @@ public:
void keepWebHistory();
void notifyDone();
int numberOfPendingGeolocationPermissionRequests();
+ bool isGeolocationProviderActive();
void overridePreference(JSStringRef key, JSStringRef value);
JSStringRef pathToLocalResource(JSContextRef, JSStringRef url);
void queueBackNavigation(int howFarBackward);
@@ -86,8 +93,10 @@ public:
void queueReload();
void removeAllVisitedLinks();
void setAcceptsEditing(bool);
+ void setFetchAPIEnabled(bool);
void setAllowUniversalAccessFromFileURLs(bool);
void setAllowFileAccessFromFileURLs(bool);
+ void setNeedsStorageAccessFromFileURLsQuirk(bool);
void setAppCacheMaximumSize(unsigned long long quota);
void setAuthorAndUserStylesEnabled(bool);
void setCacheModel(int);
@@ -102,8 +111,6 @@ public:
void setMockDeviceOrientation(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma);
void setMockGeolocationPosition(double latitude, double longitude, double accuracy, bool providesAltitude, double altitude, bool providesAltitudeAccuracy, double altitudeAccuracy, bool providesHeading, double heading, bool providesSpeed, double speed);
void setMockGeolocationPositionUnavailableError(JSStringRef message);
- void addMockSpeechInputResult(JSStringRef result, double confidence, JSStringRef language);
- void setMockSpeechInputDumpRect(bool flag);
void setPersistentUserStyleSheetLocation(JSStringRef path);
void setPluginsEnabled(bool);
void setPopupBlockingEnabled(bool);
@@ -117,7 +124,6 @@ public:
void setXSSAuditorEnabled(bool flag);
void setSpatialNavigationEnabled(bool);
void setScrollbarPolicy(JSStringRef orientation, JSStringRef policy);
- void startSpeechInput(JSContextRef inputElement);
#if PLATFORM(IOS)
void setTelephoneNumberParsingEnabled(bool enable);
void setPagePaused(bool paused);
@@ -126,14 +132,20 @@ public:
void setPageVisibility(const char*);
void resetPageVisibility();
+ static void setAllowsAnySSLCertificate(bool);
+
void waitForPolicyDelegate();
size_t webHistoryItemCount();
int windowCount();
-#if ENABLE(IOS_TEXT_AUTOSIZING)
+#if ENABLE(TEXT_AUTOSIZING)
void setTextAutosizingEnabled(bool);
#endif
+ void setAccummulateLogsForChannel(JSStringRef);
+
+ void runUIScript(JSContextRef, JSStringRef, JSValueRef callback);
+
// Legacy here refers to the old TestRunner API for handling web notifications, not the legacy web notification API.
void ignoreLegacyWebNotificationPermissionRequests();
// Legacy here refers to the old TestRunner API for handling web notifications, not the legacy web notification API.
@@ -209,9 +221,6 @@ public:
bool dumpTitleChanges() const { return m_dumpTitleChanges; }
void setDumpTitleChanges(bool dumpTitleChanges) { m_dumpTitleChanges = dumpTitleChanges; }
- bool dumpIconChanges() const { return m_dumpIconChanges; }
- void setDumpIconChanges(bool dumpIconChanges) { m_dumpIconChanges = dumpIconChanges; }
-
bool dumpVisitedLinksCallback() const { return m_dumpVisitedLinksCallback; }
void setDumpVisitedLinksCallback(bool dumpVisitedLinksCallback) { m_dumpVisitedLinksCallback = dumpVisitedLinksCallback; }
@@ -258,9 +267,14 @@ public:
bool windowIsKey() const { return m_windowIsKey; }
void setWindowIsKey(bool);
+ void setViewSize(double width, double height);
+
bool alwaysAcceptCookies() const { return m_alwaysAcceptCookies; }
void setAlwaysAcceptCookies(bool);
+ bool rejectsProtectionSpaceAndContinueForAuthenticationChallenges() const { return m_rejectsProtectionSpaceAndContinueForAuthenticationChallenges; }
+ void setRejectsProtectionSpaceAndContinueForAuthenticationChallenges(bool value) { m_rejectsProtectionSpaceAndContinueForAuthenticationChallenges = value; }
+
bool handlesAuthenticationChallenges() const { return m_handlesAuthenticationChallenges; }
void setHandlesAuthenticationChallenges(bool handlesAuthenticationChallenges) { m_handlesAuthenticationChallenges = handlesAuthenticationChallenges; }
@@ -282,13 +296,10 @@ public:
double databaseMaxQuota() const { return m_databaseMaxQuota; }
void setDatabaseMaxQuota(double quota) { m_databaseMaxQuota = quota; }
- bool deferMainResourceDataLoad() const { return m_deferMainResourceDataLoad; }
- void setDeferMainResourceDataLoad(bool flag) { m_deferMainResourceDataLoad = flag; }
-
bool useDeferredFrameLoading() const { return m_useDeferredFrameLoading; }
void setUseDeferredFrameLoading(bool flag) { m_useDeferredFrameLoading = flag; }
- const std::string& testPathOrURL() const { return m_testPathOrURL; }
+ const std::string& testURL() const { return m_testURL; }
const std::string& expectedPixelHash() const { return m_expectedPixelHash; }
const std::vector<char>& audioResult() const { return m_audioResult; }
@@ -307,7 +318,9 @@ public:
void setDeveloperExtrasEnabled(bool);
void showWebInspector();
void closeWebInspector();
- void evaluateInWebInspector(long callId, JSStringRef script);
+ void evaluateInWebInspector(JSStringRef script);
+ JSStringRef inspectorTestStubURL();
+
void evaluateScriptInIsolatedWorld(unsigned worldID, JSObjectRef globalObject, JSStringRef script);
void evaluateScriptInIsolatedWorldAndReturnValue(unsigned worldID, JSObjectRef globalObject, JSStringRef script);
@@ -336,13 +349,6 @@ public:
// Simulate a request an embedding application could make, populating per-session credential storage.
void authenticateSession(JSStringRef url, JSStringRef username, JSStringRef password);
- JSValueRef originsWithLocalStorage(JSContextRef);
- void deleteAllLocalStorage();
- void deleteLocalStorageForOrigin(JSStringRef originIdentifier);
- long long localStorageDiskUsageForOrigin(JSStringRef originIdentifier);
- void observeStorageTrackerNotifications(unsigned number);
- void syncLocalStorage();
-
void setShouldPaintBrokenImage(bool);
bool shouldPaintBrokenImage() const { return m_shouldPaintBrokenImage; }
@@ -359,8 +365,29 @@ public:
bool hasPendingWebNotificationClick() const { return m_hasPendingWebNotificationClick; }
+ void setCustomTimeout(int duration) { m_timeout = duration; }
+ double timeout() { return m_timeout; }
+
+ unsigned imageCountInGeneralPasteboard() const;
+
+ void callUIScriptCallback(unsigned callbackID, JSStringRef result);
+
+ void setDumpJSConsoleLogInStdErr(bool inStdErr) { m_dumpJSConsoleLogInStdErr = inStdErr; }
+ bool dumpJSConsoleLogInStdErr() const { return m_dumpJSConsoleLogInStdErr; }
+
+ void setSpellCheckerLoggingEnabled(bool);
+
private:
- TestRunner(const std::string& testPathOrURL, const std::string& expectedPixelHash);
+ TestRunner(const std::string& testURL, const std::string& expectedPixelHash);
+
+ JSContextRef mainFrameJSContext();
+
+ // UIScriptContextDelegate
+ void uiScriptDidComplete(const String&, unsigned callbackID) override;
+
+ void cacheTestRunnerCallback(unsigned index, JSValueRef);
+ void callTestRunnerCallback(unsigned index, size_t argumentCount = 0, const JSValueRef arguments[] = nullptr);
+ void clearTestRunnerCallbacks();
void setGeolocationPermissionCommon(bool allow);
@@ -385,7 +412,6 @@ private:
bool m_dumpSourceAsWebArchive;
bool m_dumpStatusCallbacks;
bool m_dumpTitleChanges;
- bool m_dumpIconChanges;
bool m_dumpVisitedLinksCallback;
bool m_dumpWillCacheResponse;
bool m_generatePixelResults;
@@ -405,9 +431,9 @@ private:
bool m_globalFlag;
bool m_isGeolocationPermissionSet;
bool m_geolocationPermission;
+ bool m_rejectsProtectionSpaceAndContinueForAuthenticationChallenges;
bool m_handlesAuthenticationChallenges;
bool m_isPrinting;
- bool m_deferMainResourceDataLoad;
bool m_useDeferredFrameLoading;
bool m_shouldPaintBrokenImage;
bool m_shouldStayOnPageAfterHandlingBeforeUnload;
@@ -415,25 +441,35 @@ private:
bool m_areLegacyWebNotificationPermissionRequestsIgnored;
bool m_customFullScreenBehavior;
bool m_hasPendingWebNotificationClick;
+ bool m_dumpJSConsoleLogInStdErr { false };
double m_databaseDefaultQuota;
double m_databaseMaxQuota;
std::string m_authenticationUsername;
std::string m_authenticationPassword;
- std::string m_testPathOrURL;
+ std::string m_testURL;
std::string m_expectedPixelHash; // empty string if no hash
std::string m_titleTextDirection;
std::set<std::string> m_willSendRequestClearHeaders;
+ std::set<std::string> m_allowedHosts;
std::vector<char> m_audioResult;
std::map<std::string, std::string> m_URLsToRedirect;
-
+
+ struct UIScriptInvocationData {
+ unsigned callbackID;
+ String scriptString;
+ };
+
+ std::unique_ptr<WTR::UIScriptContext> m_UIScriptContext;
+ UIScriptInvocationData* m_pendingUIScriptInvocationData { nullptr };
+
static JSClassRef getJSClass();
static JSStaticValue* staticValues();
static JSStaticFunction* staticFunctions();
-};
-#endif // TestRunner_h
+ int m_timeout;
+};
diff --git a/Tools/DumpRenderTree/gtk/TextInputController.h b/Tools/DumpRenderTree/TextInputController.h
index 53793f637..3472ee789 100644
--- a/Tools/DumpRenderTree/gtk/TextInputController.h
+++ b/Tools/DumpRenderTree/TextInputController.h
@@ -1,18 +1,18 @@
/*
- * Copyright (C) 2011 Igalia S.L.
+ * Copyright (C) 2005, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
+ * notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
+ * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -26,12 +26,16 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TextInputController_h
-#define TextInputController_h
+#import <Foundation/Foundation.h>
-typedef const struct OpaqueJSContext* JSContextRef;
-typedef struct OpaqueJSValue* JSObjectRef;
+@class WebView;
+@class WebHTMLView;
+@class WebScriptObject;
-JSObjectRef makeTextInputController(JSContextRef);
-
-#endif
+@interface TextInputController : NSObject {
+ WebView *webView;
+ WebHTMLView *inputMethodView;
+ WebScriptObject *inputMethodHandler;
+}
+- (id)initWithWebView:(WebView *)view;
+@end
diff --git a/Tools/DumpRenderTree/WorkQueue.cpp b/Tools/DumpRenderTree/WorkQueue.cpp
index 0106fbac1..097f4cdd2 100644
--- a/Tools/DumpRenderTree/WorkQueue.cpp
+++ b/Tools/DumpRenderTree/WorkQueue.cpp
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -31,6 +31,7 @@
#include "WorkQueueItem.h"
#include <wtf/Assertions.h>
+#include <wtf/NeverDestroyed.h>
static const unsigned queueLength = 1024;
@@ -38,9 +39,9 @@ static WorkQueueItem* theQueue[queueLength];
static unsigned startOfQueue;
static unsigned endOfQueue;
-WorkQueue* WorkQueue::shared()
+WorkQueue& WorkQueue::singleton()
{
- static WorkQueue* sharedInstance = new WorkQueue;
+ static NeverDestroyed<WorkQueue> sharedInstance;
return sharedInstance;
}
diff --git a/Tools/DumpRenderTree/WorkQueue.h b/Tools/DumpRenderTree/WorkQueue.h
index 649c6c1f5..0697e7c3e 100644
--- a/Tools/DumpRenderTree/WorkQueue.h
+++ b/Tools/DumpRenderTree/WorkQueue.h
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -29,11 +29,15 @@
#ifndef WorkQueue_h
#define WorkQueue_h
+#include <wtf/Forward.h>
+
class WorkQueueItem;
class WorkQueue {
+friend class WTF::NeverDestroyed<WorkQueue>;
+
public:
- static WorkQueue* shared();
+ static WorkQueue& singleton();
void queue(WorkQueueItem*);
WorkQueueItem* dequeue();
diff --git a/Tools/DumpRenderTree/WorkQueueItem.h b/Tools/DumpRenderTree/WorkQueueItem.h
index 08fc2208b..6a49f593f 100644
--- a/Tools/DumpRenderTree/WorkQueueItem.h
+++ b/Tools/DumpRenderTree/WorkQueueItem.h
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
diff --git a/Tools/DumpRenderTree/atk/AccessibilityCallbacks.h b/Tools/DumpRenderTree/atk/AccessibilityCallbacks.h
deleted file mode 100644
index 0feef55c8..000000000
--- a/Tools/DumpRenderTree/atk/AccessibilityCallbacks.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2011 Igalia S.L.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef AccessibilityCallbacks_h
-#define AccessibilityCallbacks_h
-
-#if HAVE(ACCESSIBILITY)
-
-#include "AccessibilityNotificationHandlerAtk.h"
-#include "AccessibilityUIElement.h"
-
-void connectAccessibilityCallbacks();
-bool disconnectAccessibilityCallbacks();
-void addAccessibilityNotificationHandler(AccessibilityNotificationHandler*);
-void removeAccessibilityNotificationHandler(AccessibilityNotificationHandler*);
-
-#endif // HAVE(ACCESSIBILITY)
-
-#endif // AccessibilityCallbacks_h
diff --git a/Tools/DumpRenderTree/atk/AccessibilityCallbacksAtk.cpp b/Tools/DumpRenderTree/atk/AccessibilityCallbacksAtk.cpp
deleted file mode 100644
index 01f6651b4..000000000
--- a/Tools/DumpRenderTree/atk/AccessibilityCallbacksAtk.cpp
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Copyright (C) 2011 Igalia S.L.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "AccessibilityCallbacks.h"
-
-#if HAVE(ACCESSIBILITY)
-
-#include "AccessibilityController.h"
-#include "AccessibilityNotificationHandlerAtk.h"
-#include "DumpRenderTree.h"
-#include "JSRetainPtr.h"
-#include <atk/atk.h>
-#include <wtf/gobject/GUniquePtr.h>
-
-#if PLATFORM(GTK)
-#include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
-#include <webkit/webkit.h>
-#endif
-
-#if PLATFORM(EFL)
-#include "DumpRenderTreeChrome.h"
-#include "WebCoreSupport/DumpRenderTreeSupportEfl.h"
-#endif
-
-typedef HashMap<PlatformUIElement, AccessibilityNotificationHandler*> NotificationHandlersMap;
-
-static guint stateChangeListenerId = 0;
-static guint focusEventListenerId = 0;
-static guint activeDescendantChangedListenerId = 0;
-static guint childrenChangedListenerId = 0;
-static guint propertyChangedListenerId = 0;
-static guint visibleDataChangedListenerId = 0;
-static guint loadCompleteListenerId = 0;
-// Up to 2014 it was obligatory to mirror the changes from
-// WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.cpp,
-// but the habit has been dropped: https://bugs.webkit.org/show_bug.cgi?id=132527#c6
-static NotificationHandlersMap notificationHandlers;
-static AccessibilityNotificationHandler* globalNotificationHandler = 0;
-
-extern bool loggingAccessibilityEvents;
-
-static void printAccessibilityEvent(AtkObject* accessible, const gchar* signalName, const gchar* signalValue)
-{
- // Do not handle state-change:defunct signals, as the AtkObject
- // associated to them will not be valid at this point already.
- if (!signalName || !g_strcmp0(signalName, "state-change:defunct"))
- return;
-
- if (!accessible || !ATK_IS_OBJECT(accessible))
- return;
-
- const gchar* objectName = atk_object_get_name(accessible);
- AtkRole objectRole = atk_object_get_role(accessible);
-
- // Try to always provide a name to be logged for the object.
- if (!objectName || *objectName == '\0')
- objectName = "(No name)";
-
- GUniquePtr<gchar> signalNameAndValue(signalValue ? g_strdup_printf("%s = %s", signalName, signalValue) : g_strdup(signalName));
- printf("Accessibility object emitted \"%s\" / Name: \"%s\" / Role: %d\n", signalNameAndValue.get(), objectName, objectRole);
-}
-
-static gboolean axObjectEventListener(GSignalInvocationHint *signalHint, guint numParamValues, const GValue *paramValues, gpointer data)
-{
- // At least we should receive the instance emitting the signal.
- if (numParamValues < 1)
- return true;
-
- AtkObject* accessible = ATK_OBJECT(g_value_get_object(&paramValues[0]));
- if (!accessible || !ATK_IS_OBJECT(accessible))
- return true;
-
- GSignalQuery signalQuery;
- GUniquePtr<gchar> signalName;
- GUniquePtr<gchar> signalValue;
- String notificationName;
-
- g_signal_query(signalHint->signal_id, &signalQuery);
-
- if (!g_strcmp0(signalQuery.signal_name, "state-change")) {
- signalName.reset(g_strdup_printf("state-change:%s", g_value_get_string(&paramValues[1])));
- signalValue.reset(g_strdup_printf("%d", g_value_get_boolean(&paramValues[2])));
- if (!g_strcmp0(g_value_get_string(&paramValues[1]), "checked"))
- notificationName = "CheckedStateChanged";
- else if (!g_strcmp0(g_value_get_string(&paramValues[1]), "invalid-entry"))
- notificationName = "AXInvalidStatusChanged";
- } else if (!g_strcmp0(signalQuery.signal_name, "focus-event")) {
- signalName.reset(g_strdup("focus-event"));
- signalValue.reset(g_strdup_printf("%d", g_value_get_boolean(&paramValues[1])));
- if (g_value_get_boolean(&paramValues[1]))
- notificationName = "AXFocusedUIElementChanged";
- } else if (!g_strcmp0(signalQuery.signal_name, "children-changed")) {
- const gchar* childrenChangedDetail = g_quark_to_string(signalHint->detail);
- signalName.reset(g_strdup_printf("children-changed:%s", childrenChangedDetail));
- signalValue.reset(g_strdup_printf("%d", g_value_get_uint(&paramValues[1])));
- notificationName = !g_strcmp0(childrenChangedDetail, "add") ? "AXChildrenAdded" : "AXChildrenRemoved";
- } else if (!g_strcmp0(signalQuery.signal_name, "property-change")) {
- signalName.reset(g_strdup_printf("property-change:%s", g_quark_to_string(signalHint->detail)));
- if (!g_strcmp0(g_quark_to_string(signalHint->detail), "accessible-value"))
- notificationName = "AXValueChanged";
- } else if (!g_strcmp0(signalQuery.signal_name, "load-complete"))
- notificationName = "AXLoadComplete";
- else
- signalName.reset(g_strdup(signalQuery.signal_name));
-
- if (loggingAccessibilityEvents)
- printAccessibilityEvent(accessible, signalName.get(), signalValue.get());
-
-#if PLATFORM(GTK)
- JSGlobalContextRef jsContext = webkit_web_frame_get_global_context(mainFrame);
-#elif PLATFORM(EFL)
- JSGlobalContextRef jsContext = DumpRenderTreeSupportEfl::globalContextRefForFrame(browser->mainFrame());
-#else
- JSContextRef jsContext = 0;
-#endif
- if (!jsContext)
- return true;
-
- if (notificationName.length()) {
- JSRetainPtr<JSStringRef> jsNotificationEventName(Adopt, JSStringCreateWithUTF8CString(notificationName.utf8().data()));
- JSValueRef notificationNameArgument = JSValueMakeString(jsContext, jsNotificationEventName.get());
- NotificationHandlersMap::iterator elementNotificationHandler = notificationHandlers.find(accessible);
- if (elementNotificationHandler != notificationHandlers.end()) {
- // Listener for one element just gets one argument, the notification name.
- JSObjectCallAsFunction(jsContext, elementNotificationHandler->value->notificationFunctionCallback(), 0, 1, &notificationNameArgument, 0);
- }
-
- if (globalNotificationHandler) {
- // A global listener gets the element and the notification name as arguments.
- JSValueRef arguments[2];
- arguments[0] = AccessibilityUIElement::makeJSAccessibilityUIElement(jsContext, AccessibilityUIElement(accessible));
- arguments[1] = notificationNameArgument;
- JSObjectCallAsFunction(jsContext, globalNotificationHandler->notificationFunctionCallback(), 0, 2, arguments, 0);
- }
- }
-
- return true;
-}
-
-void connectAccessibilityCallbacks()
-{
- // Ensure no callbacks are connected before.
- if (!disconnectAccessibilityCallbacks())
- return;
-
- // Ensure that accessibility is initialized for the WebView by querying for
- // the root accessible object, which will create the full hierarchy.
-#if PLATFORM(GTK)
- DumpRenderTreeSupportGtk::getRootAccessibleElement(mainFrame);
-#elif PLATFORM(EFL)
- DumpRenderTreeSupportEfl::rootAccessibleElement(browser->mainFrame());
-#endif
-
- // Add global listeners for AtkObject's signals.
- stateChangeListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:state-change");
- focusEventListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:focus-event");
- activeDescendantChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:active-descendant-changed");
- childrenChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:children-changed");
- propertyChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:property-change");
- visibleDataChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:visible-data-changed");
- loadCompleteListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkDocument:load-complete");
-
- // Ensure the Atk interface types are registered, otherwise
- // the AtkDocument signal handlers below won't get registered.
- GObject* dummyAxObject = G_OBJECT(g_object_new(ATK_TYPE_OBJECT, 0));
- AtkObject* dummyNoOpAxObject = atk_no_op_object_new(dummyAxObject);
- g_object_unref(G_OBJECT(dummyNoOpAxObject));
- g_object_unref(dummyAxObject);
-}
-
-bool disconnectAccessibilityCallbacks()
-{
- // Only disconnect if logging is off and there is no notification handler.
- if (loggingAccessibilityEvents || !notificationHandlers.isEmpty() || globalNotificationHandler)
- return false;
-
- // AtkObject signals.
- if (stateChangeListenerId) {
- atk_remove_global_event_listener(stateChangeListenerId);
- stateChangeListenerId = 0;
- }
- if (focusEventListenerId) {
- atk_remove_global_event_listener(focusEventListenerId);
- focusEventListenerId = 0;
- }
- if (activeDescendantChangedListenerId) {
- atk_remove_global_event_listener(activeDescendantChangedListenerId);
- activeDescendantChangedListenerId = 0;
- }
- if (childrenChangedListenerId) {
- atk_remove_global_event_listener(childrenChangedListenerId);
- childrenChangedListenerId = 0;
- }
- if (propertyChangedListenerId) {
- atk_remove_global_event_listener(propertyChangedListenerId);
- propertyChangedListenerId = 0;
- }
- if (visibleDataChangedListenerId) {
- atk_remove_global_event_listener(visibleDataChangedListenerId);
- visibleDataChangedListenerId = 0;
- }
- if (loadCompleteListenerId) {
- atk_remove_global_event_listener(loadCompleteListenerId);
- loadCompleteListenerId = 0;
- }
-
- return true;
-}
-
-void addAccessibilityNotificationHandler(AccessibilityNotificationHandler* notificationHandler)
-{
- if (!notificationHandler)
- return;
-
-#if PLATFORM(GTK)
- JSGlobalContextRef jsContext = webkit_web_frame_get_global_context(mainFrame);
-#elif PLATFORM(EFL)
- JSGlobalContextRef jsContext = DumpRenderTreeSupportEfl::globalContextRefForFrame(browser->mainFrame());
-#else
- JSContextRef jsContext = 0;
-#endif
- if (!jsContext)
- return;
-
- JSValueProtect(jsContext, notificationHandler->notificationFunctionCallback());
- // Check if this notification handler is related to a specific element.
- if (notificationHandler->platformElement()) {
- NotificationHandlersMap::iterator currentNotificationHandler = notificationHandlers.find(notificationHandler->platformElement());
- if (currentNotificationHandler != notificationHandlers.end()) {
- ASSERT(currentNotificationHandler->value->platformElement());
- JSValueUnprotect(jsContext, currentNotificationHandler->value->notificationFunctionCallback());
- notificationHandlers.remove(currentNotificationHandler->value->platformElement());
- }
- notificationHandlers.add(notificationHandler->platformElement(), notificationHandler);
- } else {
- if (globalNotificationHandler)
- JSValueUnprotect(jsContext, globalNotificationHandler->notificationFunctionCallback());
- globalNotificationHandler = notificationHandler;
- }
-
- connectAccessibilityCallbacks();
-}
-
-void removeAccessibilityNotificationHandler(AccessibilityNotificationHandler* notificationHandler)
-{
- if (!notificationHandler)
- return;
-
-#if PLATFORM(GTK)
- JSGlobalContextRef jsContext = webkit_web_frame_get_global_context(mainFrame);
-#elif PLATFORM(EFL)
- JSGlobalContextRef jsContext = DumpRenderTreeSupportEfl::globalContextRefForFrame(browser->mainFrame());
-#else
- JSGlobalContextRef jsContext = 0;
-#endif
- if (!jsContext)
- return;
-
- if (globalNotificationHandler == notificationHandler) {
- JSValueUnprotect(jsContext, globalNotificationHandler->notificationFunctionCallback());
- globalNotificationHandler = 0;
- } else if (notificationHandler->platformElement()) {
- NotificationHandlersMap::iterator removeNotificationHandler = notificationHandlers.find(notificationHandler->platformElement());
- if (removeNotificationHandler != notificationHandlers.end()) {
- JSValueUnprotect(jsContext, removeNotificationHandler->value->notificationFunctionCallback());
- notificationHandlers.remove(removeNotificationHandler);
- }
- }
-}
-
-#endif
diff --git a/Tools/DumpRenderTree/atk/AccessibilityControllerAtk.cpp b/Tools/DumpRenderTree/atk/AccessibilityControllerAtk.cpp
deleted file mode 100644
index d8d0fc96c..000000000
--- a/Tools/DumpRenderTree/atk/AccessibilityControllerAtk.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved.
- * Copyright (C) 2009 Jan Michael Alonzo
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "AccessibilityController.h"
-
-#if HAVE(ACCESSIBILITY)
-
-#include "AccessibilityCallbacks.h"
-#include "AccessibilityUIElement.h"
-#include "DumpRenderTree.h"
-
-#include <atk/atk.h>
-
-bool loggingAccessibilityEvents = false;
-
-AccessibilityController::AccessibilityController()
- : m_globalNotificationHandler(nullptr)
-{
-}
-
-AccessibilityController::~AccessibilityController()
-{
-}
-
-AccessibilityUIElement AccessibilityController::elementAtPoint(int x, int y)
-{
- // FIXME: implement
- return nullptr;
-}
-
-void AccessibilityController::platformResetToConsistentState()
-{
-}
-
-void AccessibilityController::setLogFocusEvents(bool)
-{
-}
-
-void AccessibilityController::setLogScrollingStartEvents(bool)
-{
-}
-
-void AccessibilityController::setLogValueChangeEvents(bool)
-{
-}
-
-void AccessibilityController::setLogAccessibilityEvents(bool logAccessibilityEvents)
-{
- if (logAccessibilityEvents == loggingAccessibilityEvents)
- return;
-
- if (!logAccessibilityEvents) {
- loggingAccessibilityEvents = false;
- disconnectAccessibilityCallbacks();
- return;
- }
-
- connectAccessibilityCallbacks();
- loggingAccessibilityEvents = true;
-}
-
-bool AccessibilityController::addNotificationListener(JSObjectRef functionCallback)
-{
- if (!functionCallback)
- return false;
-
- // Only one global notification listener.
- if (m_globalNotificationHandler)
- return false;
-
- m_globalNotificationHandler = AccessibilityNotificationHandler::create();
- m_globalNotificationHandler->setNotificationFunctionCallback(functionCallback);
-
- return true;
-}
-
-void AccessibilityController::removeNotificationListener()
-{
- // Programmers should not be trying to remove a listener that's already removed.
- ASSERT(m_globalNotificationHandler);
-
- m_globalNotificationHandler = nullptr;
-}
-
-JSRetainPtr<JSStringRef> AccessibilityController::platformName() const
-{
- JSRetainPtr<JSStringRef> platformName(Adopt, JSStringCreateWithUTF8CString("atk"));
- return platformName;
-}
-
-AtkObject* AccessibilityController::childElementById(AtkObject* parent, const char* id)
-{
- if (!ATK_IS_OBJECT(parent))
- return nullptr;
-
- bool parentFound = false;
- AtkAttributeSet* attributeSet(atk_object_get_attributes(parent));
- for (AtkAttributeSet* attributes = attributeSet; attributes; attributes = attributes->next) {
- AtkAttribute* attribute = static_cast<AtkAttribute*>(attributes->data);
- if (!strcmp(attribute->name, "html-id")) {
- if (!strcmp(attribute->value, id))
- parentFound = true;
- break;
- }
- }
- atk_attribute_set_free(attributeSet);
-
- if (parentFound)
- return parent;
-
- int childCount = atk_object_get_n_accessible_children(parent);
- for (int i = 0; i < childCount; i++) {
- AtkObject* result = childElementById(atk_object_ref_accessible_child(parent, i), id);
- if (ATK_IS_OBJECT(result))
- return result;
- }
-
- return nullptr;
-}
-
-#endif
diff --git a/Tools/DumpRenderTree/atk/AccessibilityNotificationHandlerAtk.cpp b/Tools/DumpRenderTree/atk/AccessibilityNotificationHandlerAtk.cpp
deleted file mode 100644
index 4565d5506..000000000
--- a/Tools/DumpRenderTree/atk/AccessibilityNotificationHandlerAtk.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2013 Samsung Electronics Inc. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include "AccessibilityNotificationHandlerAtk.h"
-
-#if HAVE(ACCESSIBILITY)
-
-#include "AccessibilityCallbacks.h"
-
-AccessibilityNotificationHandler::AccessibilityNotificationHandler(void)
- : m_platformElement(nullptr)
- , m_notificationFunctionCallback(nullptr)
-{
-}
-
-AccessibilityNotificationHandler::~AccessibilityNotificationHandler()
-{
- removeAccessibilityNotificationHandler(this);
- disconnectAccessibilityCallbacks();
-}
-
-void AccessibilityNotificationHandler::setNotificationFunctionCallback(JSObjectRef notificationFunctionCallback)
-{
- if (!notificationFunctionCallback) {
- removeAccessibilityNotificationHandler(this);
- disconnectAccessibilityCallbacks();
- return;
- }
-
- if (m_notificationFunctionCallback)
- removeAccessibilityNotificationHandler(this);
-
- m_notificationFunctionCallback = notificationFunctionCallback;
- connectAccessibilityCallbacks();
- addAccessibilityNotificationHandler(this);
-}
-
-#endif // HAVE(ACCESSIBILITY)
diff --git a/Tools/DumpRenderTree/atk/AccessibilityNotificationHandlerAtk.h b/Tools/DumpRenderTree/atk/AccessibilityNotificationHandlerAtk.h
deleted file mode 100644
index 9018e7290..000000000
--- a/Tools/DumpRenderTree/atk/AccessibilityNotificationHandlerAtk.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2013 Samsung Electronics Inc. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef AccessibilityNotificationHandlerAtk_h
-#define AccessibilityNotificationHandlerAtk_h
-
-#if HAVE(ACCESSIBILITY)
-
-#include <JavaScriptCore/JSObjectRef.h>
-#include <atk/atk.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
-
-class AccessibilityNotificationHandler : public RefCounted<AccessibilityNotificationHandler> {
-public:
- static PassRefPtr<AccessibilityNotificationHandler> create()
- {
- return adoptRef(new AccessibilityNotificationHandler());
- }
- AccessibilityNotificationHandler(void);
- ~AccessibilityNotificationHandler();
-
- void setPlatformElement(AtkObject* platformElement) { m_platformElement = platformElement; }
- AtkObject* platformElement(void) const { return m_platformElement; }
- void setNotificationFunctionCallback(JSObjectRef);
- JSObjectRef notificationFunctionCallback(void) const { return m_notificationFunctionCallback; }
-
-private:
- AtkObject* m_platformElement;
- JSObjectRef m_notificationFunctionCallback;
-};
-
-#endif // HAVE(ACCESSIBILITY)
-
-#endif // AccessibilityNotificationHandlerAtk_h
diff --git a/Tools/DumpRenderTree/atk/AccessibilityUIElementAtk.cpp b/Tools/DumpRenderTree/atk/AccessibilityUIElementAtk.cpp
deleted file mode 100644
index 41317bdd1..000000000
--- a/Tools/DumpRenderTree/atk/AccessibilityUIElementAtk.cpp
+++ /dev/null
@@ -1,1604 +0,0 @@
-/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
- * Copyright (C) 2009 Jan Michael Alonzo
- * Copyright (C) 2013 Samsung Electronics. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "AccessibilityUIElement.h"
-
-#if HAVE(ACCESSIBILITY)
-
-#include "AccessibilityNotificationHandlerAtk.h"
-#include <JavaScriptCore/JSStringRef.h>
-#include <JavaScriptCore/OpaqueJSString.h>
-#include <atk/atk.h>
-#include <wtf/Assertions.h>
-#include <wtf/gobject/GRefPtr.h>
-#include <wtf/gobject/GUniquePtr.h>
-#include <wtf/text/CString.h>
-#include <wtf/text/StringBuilder.h>
-#include <wtf/text/WTFString.h>
-#include <wtf/unicode/CharacterNames.h>
-
-namespace {
-
-enum AtkAttributeType {
- ObjectAttributeType,
- TextAttributeType
-};
-
-enum AttributeDomain {
- CoreDomain = 0,
- AtkDomain
-};
-
-enum AttributesIndex {
- // Attribute names.
- InvalidNameIndex = 0,
- PlaceholderNameIndex,
- SortNameIndex,
-
- // Attribute values.
- SortAscendingValueIndex,
- SortDescendingValueIndex,
- SortUnknownValueIndex,
-
- NumberOfAttributes
-};
-
-// Attribute names & Values (keep on sync with enum AttributesIndex).
-const String attributesMap[][2] = {
- // Attribute names.
- { "AXInvalid", "invalid" },
- { "AXPlaceholderValue", "placeholder-text" } ,
- { "AXSortDirection", "sort" },
-
- // Attribute values.
- { "AXAscendingSortDirection", "ascending" },
- { "AXDescendingSortDirection", "descending" },
- { "AXUnknownSortDirection", "unknown" }
-};
-
-#if ATK_CHECK_VERSION(2, 11, 3)
-const char* landmarkStringBanner = "AXLandmarkBanner";
-const char* landmarkStringComplementary = "AXLandmarkComplementary";
-const char* landmarkStringContentinfo = "AXLandmarkContentInfo";
-const char* landmarkStringMain = "AXLandmarkMain";
-const char* landmarkStringNavigation = "AXLandmarkNavigation";
-const char* landmarkStringSearch = "AXLandmarkSearch";
-#endif
-
-String jsStringToWTFString(JSStringRef attribute)
-{
- size_t bufferSize = JSStringGetMaximumUTF8CStringSize(attribute);
- GUniquePtr<gchar> buffer(static_cast<gchar*>(g_malloc(bufferSize)));
- JSStringGetUTF8CString(attribute, buffer.get(), bufferSize);
-
- return String::fromUTF8(buffer.get());
-}
-
-String coreAttributeToAtkAttribute(JSStringRef attribute)
-{
- String attributeString = jsStringToWTFString(attribute);
- for (int i = 0; i < NumberOfAttributes; ++i) {
- if (attributesMap[i][CoreDomain] == attributeString)
- return attributesMap[i][AtkDomain];
- }
-
- return attributeString;
-}
-
-String atkAttributeValueToCoreAttributeValue(AtkAttributeType type, const String& id, const String& value)
-{
- if (type == ObjectAttributeType) {
- // We need to translate ATK values exposed for 'aria-sort' (e.g. 'ascending')
- // into those expected by the layout tests (e.g. 'AXAscendingSortDirection').
- if (id == attributesMap[SortNameIndex][AtkDomain] && !value.isEmpty()) {
- if (value == attributesMap[SortAscendingValueIndex][AtkDomain])
- return attributesMap[SortAscendingValueIndex][CoreDomain];
- if (value == attributesMap[SortDescendingValueIndex][AtkDomain])
- return attributesMap[SortDescendingValueIndex][CoreDomain];
-
- return attributesMap[SortUnknownValueIndex][CoreDomain];
- }
- } else if (type == TextAttributeType) {
- // In case of 'aria-invalid' when the attribute empty or has "false" for ATK
- // it should not be mapped at all, but layout tests will expect 'false'.
- if (id == attributesMap[InvalidNameIndex][AtkDomain] && value.isEmpty())
- return "false";
- }
-
- return value;
-}
-
-AtkAttributeSet* getAttributeSet(AtkObject* accessible, AtkAttributeType type)
-{
- if (type == ObjectAttributeType)
- return atk_object_get_attributes(accessible);
-
- if (type == TextAttributeType) {
- if (!ATK_IS_TEXT(accessible))
- return nullptr;
-
- return atk_text_get_default_attributes(ATK_TEXT(accessible));
- }
-
- ASSERT_NOT_REACHED();
- return nullptr;
-}
-
-String getAttributeSetValueForId(AtkObject* accessible, AtkAttributeType type, String id)
-{
- AtkAttributeSet* attributeSet = getAttributeSet(accessible, type);
- if (!attributeSet)
- return String();
-
- String attributeValue;
- for (AtkAttributeSet* attributes = attributeSet; attributes; attributes = attributes->next) {
- AtkAttribute* atkAttribute = static_cast<AtkAttribute*>(attributes->data);
- if (id == atkAttribute->name) {
- attributeValue = String::fromUTF8(atkAttribute->value);
- break;
- }
- }
- atk_attribute_set_free(attributeSet);
-
- return atkAttributeValueToCoreAttributeValue(type, id, attributeValue);
-}
-
-String getAtkAttributeSetAsString(AtkObject* accessible, AtkAttributeType type)
-{
- AtkAttributeSet* attributeSet = getAttributeSet(accessible, type);
- if (!attributeSet)
- return String();
-
- StringBuilder builder;
- for (AtkAttributeSet* attributes = attributeSet; attributes; attributes = attributes->next) {
- AtkAttribute* attribute = static_cast<AtkAttribute*>(attributes->data);
- GUniquePtr<gchar> attributeData(g_strconcat(attribute->name, ":", attribute->value, NULL));
- builder.append(attributeData.get());
- if (attributes->next)
- builder.append(", ");
- }
- atk_attribute_set_free(attributeSet);
-
- return builder.toString();
-}
-
-const char* roleToString(AtkObject* object)
-{
- AtkRole role = atk_object_get_role(object);
-
-#if ATK_CHECK_VERSION(2, 11, 3)
- if (role == ATK_ROLE_LANDMARK) {
- String xmlRolesValue = getAttributeSetValueForId(object, ObjectAttributeType, "xml-roles");
- if (equalIgnoringCase(xmlRolesValue, "banner"))
- return landmarkStringBanner;
- if (equalIgnoringCase(xmlRolesValue, "complementary"))
- return landmarkStringComplementary;
- if (equalIgnoringCase(xmlRolesValue, "contentinfo"))
- return landmarkStringContentinfo;
- if (equalIgnoringCase(xmlRolesValue, "main"))
- return landmarkStringMain;
- if (equalIgnoringCase(xmlRolesValue, "navigation"))
- return landmarkStringNavigation;
- if (equalIgnoringCase(xmlRolesValue, "search"))
- return landmarkStringSearch;
- }
-#endif
-
- switch (role) {
- case ATK_ROLE_ALERT:
- return "AXAlert";
- case ATK_ROLE_DIALOG:
- return "AXDialog";
- case ATK_ROLE_CANVAS:
- return "AXCanvas";
- case ATK_ROLE_CHECK_BOX:
- return "AXCheckBox";
- case ATK_ROLE_COLOR_CHOOSER:
- return "AXColorWell";
- case ATK_ROLE_COLUMN_HEADER:
- return "AXColumnHeader";
- case ATK_ROLE_COMBO_BOX:
- return "AXComboBox";
- case ATK_ROLE_COMMENT:
- return "AXComment";
- case ATK_ROLE_DOCUMENT_FRAME:
- return "AXDocument";
- case ATK_ROLE_DOCUMENT_WEB:
- return "AXWebArea";
- case ATK_ROLE_EMBEDDED:
- return "AXEmbedded";
- case ATK_ROLE_ENTRY:
- return "AXTextField";
- case ATK_ROLE_FOOTER:
- return "AXFooter";
- case ATK_ROLE_FORM:
- return "AXForm";
- case ATK_ROLE_GROUPING:
- return "AXGroup";
- case ATK_ROLE_HEADING:
- return "AXHeading";
- case ATK_ROLE_IMAGE:
- return "AXImage";
- case ATK_ROLE_IMAGE_MAP:
- return "AXImageMap";
- case ATK_ROLE_LABEL:
- return "AXLabel";
- case ATK_ROLE_LINK:
- return "AXLink";
- case ATK_ROLE_LIST:
- return "AXList";
- case ATK_ROLE_LIST_BOX:
- return "AXListBox";
- case ATK_ROLE_LIST_ITEM:
- return "AXListItem";
- case ATK_ROLE_MENU:
- return "AXMenu";
- case ATK_ROLE_MENU_BAR:
- return "AXMenuBar";
- case ATK_ROLE_MENU_ITEM:
- return "AXMenuItem";
- case ATK_ROLE_PAGE_TAB:
- return "AXTab";
- case ATK_ROLE_PAGE_TAB_LIST:
- return "AXTabGroup";
- case ATK_ROLE_PANEL:
- return "AXGroup";
- case ATK_ROLE_PARAGRAPH:
- return "AXParagraph";
- case ATK_ROLE_PASSWORD_TEXT:
- return "AXPasswordField";
- case ATK_ROLE_PROGRESS_BAR:
- return "AXProgressIndicator";
- case ATK_ROLE_PUSH_BUTTON:
- return "AXButton";
- case ATK_ROLE_RADIO_BUTTON:
- return "AXRadioButton";
- case ATK_ROLE_RADIO_MENU_ITEM:
- return "AXRadioMenuItem";
- case ATK_ROLE_ROW_HEADER:
- return "AXRowHeader";
- case ATK_ROLE_CHECK_MENU_ITEM:
- return "AXCheckMenuItem";
- case ATK_ROLE_RULER:
- return "AXRuler";
- case ATK_ROLE_SCROLL_BAR:
- return "AXScrollBar";
- case ATK_ROLE_SCROLL_PANE:
- return "AXScrollArea";
- case ATK_ROLE_SECTION:
- return "AXSection";
- case ATK_ROLE_SEPARATOR:
- return "AXSeparator";
- case ATK_ROLE_SLIDER:
- return "AXSlider";
- case ATK_ROLE_SPIN_BUTTON:
- return "AXSpinButton";
- case ATK_ROLE_STATUSBAR:
- return "AXStatusBar";
- case ATK_ROLE_TABLE:
- return "AXTable";
- case ATK_ROLE_TABLE_CELL:
- return "AXCell";
- case ATK_ROLE_TABLE_COLUMN_HEADER:
- return "AXColumnHeader";
- case ATK_ROLE_TABLE_ROW:
- return "AXRow";
- case ATK_ROLE_TABLE_ROW_HEADER:
- return "AXRowHeader";
- case ATK_ROLE_TOGGLE_BUTTON:
- return "AXToggleButton";
- case ATK_ROLE_TOOL_BAR:
- return "AXToolbar";
- case ATK_ROLE_TOOL_TIP:
- return "AXUserInterfaceTooltip";
- case ATK_ROLE_TREE:
- return "AXTree";
- case ATK_ROLE_TREE_TABLE:
- return "AXTreeGrid";
- case ATK_ROLE_TREE_ITEM:
- return "AXTreeItem";
- case ATK_ROLE_WINDOW:
- return "AXWindow";
- case ATK_ROLE_UNKNOWN:
- return "AXUnknown";
-#if ATK_CHECK_VERSION(2, 11, 3)
- case ATK_ROLE_ARTICLE:
- return "AXArticle";
- case ATK_ROLE_DEFINITION:
- return "AXDefinition";
- case ATK_ROLE_LOG:
- return "AXLog";
- case ATK_ROLE_MARQUEE:
- return "AXMarquee";
- case ATK_ROLE_MATH:
- return "AXMath";
- case ATK_ROLE_TIMER:
- return "AXTimer";
-#endif
-#if ATK_CHECK_VERSION(2, 11, 4)
- case ATK_ROLE_DESCRIPTION_LIST:
- return "AXDescriptionList";
- case ATK_ROLE_DESCRIPTION_TERM:
- return "AXDescriptionTerm";
- case ATK_ROLE_DESCRIPTION_VALUE:
- return "AXDescriptionValue";
-#endif
- default:
- // We want to distinguish ATK_ROLE_UNKNOWN from a known AtkRole which
- // our DRT isn't properly handling.
- return "FIXME not identified";
- }
-}
-
-inline gchar* replaceCharactersForResults(gchar* str)
-{
- String uString = String::fromUTF8(str);
-
- // The object replacement character is passed along to ATs so we need to be
- // able to test for their presence and do so without causing test failures.
- uString.replace(objectReplacementCharacter, "<obj>");
-
- // The presence of newline characters in accessible text of a single object
- // is appropriate, but it makes test results (especially the accessible tree)
- // harder to read.
- uString.replace("\n", "<\\n>");
-
- return g_strdup(uString.utf8().data());
-}
-
-bool checkElementState(PlatformUIElement element, AtkStateType stateType)
-{
- if (!ATK_IS_OBJECT(element))
- return false;
-
- GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(element)));
- return atk_state_set_contains_state(stateSet.get(), stateType);
-}
-
-String attributesOfElement(AccessibilityUIElement* element)
-{
- StringBuilder builder;
-
- builder.append(String::format("%s\n", element->role()->string().utf8().data()));
-
- // For the parent we print its role and its name, if available.
- builder.append("AXParent: ");
- AccessibilityUIElement parent = element->parentElement();
- if (AtkObject* atkParent = parent.platformUIElement()) {
- builder.append(roleToString(atkParent));
- const char* parentName = atk_object_get_name(atkParent);
- if (parentName && g_utf8_strlen(parentName, -1))
- builder.append(String::format(": %s", parentName));
- } else
- builder.append("(null)");
- builder.append("\n");
-
- builder.append(String::format("AXChildren: %d\n", element->childrenCount()));
- builder.append(String::format("AXPosition: { %f, %f }\n", element->x(), element->y()));
- builder.append(String::format("AXSize: { %f, %f }\n", element->width(), element->height()));
-
- String title = element->title()->string();
- if (!title.isEmpty())
- builder.append(String::format("%s\n", title.utf8().data()));
-
- String description = element->description()->string();
- if (!description.isEmpty())
- builder.append(String::format("%s\n", description.utf8().data()));
-
- String value = element->stringValue()->string();
- if (!value.isEmpty())
- builder.append(String::format("%s\n", value.utf8().data()));
-
- builder.append(String::format("AXFocusable: %d\n", element->isFocusable()));
- builder.append(String::format("AXFocused: %d\n", element->isFocused()));
- builder.append(String::format("AXSelectable: %d\n", element->isSelectable()));
- builder.append(String::format("AXSelected: %d\n", element->isSelected()));
- builder.append(String::format("AXMultiSelectable: %d\n", element->isMultiSelectable()));
- builder.append(String::format("AXEnabled: %d\n", element->isEnabled()));
- builder.append(String::format("AXExpanded: %d\n", element->isExpanded()));
- builder.append(String::format("AXRequired: %d\n", element->isRequired()));
- builder.append(String::format("AXChecked: %d\n", element->isChecked()));
-
- String url = element->url()->string();
- if (!url.isEmpty())
- builder.append(String::format("%s\n", url.utf8().data()));
-
- // We append the ATK specific attributes as a single line at the end.
- builder.append("AXPlatformAttributes: ");
- builder.append(getAtkAttributeSetAsString(element->platformUIElement(), ObjectAttributeType));
-
- return builder.toString();
-}
-
-static JSStringRef createStringWithAttributes(const Vector<AccessibilityUIElement>& elements)
-{
- StringBuilder builder;
-
- for (Vector<AccessibilityUIElement>::const_iterator it = elements.begin(); it != elements.end(); ++it) {
- builder.append(attributesOfElement(const_cast<AccessibilityUIElement*>(it)));
- builder.append("\n------------\n");
- }
-
- return JSStringCreateWithUTF8CString(builder.toString().utf8().data());
-}
-
-static Vector<AccessibilityUIElement> getRowHeaders(AtkTable* accessible)
-{
- Vector<AccessibilityUIElement> rowHeaders;
-
- int rowsCount = atk_table_get_n_rows(accessible);
- for (int row = 0; row < rowsCount; ++row)
- rowHeaders.append(AccessibilityUIElement(atk_table_get_row_header(accessible, row)));
-
- return rowHeaders;
-}
-
-static Vector<AccessibilityUIElement> getColumnHeaders(AtkTable* accessible)
-{
- Vector<AccessibilityUIElement> columnHeaders;
-
- int columnsCount = atk_table_get_n_columns(accessible);
- for (int column = 0; column < columnsCount; ++column)
- columnHeaders.append(AccessibilityUIElement(atk_table_get_column_header(accessible, column)));
-
- return columnHeaders;
-}
-
-static Vector<AccessibilityUIElement> getVisibleCells(AccessibilityUIElement* element)
-{
- Vector<AccessibilityUIElement> visibleCells;
-
- AtkTable* accessible = ATK_TABLE(element->platformUIElement());
- int rowsCount = atk_table_get_n_rows(accessible);
- int columnsCount = atk_table_get_n_columns(accessible);
-
- for (int row = 0; row < rowsCount; ++row) {
- for (int column = 0; column < columnsCount; ++column)
- visibleCells.append(element->cellForColumnAndRow(column, row));
- }
-
- return visibleCells;
-}
-
-} // namespace
-
-JSStringRef indexRangeInTable(PlatformUIElement element, bool isRowRange)
-{
- GUniquePtr<gchar> rangeString(g_strdup("{0, 0}"));
-
- if (!ATK_IS_OBJECT(element))
- return JSStringCreateWithUTF8CString(rangeString.get());
-
- AtkObject* axTable = atk_object_get_parent(ATK_OBJECT(element));
- if (!axTable || !ATK_IS_TABLE(axTable))
- return JSStringCreateWithUTF8CString(rangeString.get());
-
- // Look for the cell in the table.
- gint indexInParent = atk_object_get_index_in_parent(ATK_OBJECT(element));
- if (indexInParent == -1)
- return JSStringCreateWithUTF8CString(rangeString.get());
-
- int row = -1;
- int column = -1;
- row = atk_table_get_row_at_index(ATK_TABLE(axTable), indexInParent);
- column = atk_table_get_column_at_index(ATK_TABLE(axTable), indexInParent);
-
- // Get the actual values, if row and columns are valid values.
- if (row != -1 && column != -1) {
- int base = 0;
- int length = 0;
- if (isRowRange) {
- base = row;
- length = atk_table_get_row_extent_at(ATK_TABLE(axTable), row, column);
- } else {
- base = column;
- length = atk_table_get_column_extent_at(ATK_TABLE(axTable), row, column);
- }
- rangeString.reset(g_strdup_printf("{%d, %d}", base, length));
- }
-
- return JSStringCreateWithUTF8CString(rangeString.get());
-}
-
-void alterCurrentValue(PlatformUIElement element, int factor)
-{
- if (!ATK_IS_VALUE(element))
- return;
-
- GValue currentValue = G_VALUE_INIT;
- atk_value_get_current_value(ATK_VALUE(element), &currentValue);
-
- GValue increment = G_VALUE_INIT;
- atk_value_get_minimum_increment(ATK_VALUE(element), &increment);
-
- GValue newValue = G_VALUE_INIT;
- g_value_init(&newValue, G_TYPE_FLOAT);
-
- g_value_set_float(&newValue, g_value_get_float(&currentValue) + factor * g_value_get_float(&increment));
- atk_value_set_current_value(ATK_VALUE(element), &newValue);
-
- g_value_unset(&newValue);
- g_value_unset(&increment);
- g_value_unset(&currentValue);
-}
-
-AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element)
- : m_element(element)
-{
- if (m_element)
- g_object_ref(m_element);
-}
-
-AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other)
- : m_element(other.m_element)
-{
- if (m_element)
- g_object_ref(m_element);
-}
-
-AccessibilityUIElement::~AccessibilityUIElement()
-{
- if (m_element)
- g_object_unref(m_element);
-}
-
-void AccessibilityUIElement::getLinkedUIElements(Vector<AccessibilityUIElement>& elements)
-{
- // FIXME: implement
-}
-
-void AccessibilityUIElement::getDocumentLinks(Vector<AccessibilityUIElement>&)
-{
- // FIXME: implement
-}
-
-void AccessibilityUIElement::getChildren(Vector<AccessibilityUIElement>& children)
-{
- if (!ATK_IS_OBJECT(m_element))
- return;
-
- int count = childrenCount();
- for (int i = 0; i < count; i++) {
- AtkObject* child = atk_object_ref_accessible_child(ATK_OBJECT(m_element), i);
- children.append(AccessibilityUIElement(child));
- }
-}
-
-void AccessibilityUIElement::getChildrenWithRange(Vector<AccessibilityUIElement>& elementVector, unsigned start, unsigned end)
-{
- if (!ATK_IS_OBJECT(m_element))
- return;
-
- for (unsigned i = start; i < end; i++) {
- AtkObject* child = atk_object_ref_accessible_child(ATK_OBJECT(m_element), i);
- elementVector.append(AccessibilityUIElement(child));
- }
-}
-
-int AccessibilityUIElement::rowCount()
-{
- if (!ATK_IS_TABLE(m_element))
- return 0;
-
- return atk_table_get_n_rows(ATK_TABLE(m_element));
-}
-
-int AccessibilityUIElement::columnCount()
-{
- if (!ATK_IS_TABLE(m_element))
- return 0;
-
- return atk_table_get_n_columns(ATK_TABLE(m_element));
-}
-
-int AccessibilityUIElement::childrenCount()
-{
- if (!ATK_IS_OBJECT(m_element))
- return 0;
-
- return atk_object_get_n_accessible_children(ATK_OBJECT(m_element));
-}
-
-AccessibilityUIElement AccessibilityUIElement::elementAtPoint(int x, int y)
-{
- if (!ATK_IS_COMPONENT(m_element))
- return nullptr;
-
- GRefPtr<AtkObject> objectAtPoint = adoptGRef(atk_component_ref_accessible_at_point(ATK_COMPONENT(m_element), x, y, ATK_XY_WINDOW));
- return AccessibilityUIElement(objectAtPoint ? objectAtPoint.get() : m_element);
-}
-
-AccessibilityUIElement AccessibilityUIElement::linkedUIElementAtIndex(unsigned index)
-{
- // FIXME: implement
- return nullptr;
-}
-
-AccessibilityUIElement AccessibilityUIElement::getChildAtIndex(unsigned index)
-{
- if (!ATK_IS_OBJECT(m_element))
- return nullptr;
-
- Vector<AccessibilityUIElement> children;
- getChildrenWithRange(children, index, index + 1);
-
- if (children.size() == 1)
- return children.at(0);
-
- return nullptr;
-}
-
-unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element)
-{
- // FIXME: implement
- return 0;
-}
-
-JSStringRef AccessibilityUIElement::allAttributes()
-{
- if (!ATK_IS_OBJECT(m_element))
- return JSStringCreateWithCharacters(0, 0);
-
- return JSStringCreateWithUTF8CString(attributesOfElement(this).utf8().data());
-}
-
-JSStringRef AccessibilityUIElement::attributesOfLinkedUIElements()
-{
- // FIXME: implement
- return JSStringCreateWithCharacters(0, 0);
-}
-
-JSStringRef AccessibilityUIElement::attributesOfDocumentLinks()
-{
- // FIXME: implement
- return JSStringCreateWithCharacters(0, 0);
-}
-
-AccessibilityUIElement AccessibilityUIElement::titleUIElement()
-{
- if (!ATK_IS_OBJECT(m_element))
- return nullptr;
-
- AtkRelationSet* set = atk_object_ref_relation_set(ATK_OBJECT(m_element));
- if (!set)
- return nullptr;
-
- AtkObject* target = nullptr;
- int count = atk_relation_set_get_n_relations(set);
- for (int i = 0; i < count; i++) {
- AtkRelation* relation = atk_relation_set_get_relation(set, i);
- if (atk_relation_get_relation_type(relation) == ATK_RELATION_LABELLED_BY) {
- GPtrArray* targetList = atk_relation_get_target(relation);
- if (targetList->len)
- target = static_cast<AtkObject*>(g_ptr_array_index(targetList, 0));
- }
- }
-
- g_object_unref(set);
- return target ? AccessibilityUIElement(target) : nullptr;
-}
-
-AccessibilityUIElement AccessibilityUIElement::parentElement()
-{
- if (!ATK_IS_OBJECT(m_element))
- return nullptr;
-
- AtkObject* parent = atk_object_get_parent(ATK_OBJECT(m_element));
- return parent ? AccessibilityUIElement(parent) : nullptr;
-}
-
-JSStringRef AccessibilityUIElement::attributesOfChildren()
-{
- if (!ATK_IS_OBJECT(m_element))
- return JSStringCreateWithCharacters(0, 0);
-
- Vector<AccessibilityUIElement> children;
- getChildren(children);
-
- return createStringWithAttributes(children);
-}
-
-JSStringRef AccessibilityUIElement::parameterizedAttributeNames()
-{
- // FIXME: implement
- return JSStringCreateWithCharacters(0, 0);
-}
-
-JSStringRef AccessibilityUIElement::role()
-{
- if (!ATK_IS_OBJECT(m_element))
- return JSStringCreateWithCharacters(0, 0);
-
- if (!atk_object_get_role(ATK_OBJECT(m_element)))
- return JSStringCreateWithCharacters(0, 0);
-
- GUniquePtr<char> roleStringWithPrefix(g_strdup_printf("AXRole: %s", roleToString(ATK_OBJECT(m_element))));
- return JSStringCreateWithUTF8CString(roleStringWithPrefix.get());
-}
-
-JSStringRef AccessibilityUIElement::subrole()
-{
- return nullptr;
-}
-
-JSStringRef AccessibilityUIElement::roleDescription()
-{
- return nullptr;
-}
-
-JSStringRef AccessibilityUIElement::title()
-{
- if (!ATK_IS_OBJECT(m_element))
- return JSStringCreateWithCharacters(0, 0);
-
- const gchar* name = atk_object_get_name(ATK_OBJECT(m_element));
- GUniquePtr<gchar> axTitle(g_strdup_printf("AXTitle: %s", name ? name : ""));
-
- return JSStringCreateWithUTF8CString(axTitle.get());
-}
-
-JSStringRef AccessibilityUIElement::description()
-{
- if (!ATK_IS_OBJECT(m_element))
- return JSStringCreateWithCharacters(0, 0);
-
- const gchar* description = atk_object_get_description(ATK_OBJECT(m_element));
- if (!description)
- return JSStringCreateWithCharacters(0, 0);
-
- GUniquePtr<gchar> axDesc(g_strdup_printf("AXDescription: %s", description));
-
- return JSStringCreateWithUTF8CString(axDesc.get());
-}
-
-JSStringRef AccessibilityUIElement::stringValue()
-{
- if (!ATK_IS_TEXT(m_element))
- return JSStringCreateWithCharacters(0, 0);
-
- GUniquePtr<gchar> text(atk_text_get_text(ATK_TEXT(m_element), 0, -1));
- GUniquePtr<gchar> textWithReplacedCharacters(replaceCharactersForResults(text.get()));
- GUniquePtr<gchar> axValue(g_strdup_printf("AXValue: %s", textWithReplacedCharacters.get()));
-
- return JSStringCreateWithUTF8CString(axValue.get());
-}
-
-JSStringRef AccessibilityUIElement::language()
-{
- if (!ATK_IS_OBJECT(m_element))
- return JSStringCreateWithCharacters(0, 0);
-
- const gchar* locale = atk_object_get_object_locale(ATK_OBJECT(m_element));
- if (!locale)
- return JSStringCreateWithCharacters(0, 0);
-
- GUniquePtr<char> axValue(g_strdup_printf("AXLanguage: %s", locale));
- return JSStringCreateWithUTF8CString(axValue.get());
-}
-
-JSStringRef AccessibilityUIElement::helpText() const
-{
- if (!ATK_IS_OBJECT(m_element))
- return JSStringCreateWithCharacters(0, 0);
-
- AtkRelationSet* relationSet = atk_object_ref_relation_set(ATK_OBJECT(m_element));
- if (!relationSet)
- return nullptr;
-
- AtkRelation* relation = atk_relation_set_get_relation_by_type(relationSet, ATK_RELATION_DESCRIBED_BY);
- if (!relation)
- return nullptr;
-
- GPtrArray* targetList = atk_relation_get_target(relation);
- if (!targetList || !targetList->len)
- return nullptr;
-
- StringBuilder builder;
- builder.append("AXHelp: ");
-
- for (int targetCount = 0; targetCount < targetList->len; targetCount++) {
- if (AtkObject* target = static_cast<AtkObject*>(g_ptr_array_index(targetList, targetCount))) {
- GUniquePtr<gchar> text(atk_text_get_text(ATK_TEXT(target), 0, -1));
- if (!builder.isEmpty())
- builder.append(" ");
- builder.append(text.get());
- }
- }
-
- g_object_unref(relationSet);
-
- return JSStringCreateWithUTF8CString(builder.toString().utf8().data());
-
-}
-
-double AccessibilityUIElement::x()
-{
- if (!ATK_IS_COMPONENT(m_element))
- return 0;
-
- int x, y;
- atk_component_get_position(ATK_COMPONENT(m_element), &x, &y, ATK_XY_SCREEN);
-
- return x;
-}
-
-double AccessibilityUIElement::y()
-{
- if (!ATK_IS_COMPONENT(m_element))
- return 0;
-
- int x, y;
- atk_component_get_position(ATK_COMPONENT(m_element), &x, &y, ATK_XY_SCREEN);
-
- return y;
-}
-
-double AccessibilityUIElement::width()
-{
- if (!ATK_IS_COMPONENT(m_element))
- return 0;
-
- int width, height;
- atk_component_get_size(ATK_COMPONENT(m_element), &width, &height);
-
- return width;
-}
-
-double AccessibilityUIElement::height()
-{
- if (!ATK_IS_COMPONENT(m_element))
- return 0;
-
- int width, height;
- atk_component_get_size(ATK_COMPONENT(m_element), &width, &height);
-
- return height;
-}
-
-double AccessibilityUIElement::clickPointX()
-{
- if (!ATK_IS_COMPONENT(m_element))
- return 0;
-
- int x, y;
- atk_component_get_position(ATK_COMPONENT(m_element), &x, &y, ATK_XY_WINDOW);
-
- int width, height;
- atk_component_get_size(ATK_COMPONENT(m_element), &width, &height);
-
- return x + width / 2.0;
-}
-
-double AccessibilityUIElement::clickPointY()
-{
- if (!ATK_IS_COMPONENT(m_element))
- return 0;
-
- int x, y;
- atk_component_get_position(ATK_COMPONENT(m_element), &x, &y, ATK_XY_WINDOW);
-
- int width, height;
- atk_component_get_size(ATK_COMPONENT(m_element), &width, &height);
-
- return y + height / 2.0;
-}
-
-JSStringRef AccessibilityUIElement::orientation() const
-{
- if (!ATK_IS_OBJECT(m_element))
- return JSStringCreateWithCharacters(0, 0);
-
- const char* axOrientation = nullptr;
- if (checkElementState(m_element, ATK_STATE_HORIZONTAL))
- axOrientation = "AXOrientation: AXHorizontalOrientation";
- else if (checkElementState(m_element, ATK_STATE_VERTICAL))
- axOrientation = "AXOrientation: AXVerticalOrientation";
-
- if (!axOrientation)
- return JSStringCreateWithCharacters(0, 0);
-
- return JSStringCreateWithUTF8CString(axOrientation);
-}
-
-double AccessibilityUIElement::intValue() const
-{
- if (!ATK_IS_OBJECT(m_element))
- return 0;
-
- if (ATK_IS_VALUE(m_element)) {
- GValue value = G_VALUE_INIT;
- atk_value_get_current_value(ATK_VALUE(m_element), &value);
- if (!G_VALUE_HOLDS_FLOAT(&value))
- return 0;
- return g_value_get_float(&value);
- }
-
- // Consider headings as an special case when returning the "int value" of
- // an AccessibilityUIElement, so we can reuse some tests to check the level
- // both for HTML headings and objects with the aria-level attribute.
- if (atk_object_get_role(ATK_OBJECT(m_element)) == ATK_ROLE_HEADING) {
- String headingLevel = getAttributeSetValueForId(ATK_OBJECT(m_element), ObjectAttributeType, "level");
- bool ok;
- double headingLevelValue = headingLevel.toDouble(&ok);
- if (ok)
- return headingLevelValue;
- }
-
- return 0;
-}
-
-double AccessibilityUIElement::minValue()
-{
- if (!ATK_IS_VALUE(m_element))
- return 0;
-
- GValue value = G_VALUE_INIT;
- atk_value_get_minimum_value(ATK_VALUE(m_element), &value);
- if (!G_VALUE_HOLDS_FLOAT(&value))
- return 0;
- return g_value_get_float(&value);
-}
-
-double AccessibilityUIElement::maxValue()
-{
- if (!ATK_IS_VALUE(m_element))
- return 0;
-
- GValue value = G_VALUE_INIT;
- atk_value_get_maximum_value(ATK_VALUE(m_element), &value);
- if (!G_VALUE_HOLDS_FLOAT(&value))
- return 0;
- return g_value_get_float(&value);
-}
-
-JSStringRef AccessibilityUIElement::valueDescription()
-{
- // FIXME: implement after it has been implemented in ATK.
- // See: https://bugzilla.gnome.org/show_bug.cgi?id=684576
- return JSStringCreateWithCharacters(0, 0);
-}
-
-bool AccessibilityUIElement::isEnabled()
-{
- return checkElementState(m_element, ATK_STATE_ENABLED);
-}
-
-int AccessibilityUIElement::insertionPointLineNumber()
-{
- // FIXME: implement
- return 0;
-}
-
-bool AccessibilityUIElement::isPressActionSupported()
-{
- if (!ATK_IS_ACTION(m_element))
- return false;
-
- const gchar* actionName = atk_action_get_name(ATK_ACTION(m_element), 0);
- return equalIgnoringCase(actionName, String("press")) || equalIgnoringCase(actionName, String("jump"));
-}
-
-bool AccessibilityUIElement::isIncrementActionSupported()
-{
- // FIXME: implement
- return false;
-}
-
-bool AccessibilityUIElement::isDecrementActionSupported()
-{
- // FIXME: implement
- return false;
-}
-
-bool AccessibilityUIElement::isRequired() const
-{
- return checkElementState(m_element, ATK_STATE_REQUIRED);
-}
-
-bool AccessibilityUIElement::isFocused() const
-{
- if (!ATK_IS_OBJECT(m_element))
- return false;
-
- GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(m_element)));
- gboolean isFocused = atk_state_set_contains_state(stateSet.get(), ATK_STATE_FOCUSED);
-
- return isFocused;
-}
-
-bool AccessibilityUIElement::isSelected() const
-{
- return checkElementState(m_element, ATK_STATE_SELECTED);
-}
-
-int AccessibilityUIElement::hierarchicalLevel() const
-{
- // FIXME: implement
- return 0;
-}
-
-bool AccessibilityUIElement::ariaIsGrabbed() const
-{
- return false;
-}
-
-JSStringRef AccessibilityUIElement::ariaDropEffects() const
-{
- return nullptr;
-}
-
-bool AccessibilityUIElement::isExpanded() const
-{
- if (!ATK_IS_OBJECT(m_element))
- return false;
-
- GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(m_element)));
- gboolean isExpanded = atk_state_set_contains_state(stateSet.get(), ATK_STATE_EXPANDED);
-
- return isExpanded;
-}
-
-bool AccessibilityUIElement::isChecked() const
-{
- if (!ATK_IS_OBJECT(m_element))
- return false;
-
- GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(m_element)));
- gboolean isChecked = atk_state_set_contains_state(stateSet.get(), ATK_STATE_CHECKED);
-
- return isChecked;
-}
-
-bool AccessibilityUIElement::isIndeterminate() const
-{
- if (!ATK_IS_OBJECT(m_element))
- return false;
-
- GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(m_element)));
- return atk_state_set_contains_state(stateSet.get(), ATK_STATE_INDETERMINATE);
-}
-
-JSStringRef AccessibilityUIElement::attributesOfColumnHeaders()
-{
- if (!ATK_IS_TABLE(m_element))
- return JSStringCreateWithCharacters(0, 0);
-
- Vector<AccessibilityUIElement> columnHeaders = getColumnHeaders(ATK_TABLE(m_element));
- return createStringWithAttributes(columnHeaders);
-}
-
-JSStringRef AccessibilityUIElement::attributesOfRowHeaders()
-{
- if (!ATK_IS_TABLE(m_element))
- return JSStringCreateWithCharacters(0, 0);
-
- Vector<AccessibilityUIElement> rowHeaders = getRowHeaders(ATK_TABLE(m_element));
- return createStringWithAttributes(rowHeaders);
-}
-
-JSStringRef AccessibilityUIElement::attributesOfColumns()
-{
- // FIXME: implement
- return JSStringCreateWithCharacters(0, 0);
-}
-
-JSStringRef AccessibilityUIElement::attributesOfRows()
-{
- // FIXME: implement
- return JSStringCreateWithCharacters(0, 0);
-}
-
-JSStringRef AccessibilityUIElement::attributesOfVisibleCells()
-{
- if (!ATK_IS_TABLE(m_element))
- return JSStringCreateWithCharacters(0, 0);
-
- Vector<AccessibilityUIElement> visibleCells = getVisibleCells(this);
- return createStringWithAttributes(visibleCells);
-}
-
-JSStringRef AccessibilityUIElement::attributesOfHeader()
-{
- // FIXME: implement
- return JSStringCreateWithCharacters(0, 0);
-}
-
-int AccessibilityUIElement::indexInTable()
-{
- // FIXME: implement
- return 0;
-}
-
-JSStringRef AccessibilityUIElement::rowIndexRange()
-{
- // Range in table for rows.
- return indexRangeInTable(m_element, true);
-}
-
-JSStringRef AccessibilityUIElement::columnIndexRange()
-{
- // Range in table for columns.
- return indexRangeInTable(m_element, false);
-}
-
-int AccessibilityUIElement::lineForIndex(int index)
-{
- if (!ATK_IS_TEXT(m_element))
- return -1;
-
- if (index < 0 || index > atk_text_get_character_count(ATK_TEXT(m_element)))
- return -1;
-
- GUniquePtr<gchar> text(atk_text_get_text(ATK_TEXT(m_element), 0, index));
- int lineNo = 0;
- for (gchar* offset = text.get(); *offset; ++offset) {
- if (*offset == '\n')
- ++lineNo;
- }
-
- return lineNo;
-}
-
-JSStringRef AccessibilityUIElement::boundsForRange(unsigned location, unsigned length)
-{
- // FIXME: implement
- return JSStringCreateWithCharacters(0, 0);
-}
-
-JSStringRef AccessibilityUIElement::stringForRange(unsigned location, unsigned length)
-{
- if (!ATK_IS_TEXT(m_element))
- return JSStringCreateWithCharacters(0, 0);
-
- String string = atk_text_get_text(ATK_TEXT(m_element), location, location + length);
- return JSStringCreateWithUTF8CString(string.utf8().data());
-}
-
-JSStringRef AccessibilityUIElement::attributedStringForRange(unsigned, unsigned)
-{
- // FIXME: implement
- return JSStringCreateWithCharacters(0, 0);
-}
-
-bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location, unsigned length)
-{
- // FIXME: implement
- return false;
-}
-
-unsigned AccessibilityUIElement::uiElementCountForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly)
-{
- // FIXME: implement
- return 0;
-}
-
-AccessibilityUIElement AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly)
-{
- // FIXME: implement
- return nullptr;
-}
-
-AccessibilityUIElement AccessibilityUIElement::cellForColumnAndRow(unsigned column, unsigned row)
-{
- if (!ATK_IS_TABLE(m_element))
- return nullptr;
-
- // Adopt the AtkObject representing the cell because
- // at_table_ref_at() transfers full ownership.
- GRefPtr<AtkObject> foundCell = adoptGRef(atk_table_ref_at(ATK_TABLE(m_element), row, column));
- return foundCell ? AccessibilityUIElement(foundCell.get()) : nullptr;
-}
-
-JSStringRef AccessibilityUIElement::selectedTextRange()
-{
- if (!ATK_IS_TEXT(m_element))
- return JSStringCreateWithCharacters(0, 0);
-
- gint start, end;
- g_free(atk_text_get_selection(ATK_TEXT(m_element), 0, &start, &end));
-
- GUniquePtr<gchar> selection(g_strdup_printf("{%d, %d}", start, end - start));
- return JSStringCreateWithUTF8CString(selection.get());
-}
-
-void AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length)
-{
- if (!ATK_IS_TEXT(m_element))
- return;
-
- atk_text_set_selection(ATK_TEXT(m_element), 0, location, location + length);
-}
-
-JSStringRef AccessibilityUIElement::stringAttributeValue(JSStringRef attribute)
-{
- if (!ATK_IS_OBJECT(m_element))
- return JSStringCreateWithCharacters(0, 0);
-
- String atkAttributeName = coreAttributeToAtkAttribute(attribute);
-
- // Try object attributes first.
- String attributeValue = getAttributeSetValueForId(ATK_OBJECT(m_element), ObjectAttributeType, atkAttributeName);
-
- // Try text attributes if the requested one was not found and we have an AtkText object.
- if (attributeValue.isEmpty() && ATK_IS_TEXT(m_element))
- attributeValue = getAttributeSetValueForId(ATK_OBJECT(m_element), TextAttributeType, atkAttributeName);
-
- // Additional check to make sure that the exposure of the state ATK_STATE_INVALID_ENTRY
- // is consistent with the exposure of aria-invalid as a text attribute, if present.
- if (atkAttributeName == attributesMap[InvalidNameIndex][AtkDomain]) {
- bool isInvalidState = checkElementState(m_element, ATK_STATE_INVALID_ENTRY);
- if (attributeValue.isEmpty())
- return JSStringCreateWithUTF8CString(isInvalidState ? "true" : "false");
-
- // If the text attribute was there, check that it's consistent with
- // what the state says or force the test to fail otherwise.
- bool isAriaInvalid = attributeValue != "false";
- if (isInvalidState != isAriaInvalid)
- return JSStringCreateWithCharacters(0, 0);
- }
-
- return JSStringCreateWithUTF8CString(attributeValue.utf8().data());
-}
-
-double AccessibilityUIElement::numberAttributeValue(JSStringRef attribute)
-{
- // FIXME: implement
- return 0;
-}
-
-bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute)
-{
- // FIXME: implement
- return false;
-}
-
-bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute)
-{
- if (!ATK_IS_OBJECT(m_element))
- return false;
-
- String attributeString = jsStringToWTFString(attribute);
- if (attributeString == "AXValue")
- return checkElementState(m_element, ATK_STATE_EDITABLE);
-
- return false;
-}
-
-bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute)
-{
- if (!ATK_IS_OBJECT(m_element))
- return false;
-
- String atkAttributeName = coreAttributeToAtkAttribute(attribute);
- if (atkAttributeName.isEmpty())
- return false;
-
- // For now, an attribute is supported whether it's exposed as a object or a text attribute.
- String attributeValue = getAttributeSetValueForId(ATK_OBJECT(m_element), ObjectAttributeType, atkAttributeName);
- if (attributeValue.isEmpty())
- attributeValue = getAttributeSetValueForId(ATK_OBJECT(m_element), TextAttributeType, atkAttributeName);
-
- return !attributeValue.isEmpty();
-}
-
-void AccessibilityUIElement::increment()
-{
- alterCurrentValue(m_element, 1);
-}
-
-void AccessibilityUIElement::decrement()
-{
- alterCurrentValue(m_element, -1);
-}
-
-void AccessibilityUIElement::press()
-{
- if (!ATK_IS_ACTION(m_element))
- return;
-
- // Only one action per object is supported so far.
- atk_action_do_action(ATK_ACTION(m_element), 0);
-}
-
-void AccessibilityUIElement::showMenu()
-{
- // FIXME: implement
-}
-
-AccessibilityUIElement AccessibilityUIElement::disclosedRowAtIndex(unsigned index)
-{
- return nullptr;
-}
-
-AccessibilityUIElement AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index)
-{
- return nullptr;
-}
-
-AccessibilityUIElement AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index)
-{
- if (!ATK_IS_OBJECT(m_element))
- return nullptr;
-
- AtkRelationSet* relationSet = atk_object_ref_relation_set(ATK_OBJECT(m_element));
- if (!relationSet)
- return nullptr;
-
- AtkRelation* relation = atk_relation_set_get_relation_by_type(relationSet, ATK_RELATION_FLOWS_TO);
- if (!relation)
- return nullptr;
-
- GPtrArray* targetList = atk_relation_get_target(relation);
- if (!targetList || !targetList->len || index >= targetList->len)
- return nullptr;
-
- g_object_unref(relationSet);
-
- AtkObject* target = static_cast<AtkObject*>(g_ptr_array_index(targetList, index));
- return target ? AccessibilityUIElement(target) : nullptr;
-}
-
-AccessibilityUIElement AccessibilityUIElement::selectedRowAtIndex(unsigned index)
-{
- return nullptr;
-}
-
-AccessibilityUIElement AccessibilityUIElement::rowAtIndex(unsigned index)
-{
- return nullptr;
-}
-
-AccessibilityUIElement AccessibilityUIElement::disclosedByRow()
-{
- return nullptr;
-}
-
-JSStringRef AccessibilityUIElement::accessibilityValue() const
-{
- // FIXME: implement
- return JSStringCreateWithCharacters(0, 0);
-}
-
-JSStringRef AccessibilityUIElement::documentEncoding()
-{
- if (!ATK_IS_DOCUMENT(m_element))
- return JSStringCreateWithCharacters(0, 0);
-
- AtkRole role = atk_object_get_role(ATK_OBJECT(m_element));
- if (role != ATK_ROLE_DOCUMENT_FRAME)
- return JSStringCreateWithCharacters(0, 0);
-
- return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element), "Encoding"));
-}
-
-JSStringRef AccessibilityUIElement::documentURI()
-{
- if (!ATK_IS_DOCUMENT(m_element))
- return JSStringCreateWithCharacters(0, 0);
-
- AtkRole role = atk_object_get_role(ATK_OBJECT(m_element));
- if (role != ATK_ROLE_DOCUMENT_FRAME)
- return JSStringCreateWithCharacters(0, 0);
-
- return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element), "URI"));
-}
-
-JSStringRef AccessibilityUIElement::url()
-{
- if (!ATK_IS_HYPERLINK_IMPL(m_element))
- return JSStringCreateWithCharacters(0, 0);
-
- AtkHyperlink* hyperlink = atk_hyperlink_impl_get_hyperlink(ATK_HYPERLINK_IMPL(m_element));
- GUniquePtr<char> hyperlinkURI(atk_hyperlink_get_uri(hyperlink, 0));
-
- // Build the result string, stripping the absolute URL paths if present.
- char* localURI = g_strstr_len(hyperlinkURI.get(), -1, "LayoutTests");
- String axURL = String::format("AXURL: %s", localURI ? localURI : hyperlinkURI.get());
- return JSStringCreateWithUTF8CString(axURL.utf8().data());
-}
-
-bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallback)
-{
- if (!functionCallback)
- return false;
-
- // Only one notification listener per element.
- if (m_notificationHandler)
- return false;
-
- m_notificationHandler = AccessibilityNotificationHandler::create();
- m_notificationHandler->setPlatformElement(platformUIElement());
- m_notificationHandler->setNotificationFunctionCallback(functionCallback);
-
- return true;
-}
-
-void AccessibilityUIElement::removeNotificationListener()
-{
- // Programmers should not be trying to remove a listener that's already removed.
- ASSERT(m_notificationHandler);
-
- m_notificationHandler = nullptr;
-}
-
-bool AccessibilityUIElement::isFocusable() const
-{
- if (!ATK_IS_OBJECT(m_element))
- return false;
-
- GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(m_element)));
- gboolean isFocusable = atk_state_set_contains_state(stateSet.get(), ATK_STATE_FOCUSABLE);
-
- return isFocusable;
-}
-
-bool AccessibilityUIElement::isSelectable() const
-{
- return checkElementState(m_element, ATK_STATE_SELECTABLE);
-}
-
-bool AccessibilityUIElement::isMultiSelectable() const
-{
- return checkElementState(m_element, ATK_STATE_MULTISELECTABLE);
-}
-
-bool AccessibilityUIElement::isSelectedOptionActive() const
-{
- return checkElementState(m_element, ATK_STATE_ACTIVE);
-}
-
-bool AccessibilityUIElement::isVisible() const
-{
- // FIXME: implement
- return false;
-}
-
-bool AccessibilityUIElement::isOffScreen() const
-{
- // FIXME: implement
- return false;
-}
-
-bool AccessibilityUIElement::isCollapsed() const
-{
- // FIXME: implement
- return false;
-}
-
-bool AccessibilityUIElement::isIgnored() const
-{
- // FIXME: implement
- return false;
-}
-
-bool AccessibilityUIElement::hasPopup() const
-{
- if (!ATK_IS_OBJECT(m_element))
- return false;
-
- String hasPopupValue = getAttributeSetValueForId(ATK_OBJECT(m_element), ObjectAttributeType, "haspopup");
- return equalIgnoringCase(hasPopupValue, "true");
-}
-
-void AccessibilityUIElement::takeFocus()
-{
- // FIXME: implement
-}
-
-void AccessibilityUIElement::takeSelection()
-{
- // FIXME: implement
-}
-
-void AccessibilityUIElement::addSelection()
-{
- // FIXME: implement
-}
-
-void AccessibilityUIElement::removeSelection()
-{
- // FIXME: implement
-}
-
-void AccessibilityUIElement::scrollToMakeVisible()
-{
- // FIXME: implement
-}
-
-void AccessibilityUIElement::scrollToMakeVisibleWithSubFocus(int x, int y, int width, int height)
-{
- // FIXME: implement
-}
-
-void AccessibilityUIElement::scrollToGlobalPoint(int x, int y)
-{
- // FIXME: implement
-}
-
-JSStringRef AccessibilityUIElement::classList() const
-{
- // FIXME: implement
- return nullptr;
-}
-
-JSStringRef stringAtOffset(PlatformUIElement element, AtkTextBoundary boundary, int offset)
-{
- if (!ATK_IS_TEXT(element))
- return JSStringCreateWithCharacters(0, 0);
-
- gint startOffset, endOffset;
- StringBuilder builder;
-
-#if ATK_CHECK_VERSION(2, 10, 0)
- AtkTextGranularity granularity;
- switch (boundary) {
- case ATK_TEXT_BOUNDARY_CHAR:
- granularity = ATK_TEXT_GRANULARITY_CHAR;
- break;
- case ATK_TEXT_BOUNDARY_WORD_START:
- granularity = ATK_TEXT_GRANULARITY_WORD;
- break;
- case ATK_TEXT_BOUNDARY_LINE_START:
- granularity = ATK_TEXT_GRANULARITY_LINE;
- break;
- case ATK_TEXT_BOUNDARY_SENTENCE_START:
- granularity = ATK_TEXT_GRANULARITY_SENTENCE;
- break;
- default:
- return JSStringCreateWithCharacters(0, 0);
- }
-
- builder.append(atk_text_get_string_at_offset(ATK_TEXT(element), offset, granularity, &startOffset, &endOffset));
-#else
- builder.append(atk_text_get_text_at_offset(ATK_TEXT(element), offset, boundary, &startOffset, &endOffset));
-#endif
- builder.append(String::format(", %i, %i", startOffset, endOffset));
- return JSStringCreateWithUTF8CString(builder.toString().utf8().data());
-}
-
-JSStringRef AccessibilityUIElement::characterAtOffset(int offset)
-{
- return stringAtOffset(m_element, ATK_TEXT_BOUNDARY_CHAR, offset);
-}
-
-JSStringRef AccessibilityUIElement::wordAtOffset(int offset)
-{
- return stringAtOffset(m_element, ATK_TEXT_BOUNDARY_WORD_START, offset);
-}
-
-JSStringRef AccessibilityUIElement::lineAtOffset(int offset)
-{
- return stringAtOffset(m_element, ATK_TEXT_BOUNDARY_LINE_START, offset);
-}
-
-JSStringRef AccessibilityUIElement::sentenceAtOffset(int offset)
-{
- return stringAtOffset(m_element, ATK_TEXT_BOUNDARY_SENTENCE_START, offset);
-}
-
-#endif
diff --git a/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp b/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp
index fe6046c68..9c8931075 100644
--- a/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp
+++ b/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp
@@ -12,7 +12,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
diff --git a/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.h b/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.h
index 071e874d0..8cc59589d 100644
--- a/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.h
+++ b/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.h
@@ -11,7 +11,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -27,10 +27,9 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef PixelDumpSupportCairo_h
-#define PixelDumpSupportCairo_h
+#pragma once
-#include <wtf/PassRefPtr.h>
+#include <wtf/Ref.h>
#include <wtf/RefCounted.h>
#if PLATFORM(WIN)
@@ -48,9 +47,9 @@ typedef void* PlatformBitmapBuffer;
class BitmapContext : public RefCounted<BitmapContext> {
public:
- static PassRefPtr<BitmapContext> createByAdoptingBitmapAndContext(PlatformBitmapBuffer buffer, cairo_t* context)
+ static Ref<BitmapContext> createByAdoptingBitmapAndContext(PlatformBitmapBuffer buffer, cairo_t* context)
{
- return adoptRef(new BitmapContext(buffer, context));
+ return adoptRef(*new BitmapContext(buffer, context));
}
~BitmapContext()
@@ -77,5 +76,3 @@ private:
PlatformBitmapBuffer m_buffer;
cairo_t* m_context;
};
-
-#endif // PixelDumpSupportCairo_h
diff --git a/Tools/DumpRenderTree/config.h b/Tools/DumpRenderTree/config.h
index ddb1d5195..3ee18a3cd 100644
--- a/Tools/DumpRenderTree/config.h
+++ b/Tools/DumpRenderTree/config.h
@@ -18,18 +18,13 @@
*
*/
-#define Config_H
+#pragma once
-#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H
-#if defined(BUILDING_WITH_CMAKE)
+#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H && defined(BUILDING_WITH_CMAKE)
#include "cmakeconfig.h"
-#else
-#include "autotoolsconfig.h"
-#endif
#endif
-#include <wtf/Platform.h>
-#include <wtf/ExportMacros.h>
+#include <WebCore/PlatformExportMacros.h>
#include <runtime/JSExportMacros.h>
#ifdef __cplusplus
@@ -38,39 +33,25 @@
#include <wtf/FastMalloc.h>
#endif
-#if PLATFORM(MAC)
-#define WTF_USE_CF 1
-
-// FIXME: These can be removed after sufficient time has passed since the removal of BUILDING_ON / TARGETING macros.
-
-#define ERROR_PLEASE_COMPARE_WITH_MAC_OS_X_VERSION_MIN_REQUIRED 0 / 0
-#define ERROR_PLEASE_COMPARE_WITH_MAC_OS_X_VERSION_MAX_ALLOWED 0 / 0
-
-#define BUILDING_ON_LEOPARD ERROR_PLEASE_COMPARE_WITH_MAC_OS_X_VERSION_MIN_REQUIRED
-#define BUILDING_ON_SNOW_LEOPARD ERROR_PLEASE_COMPARE_WITH_MAC_OS_X_VERSION_MIN_REQUIRED
-#define BUILDING_ON_LION ERROR_PLEASE_COMPARE_WITH_MAC_OS_X_VERSION_MIN_REQUIRED
-
-#define TARGETING_LEOPARD ERROR_PLEASE_COMPARE_WITH_MAC_OS_X_VERSION_MAX_ALLOWED
-#define TARGETING_SNOW_LEOPARD ERROR_PLEASE_COMPARE_WITH_MAC_OS_X_VERSION_MAX_ALLOWED
-#define TARGETING_LION ERROR_PLEASE_COMPARE_WITH_MAC_OS_X_VERSION_MAX_ALLOWED
-
-#endif // PLATFORM(MAC)
+#if PLATFORM(COCOA)
+#define USE_CF 1
+#endif
#if PLATFORM(WIN)
-#define WTF_USE_CF 1
+#define USE_CF 1
#if PLATFORM(WIN_CAIRO)
-#define WTF_USE_CAIRO 1
-#define WTF_USE_CURL 1
+#define USE_CAIRO 1
+#define USE_CURL 1
#else
-#define WTF_USE_CG 1
-#define WTF_USE_CFNETWORK 1
+#define USE_CG 1
+#define USE_CFURLCONNECTION 1
#endif
#undef _WIN32_WINNT
-#define _WIN32_WINNT 0x0502
+#define _WIN32_WINNT 0x601
#undef WINVER
-#define WINVER 0x0502
+#define WINVER 0x0601
#undef _WINSOCKAPI_
#define _WINSOCKAPI_ // Prevent inclusion of winsock.h in windows.h
diff --git a/Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp b/Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp
deleted file mode 100644
index 7ee1d9460..000000000
--- a/Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved.
- * Copyright (C) 2009 Jan Michael Alonzo
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#if HAVE(ACCESSIBILITY)
-
-#include "AccessibilityController.h"
-
-#include "AccessibilityCallbacks.h"
-#include "AccessibilityUIElement.h"
-#include "DumpRenderTree.h"
-#include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
-
-#include <atk/atk.h>
-#include <gtk/gtk.h>
-#include <webkit/webkit.h>
-#include <wtf/gobject/GUniquePtr.h>
-
-AccessibilityUIElement AccessibilityController::focusedElement()
-{
- AtkObject* accessible = DumpRenderTreeSupportGtk::getFocusedAccessibleElement(mainFrame);
- if (!accessible)
- return 0;
-
- return AccessibilityUIElement(accessible);
-}
-
-AccessibilityUIElement AccessibilityController::rootElement()
-{
- AtkObject* accessible = DumpRenderTreeSupportGtk::getRootAccessibleElement(mainFrame);
- if (!accessible)
- return 0;
-
- return AccessibilityUIElement(accessible);
-}
-
-AccessibilityUIElement AccessibilityController::accessibleElementById(JSStringRef id)
-{
- AtkObject* root = DumpRenderTreeSupportGtk::getRootAccessibleElement(mainFrame);
- if (!root)
- return 0;
-
- size_t bufferSize = JSStringGetMaximumUTF8CStringSize(id);
- GUniquePtr<gchar> idBuffer(static_cast<gchar*>(g_malloc(bufferSize)));
- JSStringGetUTF8CString(id, idBuffer.get(), bufferSize);
-
- AtkObject* result = childElementById(root, idBuffer.get());
- if (ATK_IS_OBJECT(result))
- return AccessibilityUIElement(result);
-
- return 0;
-
-}
-
-#endif // HAVE(ACCESSIBILITY)
diff --git a/Tools/DumpRenderTree/gtk/DumpRenderTree.cpp b/Tools/DumpRenderTree/gtk/DumpRenderTree.cpp
deleted file mode 100644
index 73d710a04..000000000
--- a/Tools/DumpRenderTree/gtk/DumpRenderTree.cpp
+++ /dev/null
@@ -1,1557 +0,0 @@
-/*
- * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
- * Copyright (C) 2008 Alp Toker <alp@nuanti.com>
- * Copyright (C) 2009 Jan Alonzo <jmalonzo@gmail.com>
- * Copyright (C) 2010, 2011 Igalia S.L.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "DumpRenderTree.h"
-
-#include "AccessibilityController.h"
-#include "EditingCallbacks.h"
-#include "EventSender.h"
-#include "GCController.h"
-#include "PixelDumpSupport.h"
-#include "SelfScrollingWebKitWebView.h"
-#include "TestRunner.h"
-#include "TextInputController.h"
-#include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
-#include "WebCoreTestSupport.h"
-#include "WorkQueue.h"
-#include "WorkQueueItem.h"
-#include <JavaScriptCore/JavaScript.h>
-#include <WebCore/platform/network/soup/GUniquePtrSoup.h>
-#include <cassert>
-#include <cstdlib>
-#include <cstring>
-#include <getopt.h>
-#include <gtk/gtk.h>
-#include <locale.h>
-#include <webkit/webkit.h>
-#include <wtf/Assertions.h>
-#include <wtf/gobject/GlibUtilities.h>
-#include <wtf/text/WTFString.h>
-
-#if PLATFORM(X11)
-#include <fontconfig/fontconfig.h>
-#endif
-
-
-using namespace std;
-
-extern "C" {
-// This API is not yet public.
-extern gchar* webkit_web_history_item_get_target(WebKitWebHistoryItem*);
-extern gboolean webkit_web_history_item_is_target_item(WebKitWebHistoryItem*);
-extern GList* webkit_web_history_item_get_children(WebKitWebHistoryItem*);
-extern void webkit_web_settings_add_extra_plugin_directory(WebKitWebView* view, const gchar* directory);
-extern gchar* webkit_web_frame_get_response_mime_type(WebKitWebFrame* frame);
-}
-
-volatile bool done;
-static bool printSeparators;
-static int dumpPixelsForAllTests = false;
-static bool dumpPixelsForCurrentTest;
-static int dumpTree = 1;
-static int useTimeoutWatchdog = 1;
-
-#if HAVE(ACCESSIBILITY)
-AccessibilityController* axController = 0;
-#endif
-RefPtr<TestRunner> gTestRunner;
-static GCController* gcController = 0;
-static WebKitWebView* webView;
-static GtkWidget* window;
-static GtkWidget* container;
-static GtkWidget* webInspectorWindow;
-WebKitWebFrame* mainFrame = 0;
-WebKitWebFrame* topLoadingFrame = 0;
-guint waitToDumpWatchdog = 0;
-bool waitForPolicy = false;
-
-// This is a list of opened webviews
-GSList* webViewList = 0;
-
-// current b/f item at the end of the previous test
-static WebKitWebHistoryItem* prevTestBFItem = NULL;
-
-const unsigned historyItemIndent = 8;
-
-static void runTest(const string& inputLine);
-
-static void didRunInsecureContent(WebKitWebFrame*, WebKitSecurityOrigin*, const char* url);
-
-static bool shouldLogFrameLoadDelegates(const string& pathOrURL)
-{
- return pathOrURL.find("loading/") != string::npos;
-}
-
-static bool shouldOpenWebInspector(const string& pathOrURL)
-{
- return pathOrURL.find("inspector/") != string::npos;
-}
-
-static bool shouldDumpAsText(const string& pathOrURL)
-{
- return pathOrURL.find("dumpAsText/") != string::npos;
-}
-
-static bool shouldEnableDeveloperExtras(const string& pathOrURL)
-{
- return true;
-}
-
-void dumpFrameScrollPosition(WebKitWebFrame* frame)
-{
- WebKitDOMDocument* document = webkit_web_frame_get_dom_document(frame);
- if (!document)
- return;
-
- WebKitDOMDOMWindow* domWindow = webkit_dom_document_get_default_view(document);
- if (!domWindow)
- return;
-
- glong x = webkit_dom_dom_window_get_page_x_offset(domWindow);
- glong y = webkit_dom_dom_window_get_page_y_offset(domWindow);
-
- if (abs(x) > 0 || abs(y) > 0) {
- if (webkit_web_frame_get_parent(frame))
- printf("frame '%s' ", webkit_web_frame_get_name(frame));
- printf("scrolled to %ld,%ld\n", x, y);
- }
-
- if (gTestRunner->dumpChildFrameScrollPositions()) {
- GSList* children = DumpRenderTreeSupportGtk::getFrameChildren(frame);
- for (GSList* child = children; child; child = g_slist_next(child))
- dumpFrameScrollPosition(static_cast<WebKitWebFrame*>(child->data));
- g_slist_free(children);
- }
-}
-
-void displayWebView()
-{
- DumpRenderTreeSupportGtk::forceWebViewPaint(webView);
- DumpRenderTreeSupportGtk::setTracksRepaints(mainFrame, true);
- DumpRenderTreeSupportGtk::resetTrackedRepaints(mainFrame);
-}
-
-static void appendString(gchar*& target, const gchar* string)
-{
- gchar* oldString = target;
- target = g_strconcat(target, string, NULL);
- g_free(oldString);
-}
-
-static void initializeGtkFontSettings(const char* testURL)
-{
- GtkSettings* settings = gtk_settings_get_default();
- if (!settings)
- return;
- g_object_set(settings,
- "gtk-xft-dpi", 98304, // This is 96 * 1024 or 96 DPI according to the GTK+ docs.
- "gtk-xft-antialias", 1,
- "gtk-xft-hinting", 0,
- "gtk-font-name", "Liberation Sans 12",
- "gtk-icon-theme-name", "gnome",
- NULL);
- gdk_screen_set_resolution(gdk_screen_get_default(), 96.0);
-
- // One test needs subpixel anti-aliasing turned on, but generally we
- // want all text in other tests to use to grayscale anti-aliasing.
- if (testURL && strstr(testURL, "xsettings_antialias_settings.html"))
- g_object_set(settings, "gtk-xft-rgba", "rgb", NULL);
- else
- g_object_set(settings, "gtk-xft-rgba", "none", NULL);
-}
-
-CString getTopLevelPath()
-{
- if (const gchar* topLevel = g_getenv("WEBKIT_TOP_LEVEL"))
- return topLevel;
-
- g_setenv("WEBKIT_TOP_LEVEL", TOP_LEVEL_DIR, FALSE);
- return TOP_LEVEL_DIR;
-}
-
-CString getOutputDir()
-{
- const char* webkitOutputDir = g_getenv("WEBKIT_OUTPUTDIR");
- if (webkitOutputDir)
- return webkitOutputDir;
-
- CString topLevelPath = getTopLevelPath();
- GUniquePtr<char> outputDir(g_build_filename(topLevelPath.data(), "WebKitBuild", NULL));
- return outputDir.get();
-}
-
-static CString getFontsPath()
-{
- CString webkitOutputDir = getOutputDir();
- GUniquePtr<char> fontsPath(g_build_filename(webkitOutputDir.data(), "Dependencies", "Root", "webkitgtk-test-fonts", NULL));
- if (g_file_test(fontsPath.get(), static_cast<GFileTest>(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
- return fontsPath.get();
-
- // Try alternative fonts path.
- fontsPath.reset(g_build_filename(webkitOutputDir.data(), "webkitgtk-test-fonts", NULL));
- if (g_file_test(fontsPath.get(), static_cast<GFileTest>(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
- return fontsPath.get();
-
- return CString();
-}
-
-static void initializeFonts(const char* testURL = 0)
-{
-#if PLATFORM(X11)
- initializeGtkFontSettings(testURL);
-
- FcInit();
-
- // If a test resulted a font being added or removed via the @font-face rule, then
- // we want to reset the FontConfig configuration to prevent it from affecting other tests.
- static int numFonts = 0;
- FcFontSet* appFontSet = FcConfigGetFonts(0, FcSetApplication);
- if (appFontSet && numFonts && appFontSet->nfont == numFonts)
- return;
-
- // Load our configuration file, which sets up proper aliases for family
- // names like sans, serif and monospace.
- FcConfig* config = FcConfigCreate();
- GUniquePtr<gchar> fontConfigFilename(g_build_filename(FONTS_CONF_DIR, "fonts.conf", nullptr));
- if (!FcConfigParseAndLoad(config, reinterpret_cast<FcChar8*>(fontConfigFilename.get()), true))
- g_error("Couldn't load font configuration file from: %s", fontConfigFilename.get());
-
- CString fontsPath = getFontsPath();
- if (fontsPath.isNull())
- g_error("Could not locate test fonts at $WEBKIT_TOP_LEVEL/WebKitBuild/Dependencies/Root/webkitgtk-test-fonts. "
- "WEBKIT_TOP_LEVEL is your WebKit checkout by default, and can be overridden by setting it as an environment variable.");
-
- GUniquePtr<GDir> fontsDirectory(g_dir_open(fontsPath.data(), 0, nullptr));
- while (const char* directoryEntry = g_dir_read_name(fontsDirectory.get())) {
- if (!g_str_has_suffix(directoryEntry, ".ttf") && !g_str_has_suffix(directoryEntry, ".otf"))
- continue;
- GUniquePtr<gchar> fontPath(g_build_filename(fontsPath.data(), directoryEntry, nullptr));
- if (!FcConfigAppFontAddFile(config, reinterpret_cast<const FcChar8*>(fontPath.get())))
- g_error("Could not load font at %s!", fontPath.get());
-
- }
-
- // Ahem is used by many layout tests.
- GUniquePtr<gchar> ahemFontFilename(g_build_filename(FONTS_CONF_DIR, "AHEM____.TTF", nullptr));
- if (!FcConfigAppFontAddFile(config, reinterpret_cast<FcChar8*>(ahemFontFilename.get())))
- g_error("Could not load font at %s!", ahemFontFilename.get());
-
- for (int i = 1; i <= 9; i++) {
- GUniquePtr<gchar> fontFilename(g_strdup_printf("WebKitWeightWatcher%i00.ttf", i));
- GUniquePtr<gchar> fontPath(g_build_filename(FONTS_CONF_DIR, "..", "..", "fonts", fontFilename.get(), nullptr));
- if (!FcConfigAppFontAddFile(config, reinterpret_cast<FcChar8*>(fontPath.get())))
- g_error("Could not load font at %s!", fontPath.get());
- }
-
- // A font with no valid Fontconfig encoding to test https://bugs.webkit.org/show_bug.cgi?id=47452
- GUniquePtr<gchar> fontWithNoValidEncodingFilename(g_build_filename(FONTS_CONF_DIR, "FontWithNoValidEncoding.fon", nullptr));
- if (!FcConfigAppFontAddFile(config, reinterpret_cast<FcChar8*>(fontWithNoValidEncodingFilename.get())))
- g_error("Could not load font at %s!", fontWithNoValidEncodingFilename.get());
-
- if (!FcConfigSetCurrent(config))
- g_error("Could not set the current font configuration!");
-
- numFonts = FcConfigGetFonts(config, FcSetApplication)->nfont;
-#endif
-}
-
-static gchar* dumpFramesAsText(WebKitWebFrame* frame)
-{
- gchar* result = 0;
-
- // Add header for all but the main frame.
- bool isMainFrame = (webkit_web_view_get_main_frame(webView) == frame);
-
- CString innerText = DumpRenderTreeSupportGtk::getInnerText(frame);
- if (isMainFrame)
- result = g_strdup_printf("%s\n", innerText.data());
- else {
- const gchar* frameName = webkit_web_frame_get_name(frame);
- result = g_strdup_printf("\n--------\nFrame: '%s'\n--------\n%s\n", frameName, innerText.data());
- }
-
- if (gTestRunner->dumpChildFramesAsText()) {
- GSList* children = DumpRenderTreeSupportGtk::getFrameChildren(frame);
- for (GSList* child = children; child; child = g_slist_next(child)) {
- GUniquePtr<gchar> childData(dumpFramesAsText(static_cast<WebKitWebFrame*>(child->data)));
- appendString(result, childData.get());
- }
- g_slist_free(children);
- }
-
- return result;
-}
-
-static gint compareHistoryItems(gpointer* item1, gpointer* item2)
-{
- GUniquePtr<gchar> firstItemTarget(webkit_web_history_item_get_target(WEBKIT_WEB_HISTORY_ITEM(item1)));
- GUniquePtr<gchar> secondItemTarget(webkit_web_history_item_get_target(WEBKIT_WEB_HISTORY_ITEM(item2)));
- return g_ascii_strcasecmp(firstItemTarget.get(), secondItemTarget.get());
-}
-
-static void dumpHistoryItem(WebKitWebHistoryItem* item, int indent, bool current)
-{
- ASSERT(item != NULL);
- int start = 0;
- g_object_ref(item);
- if (current) {
- printf("curr->");
- start = 6;
- }
- for (int i = start; i < indent; i++)
- putchar(' ');
-
- // normalize file URLs.
- const gchar* uri = webkit_web_history_item_get_uri(item);
- gchar* uriScheme = g_uri_parse_scheme(uri);
- if (g_strcmp0(uriScheme, "file") == 0) {
- gchar* pos = g_strstr_len(uri, -1, "/LayoutTests/");
- if (!pos) {
- g_free(uriScheme);
- return;
- }
-
- GString* result = g_string_sized_new(strlen(uri));
- result = g_string_append(result, "(file test):");
- result = g_string_append(result, pos + strlen("/LayoutTests/"));
- printf("%s", result->str);
- g_string_free(result, TRUE);
- } else
- printf("%s", uri);
-
- g_free(uriScheme);
-
- GUniquePtr<gchar> target(webkit_web_history_item_get_target(item));
- if (target.get() && strlen(target.get()) > 0)
- printf(" (in frame \"%s\")", target.get());
- if (webkit_web_history_item_is_target_item(item))
- printf(" **nav target**");
- putchar('\n');
-
- if (GList* kids = webkit_web_history_item_get_children(item)) {
- // must sort to eliminate arbitrary result ordering which defeats reproducible testing
- for (GList* kid = g_list_sort(kids, (GCompareFunc) compareHistoryItems); kid; kid = g_list_next(kid)) {
- WebKitWebHistoryItem* item = WEBKIT_WEB_HISTORY_ITEM(kid->data);
- dumpHistoryItem(item, indent + 4, FALSE);
- g_object_unref(item);
- }
- g_list_free(kids);
- }
- g_object_unref(item);
-}
-
-static void dumpBackForwardListForWebView(WebKitWebView* view)
-{
- printf("\n============== Back Forward List ==============\n");
- WebKitWebBackForwardList* bfList = webkit_web_view_get_back_forward_list(view);
-
- // Print out all items in the list after prevTestBFItem, which was from the previous test
- // Gather items from the end of the list, the print them out from oldest to newest
- GList* itemsToPrint = NULL;
- gint forwardListCount = webkit_web_back_forward_list_get_forward_length(bfList);
- for (int i = forwardListCount; i > 0; i--) {
- WebKitWebHistoryItem* item = webkit_web_back_forward_list_get_nth_item(bfList, i);
- // something is wrong if the item from the last test is in the forward part of the b/f list
- ASSERT(item != prevTestBFItem);
- g_object_ref(item);
- itemsToPrint = g_list_prepend(itemsToPrint, item);
- }
-
- WebKitWebHistoryItem* currentItem = webkit_web_back_forward_list_get_current_item(bfList);
- g_object_ref(currentItem);
- itemsToPrint = g_list_prepend(itemsToPrint, currentItem);
-
- gint backListCount = webkit_web_back_forward_list_get_back_length(bfList);
- for (int i = -1; i >= -(backListCount); i--) {
- WebKitWebHistoryItem* item = webkit_web_back_forward_list_get_nth_item(bfList, i);
- if (item == prevTestBFItem)
- break;
- g_object_ref(item);
- itemsToPrint = g_list_prepend(itemsToPrint, item);
- }
-
- for (GList* itemToPrint = itemsToPrint; itemToPrint; itemToPrint = g_list_next(itemToPrint)) {
- WebKitWebHistoryItem* item = WEBKIT_WEB_HISTORY_ITEM(itemToPrint->data);
- dumpHistoryItem(item, historyItemIndent, item == currentItem);
- g_object_unref(item);
- }
-
- g_list_free(itemsToPrint);
- printf("===============================================\n");
-}
-
-static void dumpBackForwardListForAllWebViews()
-{
- // Dump the back forward list of the main WebView first
- dumpBackForwardListForWebView(webView);
-
- // The view list is prepended. Reverse the list so we get the order right.
- for (GSList* currentView = g_slist_reverse(webViewList); currentView; currentView = g_slist_next(currentView))
- dumpBackForwardListForWebView(WEBKIT_WEB_VIEW(currentView->data));
-}
-
-void setWaitToDumpWatchdog(guint timer)
-{
- waitToDumpWatchdog = timer;
-}
-
-bool shouldSetWaitToDumpWatchdog()
-{
- return !waitToDumpWatchdog && useTimeoutWatchdog;
-}
-
-CString soupURIToStringPreservingPassword(SoupURI* soupURI)
-{
- if (!soupURI->password) {
- GUniquePtr<char> uriString(soup_uri_to_string(soupURI, FALSE));
- return uriString.get();
- }
-
- // soup_uri_to_string does not insert the password into the string, so we need to create the
- // URI string and then reinsert any credentials that were present in the SoupURI. All tests that
- // use URL-embedded credentials use HTTP, so it's safe here.
- GUniquePtr<char> password(soupURI->password);
- GUniquePtr<char> user(soupURI->user);
- soupURI->password = 0;
- soupURI->user = 0;
-
- GUniquePtr<char> uriString(soup_uri_to_string(soupURI, FALSE));
- String absoluteURIWithoutCredentialString = String::fromUTF8(uriString.get());
- String protocolAndCredential = String::format("http://%s:%s@", user ? user.get() : "", password.get());
- return absoluteURIWithoutCredentialString.replace("http://", protocolAndCredential).utf8();
-}
-
-static void invalidateAnyPreviousWaitToDumpWatchdog()
-{
- if (waitToDumpWatchdog) {
- g_source_remove(waitToDumpWatchdog);
- waitToDumpWatchdog = 0;
- }
-
- waitForPolicy = false;
-}
-
-static void resetDefaultsToConsistentValues()
-{
- WebKitWebSettings* settings = webkit_web_view_get_settings(webView);
- GUniquePtr<gchar> localStoragePath(g_build_filename(g_get_user_data_dir(), "DumpRenderTreeGtk", "databases", nullptr));
- g_object_set(G_OBJECT(settings),
- "enable-accelerated-compositing", FALSE,
- "enable-private-browsing", FALSE,
- "enable-developer-extras", FALSE,
- "enable-spell-checking", TRUE,
- "enable-html5-database", TRUE,
- "enable-html5-local-storage", TRUE,
- "html5-local-storage-database-path", localStoragePath.get(),
- "enable-xss-auditor", FALSE,
- "enable-spatial-navigation", FALSE,
- "javascript-can-access-clipboard", TRUE,
- "javascript-can-open-windows-automatically", TRUE,
- "enable-offline-web-application-cache", TRUE,
- "enable-universal-access-from-file-uris", TRUE,
- "enable-file-access-from-file-uris", TRUE,
- "enable-scripts", TRUE,
- "enable-dom-paste", TRUE,
- "default-font-family", "Times",
- "monospace-font-family", "Courier",
- "serif-font-family", "Times",
- "sans-serif-font-family", "Helvetica",
- "cursive-font-family", "cursive",
- "fantasy-font-family", "fantasy",
- "default-font-size", 12,
- "default-monospace-font-size", 10,
- "minimum-font-size", 0,
- "enable-caret-browsing", FALSE,
- "enable-page-cache", FALSE,
- "auto-resize-window", TRUE,
- "auto-load-images", TRUE,
- "enable-java-applet", FALSE,
- "enable-plugins", TRUE,
- "enable-hyperlink-auditing", FALSE,
- "editing-behavior", WEBKIT_EDITING_BEHAVIOR_UNIX,
- "enable-fullscreen", TRUE,
- "enable-mediasource", TRUE,
- NULL);
- webkit_web_view_set_settings(webView, settings);
- webkit_set_cache_model(WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER);
-
- DumpRenderTreeSupportGtk::clearMainFrameName(mainFrame);
- DumpRenderTreeSupportGtk::scalePageBy(webView, 1, 0, 0);
-
- WebKitWebInspector* inspector = webkit_web_view_get_inspector(webView);
- g_object_set(G_OBJECT(inspector), "javascript-profiling-enabled", FALSE, NULL);
-
- webkit_web_view_set_zoom_level(webView, 1.0);
-
- DumpRenderTreeSupportGtk::resetOriginAccessWhiteLists();
-
- WebKitWebBackForwardList* list = webkit_web_view_get_back_forward_list(webView);
- webkit_web_back_forward_list_clear(list);
-
- SoupSession* session = webkit_get_default_session();
- SoupCookieJar* jar = reinterpret_cast<SoupCookieJar*>(soup_session_get_feature(session, SOUP_TYPE_COOKIE_JAR));
-
- // We only create the jar when the soup backend needs to do
- // HTTP. Should we initialize it earlier, perhaps?
- if (jar)
- g_object_set(G_OBJECT(jar), SOUP_COOKIE_JAR_ACCEPT_POLICY, SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY, NULL);
-
- setlocale(LC_ALL, "");
-
- DumpRenderTreeSupportGtk::setLinksIncludedInFocusChain(true);
- webkit_icon_database_set_path(webkit_get_icon_database(), 0);
- DumpRenderTreeSupportGtk::setDefersLoading(webView, false);
- DumpRenderTreeSupportGtk::setSerializeHTTPLoads(false);
-
-#if HAVE(ACCESSIBILITY)
- if (axController)
- axController->resetToConsistentState();
-#endif
-
- DumpRenderTreeSupportGtk::clearOpener(mainFrame);
- DumpRenderTreeSupportGtk::setTracksRepaints(mainFrame, false);
-
- DumpRenderTreeSupportGtk::resetGeolocationClientMock(webView);
-
- DumpRenderTreeSupportGtk::setCSSGridLayoutEnabled(webView, false);
- DumpRenderTreeSupportGtk::setCSSRegionsEnabled(webView, true);
- DumpRenderTreeSupportGtk::setExperimentalContentSecurityPolicyFeaturesEnabled(true);
- DumpRenderTreeSupportGtk::setSeamlessIFramesEnabled(true);
- DumpRenderTreeSupportGtk::setShadowDOMEnabled(true);
-
- if (gTestRunner) {
- gTestRunner->setAuthenticationPassword("");
- gTestRunner->setAuthenticationUsername("");
- gTestRunner->setHandlesAuthenticationChallenges(false);
- }
-
- gtk_widget_set_direction(GTK_WIDGET(webView), GTK_TEXT_DIR_NONE);
-}
-
-static bool useLongRunningServerMode(int argc, char *argv[])
-{
- // This assumes you've already called getopt_long
- return (argc == optind+1 && !strcmp(argv[optind], "-"));
-}
-
-static void runTestingServerLoop()
-{
- // When DumpRenderTree runs in server mode, we just wait around for file names
- // to be passed to us and read each in turn, passing the results back to the client
- char filenameBuffer[2048];
- while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {
- char* newLineCharacter = strchr(filenameBuffer, '\n');
- if (newLineCharacter)
- *newLineCharacter = '\0';
-
- if (!strlen(filenameBuffer))
- continue;
-
- runTest(filenameBuffer);
- }
-}
-
-static void initializeGlobalsFromCommandLineOptions(int argc, char *argv[])
-{
- struct option options[] = {
- {"notree", no_argument, &dumpTree, false},
- {"pixel-tests", no_argument, &dumpPixelsForAllTests, true},
- {"tree", no_argument, &dumpTree, true},
- {"no-timeout", no_argument, &useTimeoutWatchdog, false},
- {NULL, 0, NULL, 0}
- };
-
- int option;
- while ((option = getopt_long(argc, (char * const *)argv, "", options, NULL)) != -1) {
- switch (option) {
- case '?': // unknown or ambiguous option
- case ':': // missing argument
- exit(1);
- break;
- }
- }
-}
-
-
-void dump()
-{
- invalidateAnyPreviousWaitToDumpWatchdog();
-
- // Grab widget focus before dumping the contents of a widget, in
- // case it was lost in the course of the test.
- gtk_widget_grab_focus(GTK_WIDGET(webView));
-
- if (dumpTree) {
- char* result = 0;
- gchar* responseMimeType = webkit_web_frame_get_response_mime_type(mainFrame);
-
- if (g_str_equal(responseMimeType, "text/plain")) {
- gTestRunner->setDumpAsText(true);
- gTestRunner->setGeneratePixelResults(false);
- }
- g_free(responseMimeType);
-
- if (gTestRunner->dumpAsText())
- result = dumpFramesAsText(mainFrame);
- else {
- // Widget resizing is done asynchronously in GTK+. We pump the main
- // loop here, to flush any pending resize requests. This prevents
- // timing issues which affect the size of elements in the output.
- // We only enable this workaround for tests that print the render tree
- // because this seems to break some dumpAsText tests: see bug 39988
- // After fixing that test, we should apply this approach to all dumps.
- while (gtk_events_pending())
- gtk_main_iteration();
-
- result = g_strdup(DumpRenderTreeSupportGtk::dumpRenderTree(mainFrame).data());
- }
-
- if (!result) {
- const char* errorMessage;
- if (gTestRunner->dumpAsText())
- errorMessage = "[documentElement innerText]";
- else if (gTestRunner->dumpDOMAsWebArchive())
- errorMessage = "[[mainFrame DOMDocument] webArchive]";
- else if (gTestRunner->dumpSourceAsWebArchive())
- errorMessage = "[[mainFrame dataSource] webArchive]";
- else
- errorMessage = "[mainFrame renderTreeAsExternalRepresentation]";
- printf("ERROR: nil result from %s", errorMessage);
- } else {
- printf("%s", result);
- g_free(result);
- if (!gTestRunner->dumpAsText() && !gTestRunner->dumpDOMAsWebArchive() && !gTestRunner->dumpSourceAsWebArchive())
- dumpFrameScrollPosition(mainFrame);
-
- if (gTestRunner->dumpBackForwardList())
- dumpBackForwardListForAllWebViews();
- }
-
- if (printSeparators) {
- puts("#EOF"); // terminate the content block
- fputs("#EOF\n", stderr);
- fflush(stdout);
- fflush(stderr);
- }
- }
-
- if (dumpPixelsForCurrentTest
- && gTestRunner->generatePixelResults()
- && !gTestRunner->dumpDOMAsWebArchive()
- && !gTestRunner->dumpSourceAsWebArchive()) {
- DumpRenderTreeSupportGtk::forceWebViewPaint(webView);
- dumpWebViewAsPixelsAndCompareWithExpected(gTestRunner->expectedPixelHash());
- }
-
- // FIXME: call displayWebView here when we support --paint
-
- done = true;
- gtk_main_quit();
-}
-
-static CString temporaryDatabaseDirectory()
-{
- const char* directoryFromEnvironment = g_getenv("DUMPRENDERTREE_TEMP");
- if (directoryFromEnvironment)
- return directoryFromEnvironment;
- GUniquePtr<char> fallback(g_build_filename(g_get_user_data_dir(), "gtkwebkitdrt", "databases", NULL));
- return fallback.get();
-}
-
-static void setDefaultsToConsistentStateValuesForTesting()
-{
- resetDefaultsToConsistentValues();
-
-#if PLATFORM(X11)
- webkit_web_settings_add_extra_plugin_directory(webView, TEST_PLUGIN_DIR);
-#endif
-
- webkit_set_web_database_directory_path(temporaryDatabaseDirectory().data());
-
-#if defined(GTK_API_VERSION_2)
- gtk_rc_parse_string("style \"nix_scrollbar_spacing\" "
- "{ "
- " GtkScrolledWindow::scrollbar-spacing = 0 "
- "} "
- "class \"GtkWidget\" style \"nix_scrollbar_spacing\"");
-
-#else
- GtkCssProvider* cssProvider = gtk_css_provider_new();
- gtk_css_provider_load_from_data(cssProvider,
- "@binding-set NoKeyboardNavigation { "
- " unbind \"<shift>F10\"; "
- "} "
- " * { "
- " -GtkScrolledWindow-scrollbar-spacing: 0;"
- " gtk-key-bindings: NoKeyboardNavigation; "
- "} ",
- -1, 0);
- gtk_style_context_add_provider_for_screen(gdk_display_get_default_screen(gdk_display_get_default()),
- GTK_STYLE_PROVIDER(cssProvider),
- GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
- g_object_unref(cssProvider);
-#endif
-}
-
-static void sendPixelResultsEOF()
-{
- puts("#EOF");
-
- fflush(stdout);
- fflush(stderr);
-}
-
-static void runTest(const string& inputLine)
-{
- ASSERT(!inputLine.empty());
-
- TestCommand command = parseInputLine(inputLine);
- string& testURL = command.pathOrURL;
- dumpPixelsForCurrentTest = command.shouldDumpPixels || dumpPixelsForAllTests;
-
- // Convert the path into a full file URL if it does not look
- // like an HTTP/S URL (doesn't start with http:// or https://).
- if (testURL.find("http://") && testURL.find("https://")) {
- GFile* testFile = g_file_new_for_path(testURL.c_str());
- gchar* testURLCString = g_file_get_uri(testFile);
- testURL = testURLCString;
- g_free(testURLCString);
- g_object_unref(testFile);
- }
-
- resetDefaultsToConsistentValues();
-
- gTestRunner = TestRunner::create(testURL, command.expectedPixelHash);
- topLoadingFrame = 0;
- done = false;
-
- gTestRunner->setIconDatabaseEnabled(false);
-
- if (shouldLogFrameLoadDelegates(testURL))
- gTestRunner->setDumpFrameLoadCallbacks(true);
-
- if (shouldEnableDeveloperExtras(testURL)) {
- gTestRunner->setDeveloperExtrasEnabled(true);
- if (shouldOpenWebInspector(testURL))
- gTestRunner->showWebInspector();
- if (shouldDumpAsText(testURL)) {
- gTestRunner->setDumpAsText(true);
- gTestRunner->setGeneratePixelResults(false);
- }
- }
-
- WorkQueue::shared()->clear();
- WorkQueue::shared()->setFrozen(false);
-
- bool isSVGW3CTest = (testURL.find("svg/W3C-SVG-1.1") != string::npos);
- GtkAllocation size;
- size.x = size.y = 0;
- size.width = isSVGW3CTest ? TestRunner::w3cSVGViewWidth : TestRunner::viewWidth;
- size.height = isSVGW3CTest ? TestRunner::w3cSVGViewHeight : TestRunner::viewHeight;
- gtk_window_resize(GTK_WINDOW(window), size.width, size.height);
- gtk_widget_size_allocate(container, &size);
-
- if (prevTestBFItem)
- g_object_unref(prevTestBFItem);
- WebKitWebBackForwardList* bfList = webkit_web_view_get_back_forward_list(webView);
- prevTestBFItem = webkit_web_back_forward_list_get_current_item(bfList);
- if (prevTestBFItem)
- g_object_ref(prevTestBFItem);
-
- initializeFonts(testURL.c_str());
-
- // Focus the web view before loading the test to avoid focusing problems
- gtk_widget_grab_focus(GTK_WIDGET(webView));
- webkit_web_view_open(webView, testURL.c_str());
-
- gtk_main();
-
- // If developer extras enabled Web Inspector may have been open by the test.
- if (shouldEnableDeveloperExtras(testURL)) {
- gTestRunner->closeWebInspector();
- gTestRunner->setDeveloperExtrasEnabled(false);
- }
-
- // Also check if we still have opened webViews and free them.
- if (gTestRunner->closeRemainingWindowsWhenComplete() || webViewList) {
- while (webViewList) {
- g_object_unref(WEBKIT_WEB_VIEW(webViewList->data));
- webViewList = g_slist_next(webViewList);
- }
- g_slist_free(webViewList);
- webViewList = 0;
- }
-
- WebCoreTestSupport::resetInternalsObject(webkit_web_frame_get_global_context(mainFrame));
- DumpRenderTreeSupportGtk::clearMemoryCache();
- DumpRenderTreeSupportGtk::clearApplicationCache();
-
- // A blank load seems to be necessary to reset state after certain tests.
- webkit_web_view_open(webView, "about:blank");
-
- gTestRunner.clear();
-
- // terminate the (possibly empty) pixels block after all the state reset
- sendPixelResultsEOF();
-}
-
-void webViewLoadStarted(WebKitWebView* view, WebKitWebFrame* frame, void*)
-{
- // Make sure we only set this once per test. If it gets cleared, and then set again, we might
- // end up doing two dumps for one test.
- if (!topLoadingFrame && !done)
- topLoadingFrame = frame;
-}
-
-static gboolean processWork(void* data)
-{
- // if we finish all the commands, we're ready to dump state
- if (WorkQueue::shared()->processWork() && !gTestRunner->waitToDump())
- dump();
-
- return FALSE;
-}
-
-static char* getFrameNameSuitableForTestResult(WebKitWebView* view, WebKitWebFrame* frame)
-{
- char* frameName = g_strdup(webkit_web_frame_get_name(frame));
-
- if (frame == webkit_web_view_get_main_frame(view)) {
- // This is a bit strange. Shouldn't web_frame_get_name return NULL?
- if (frameName && (frameName[0] != '\0')) {
- char* tmp = g_strdup_printf("main frame \"%s\"", frameName);
- g_free(frameName);
- frameName = tmp;
- } else {
- g_free(frameName);
- frameName = g_strdup("main frame");
- }
- } else if (!frameName || (frameName[0] == '\0')) {
- g_free(frameName);
- frameName = g_strdup("frame (anonymous)");
- } else {
- char* tmp = g_strdup_printf("frame \"%s\"", frameName);
- g_free(frameName);
- frameName = tmp;
- }
-
- return frameName;
-}
-
-static void webViewLoadFinished(WebKitWebView* view, WebKitWebFrame* frame, void*)
-{
- // The deprecated "load-finished" signal is triggered by postProgressFinishedNotification(),
- // so we can use it here in the DRT to provide the correct dump.
- if (frame != topLoadingFrame)
- return;
- if (gTestRunner->dumpProgressFinishedCallback())
- printf("postProgressFinishedNotification\n");
-}
-
-static gboolean webViewLoadError(WebKitWebView*, WebKitWebFrame*, gchar*, gpointer, gpointer)
-{
- return TRUE; // Return true here to disable the default error page.
-}
-
-static void webViewDocumentLoadFinished(WebKitWebView* view, WebKitWebFrame* frame, void*)
-{
- if (!done && gTestRunner->dumpFrameLoadCallbacks()) {
- char* frameName = getFrameNameSuitableForTestResult(view, frame);
- printf("%s - didFinishDocumentLoadForFrame\n", frameName);
- g_free(frameName);
- } else if (!done) {
- guint pendingFrameUnloadEvents = DumpRenderTreeSupportGtk::getPendingUnloadEventCount(frame);
- if (pendingFrameUnloadEvents) {
- char* frameName = getFrameNameSuitableForTestResult(view, frame);
- printf("%s - has %u onunload handler(s)\n", frameName, pendingFrameUnloadEvents);
- g_free(frameName);
- }
- }
-}
-
-static void webViewOnloadEvent(WebKitWebView* view, WebKitWebFrame* frame, void*)
-{
- if (!done && gTestRunner->dumpFrameLoadCallbacks()) {
- char* frameName = getFrameNameSuitableForTestResult(view, frame);
- printf("%s - didHandleOnloadEventsForFrame\n", frameName);
- g_free(frameName);
- }
-}
-
-static void addControllerToWindow(JSContextRef context, JSObjectRef windowObject, const char* controllerName, JSValueRef controller)
-{
- JSStringRef controllerNameStr = JSStringCreateWithUTF8CString(controllerName);
- JSObjectSetProperty(context, windowObject, controllerNameStr, controller, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0);
- JSStringRelease(controllerNameStr);
-}
-
-static void webViewWindowObjectCleared(WebKitWebView* view, WebKitWebFrame* frame, JSGlobalContextRef context, JSObjectRef windowObject, gpointer data)
-{
- JSValueRef exception = 0;
- ASSERT(gTestRunner);
-
- gTestRunner->makeWindowObject(context, windowObject, &exception);
- ASSERT(!exception);
-
- gcController->makeWindowObject(context, windowObject, &exception);
- ASSERT(!exception);
-
-#if HAVE(ACCESSIBILITY)
- axController->makeWindowObject(context, windowObject, &exception);
- ASSERT(!exception);
-#endif
-
- addControllerToWindow(context, windowObject, "eventSender", makeEventSender(context, !webkit_web_frame_get_parent(frame)));
- addControllerToWindow(context, windowObject, "textInputController", makeTextInputController(context));
- WebCoreTestSupport::injectInternalsObject(context);
-}
-
-static gboolean webViewConsoleMessage(WebKitWebView* view, const gchar* message, unsigned int line, const gchar* sourceId, gpointer data)
-{
- gchar* testMessage = 0;
- const gchar* uriScheme;
-
- // Tests expect only the filename part of local URIs
- uriScheme = g_strstr_len(message, -1, "file://");
- if (uriScheme) {
- GString* tempString = g_string_sized_new(strlen(message));
- gchar* filename = g_strrstr(uriScheme, G_DIR_SEPARATOR_S);
-
- if (filename) {
- // If the path is a lone slash, keep it to avoid empty output.
- if (strlen(filename) > 1)
- filename += strlen(G_DIR_SEPARATOR_S);
- tempString = g_string_append_len(tempString, message, (uriScheme - message));
- tempString = g_string_append_len(tempString, filename, strlen(filename));
- testMessage = g_string_free(tempString, FALSE);
- }
- }
-
- fprintf(stdout, "CONSOLE MESSAGE: ");
- if (line)
- fprintf(stdout, "line %d: ", line);
- fprintf(stdout, "%s\n", testMessage ? testMessage : message);
- g_free(testMessage);
-
- return TRUE;
-}
-
-
-static gboolean webViewScriptAlert(WebKitWebView* view, WebKitWebFrame* frame, const gchar* message, gpointer data)
-{
- fprintf(stdout, "ALERT: %s\n", message);
- fflush(stdout);
- return TRUE;
-}
-
-static gboolean webViewScriptPrompt(WebKitWebView* webView, WebKitWebFrame* frame, const gchar* message, const gchar* defaultValue, gchar** value, gpointer data)
-{
- fprintf(stdout, "PROMPT: %s, default text: %s\n", message, defaultValue);
- *value = g_strdup(defaultValue);
- return TRUE;
-}
-
-static gboolean webViewScriptConfirm(WebKitWebView* view, WebKitWebFrame* frame, const gchar* message, gboolean* didConfirm, gpointer data)
-{
- fprintf(stdout, "CONFIRM: %s\n", message);
- *didConfirm = TRUE;
- return TRUE;
-}
-
-static void webViewTitleChanged(WebKitWebView* view, WebKitWebFrame* frame, const gchar* title, gpointer data)
-{
- if (gTestRunner->dumpFrameLoadCallbacks() && !done) {
- GUniquePtr<char> frameName(getFrameNameSuitableForTestResult(view, frame));
- printf("%s - didReceiveTitle: %s\n", frameName.get(), title ? title : "");
- }
-
- if (gTestRunner->dumpTitleChanges() && !done)
- printf("TITLE CHANGED: '%s'\n", title ? title : "");
-}
-
-static bool webViewNavigationPolicyDecisionRequested(WebKitWebView* view, WebKitWebFrame* frame,
- WebKitNetworkRequest* request,
- WebKitWebNavigationAction* navAction,
- WebKitWebPolicyDecision* policyDecision)
-{
- // Use the default handler if we're not waiting for policy,
- // i.e., TestRunner::waitForPolicyDelegate
- if (!waitForPolicy)
- return FALSE;
-
- gchar* typeDescription;
- WebKitWebNavigationReason reason;
- g_object_get(G_OBJECT(navAction), "reason", &reason, NULL);
-
- switch(reason) {
- case WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED:
- typeDescription = g_strdup("link clicked");
- break;
- case WEBKIT_WEB_NAVIGATION_REASON_FORM_SUBMITTED:
- typeDescription = g_strdup("form submitted");
- break;
- case WEBKIT_WEB_NAVIGATION_REASON_BACK_FORWARD:
- typeDescription = g_strdup("back/forward");
- break;
- case WEBKIT_WEB_NAVIGATION_REASON_RELOAD:
- typeDescription = g_strdup("reload");
- break;
- case WEBKIT_WEB_NAVIGATION_REASON_FORM_RESUBMITTED:
- typeDescription = g_strdup("form resubmitted");
- break;
- case WEBKIT_WEB_NAVIGATION_REASON_OTHER:
- typeDescription = g_strdup("other");
- break;
- default:
- typeDescription = g_strdup("illegal value");
- }
-
- printf("Policy delegate: attempt to load %s with navigation type '%s'\n", webkit_network_request_get_uri(request), typeDescription);
- g_free(typeDescription);
-
- webkit_web_policy_decision_ignore(policyDecision);
- gTestRunner->notifyDone();
-
- return TRUE;
-}
-
-static void webViewStatusBarTextChanged(WebKitWebView* view, const gchar* message, gpointer data)
-{
- // Are we doing anything wrong? One test that does not call
- // dumpStatusCallbacks gets true here
- if (gTestRunner->dumpStatusCallbacks())
- printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", message);
-}
-
-static gboolean webViewClose(WebKitWebView* view)
-{
- ASSERT(view);
-
- webViewList = g_slist_remove(webViewList, view);
- g_object_unref(view);
-
- return TRUE;
-}
-
-static void databaseQuotaExceeded(WebKitWebView* view, WebKitWebFrame* frame, WebKitWebDatabase *database)
-{
- ASSERT(view);
- ASSERT(frame);
- ASSERT(database);
-
- WebKitSecurityOrigin* origin = webkit_web_database_get_security_origin(database);
- if (gTestRunner->dumpDatabaseCallbacks()) {
- printf("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:{%s, %s, %i} database:%s\n",
- webkit_security_origin_get_protocol(origin),
- webkit_security_origin_get_host(origin),
- webkit_security_origin_get_port(origin),
- webkit_web_database_get_name(database));
- }
- webkit_security_origin_set_web_database_quota(origin, 5 * 1024 * 1024);
-}
-
-static bool
-geolocationPolicyDecisionRequested(WebKitWebView*, WebKitWebFrame*, WebKitGeolocationPolicyDecision* decision)
-{
- if (!gTestRunner->isGeolocationPermissionSet())
- return FALSE;
- if (gTestRunner->geolocationPermission())
- webkit_geolocation_policy_allow(decision);
- else
- webkit_geolocation_policy_deny(decision);
-
- return TRUE;
-}
-
-
-static WebKitWebView* webViewCreate(WebKitWebView*, WebKitWebFrame*);
-
-static gboolean webInspectorShowWindow(WebKitWebInspector*, gpointer data)
-{
- gtk_window_set_default_size(GTK_WINDOW(webInspectorWindow), TestRunner::viewWidth, TestRunner::viewHeight);
- gtk_widget_show_all(webInspectorWindow);
- return TRUE;
-}
-
-static gboolean webInspectorCloseWindow(WebKitWebInspector*, gpointer data)
-{
- gtk_widget_destroy(webInspectorWindow);
- webInspectorWindow = 0;
- return TRUE;
-}
-
-static WebKitWebView* webInspectorInspectWebView(WebKitWebInspector*, gpointer data)
-{
- webInspectorWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-
- GtkWidget* webView = self_scrolling_webkit_web_view_new();
- gtk_container_add(GTK_CONTAINER(webInspectorWindow),
- webView);
-
- return WEBKIT_WEB_VIEW(webView);
-}
-
-static void topLoadingFrameLoadFinished()
-{
- topLoadingFrame = 0;
- WorkQueue::shared()->setFrozen(true); // first complete load freezes the queue for the rest of this test
- if (gTestRunner->waitToDump())
- return;
-
- if (WorkQueue::shared()->count())
- g_idle_add_full(G_PRIORITY_DEFAULT, processWork, 0, 0);
- else
- dump();
-}
-
-static void webFrameLoadStatusNotified(WebKitWebFrame* frame, gpointer user_data)
-{
- WebKitLoadStatus loadStatus = webkit_web_frame_get_load_status(frame);
-
- if (gTestRunner->dumpFrameLoadCallbacks()) {
- GUniquePtr<char> frameName(getFrameNameSuitableForTestResult(webkit_web_frame_get_web_view(frame), frame));
-
- switch (loadStatus) {
- case WEBKIT_LOAD_PROVISIONAL:
- if (!done)
- printf("%s - didStartProvisionalLoadForFrame\n", frameName.get());
- break;
- case WEBKIT_LOAD_COMMITTED:
- if (!done)
- printf("%s - didCommitLoadForFrame\n", frameName.get());
- break;
- case WEBKIT_LOAD_FINISHED:
- if (!done)
- printf("%s - didFinishLoadForFrame\n", frameName.get());
- break;
- case WEBKIT_LOAD_FAILED:
- if (!done)
- printf("%s - didFailLoadWithError\n", frameName.get());
- break;
- default:
- break;
- }
- }
-
- if ((loadStatus == WEBKIT_LOAD_FINISHED || loadStatus == WEBKIT_LOAD_FAILED)
- && frame == topLoadingFrame)
- topLoadingFrameLoadFinished();
-}
-
-static void frameCreatedCallback(WebKitWebView* webView, WebKitWebFrame* webFrame, gpointer user_data)
-{
- g_signal_connect(webFrame, "notify::load-status", G_CALLBACK(webFrameLoadStatusNotified), NULL);
- g_signal_connect(webFrame, "insecure-content-run", G_CALLBACK(didRunInsecureContent), NULL);
-}
-
-static String pathFromSoupURI(SoupURI* uri)
-{
- if (!uri)
- return "(null)";
-
- if (!g_str_equal(uri->scheme, "file"))
- return soupURIToStringPreservingPassword(uri).data();
-
- String pathString = uri->path;
- GUniquePtr<gchar> pathBasename(g_path_get_basename(pathString.utf8().data()));
-
- WebKitWebFrame* mainFrame = webkit_web_view_get_main_frame(webView);
- GUniquePtr<SoupURI> mainFrameUri(soup_uri_new(webkit_web_frame_get_uri(mainFrame)));
-
- String mainFrameUriPathString = mainFrameUri.get()->path;
- String basePath = mainFrameUriPathString.substring(0, mainFrameUriPathString.reverseFind('/') + 1);
-
- if (!basePath.isEmpty() && pathString.startsWith(basePath))
- return pathString.substring(basePath.length());
-
- return pathBasename.get();
-}
-
-static CString convertSoupMessageToURLPath(SoupMessage* soupMessage)
-{
- if (!soupMessage)
- return CString("(null)");
- if (SoupURI* requestURI = soup_message_get_uri(soupMessage))
- return pathFromSoupURI(requestURI).utf8();
- return CString("(null)");
-}
-
-static CString convertNetworkRequestToURLPath(WebKitNetworkRequest* request)
-{
- return convertSoupMessageToURLPath(webkit_network_request_get_message(request));
-}
-
-static CString convertWebResourceToURLPath(WebKitWebResource* webResource)
-{
- GUniquePtr<SoupURI> uri(soup_uri_new(webkit_web_resource_get_uri(webResource)));
- return pathFromSoupURI(uri.get()).utf8();
-}
-
-static CString urlSuitableForTestResult(const char* uriString)
-{
- if (!g_str_has_prefix(uriString, "file://"))
- return CString(uriString);
-
- GUniquePtr<gchar> basename(g_path_get_basename(uriString));
- return CString(basename.get());
-}
-
-static CString descriptionSuitableForTestResult(SoupURI* uri)
-{
- if (!uri)
- return CString("(null)");
-
- GUniquePtr<char> uriString(soup_uri_to_string(uri, false));
- return urlSuitableForTestResult(uriString.get());
-}
-
-static CString descriptionSuitableForTestResult(GError* error, WebKitWebResource* webResource)
-{
- const gchar* errorDomain = g_quark_to_string(error->domain);
- CString resourceURIString(urlSuitableForTestResult(webkit_web_resource_get_uri(webResource)));
-
- if (g_str_equal(errorDomain, "webkit-network-error-quark") || g_str_equal(errorDomain, "soup_http_error_quark"))
- errorDomain = "NSURLErrorDomain";
-
- if (g_str_equal(errorDomain, "WebKitPolicyError"))
- errorDomain = "WebKitErrorDomain";
-
- // TODO: the other ports get the failingURL from the ResourceError
- GUniquePtr<char> errorString(g_strdup_printf("<NSError domain %s, code %d, failing URL \"%s\">",
- errorDomain, error->code, resourceURIString.data()));
- return CString(errorString.get());
-}
-
-static CString descriptionSuitableForTestResult(WebKitNetworkRequest* request)
-{
- SoupMessage* soupMessage = webkit_network_request_get_message(request);
-
- if (!soupMessage)
- return CString("(null)");
-
- SoupURI* mainDocumentURI = soup_message_get_first_party(soupMessage);
- CString mainDocumentURIString(descriptionSuitableForTestResult(mainDocumentURI));
- CString path(convertNetworkRequestToURLPath(request));
- GUniquePtr<char> description(g_strdup_printf("<NSURLRequest URL %s, main document URL %s, http method %s>",
- path.data(), mainDocumentURIString.data(), soupMessage->method));
- return CString(description.get());
-}
-
-static CString descriptionSuitableForTestResult(WebKitNetworkResponse* response)
-{
- if (!response)
- return CString("(null)");
-
- int statusCode = 0;
- CString responseURIString(urlSuitableForTestResult(webkit_network_response_get_uri(response)));
- SoupMessage* soupMessage = webkit_network_response_get_message(response);
- CString path;
-
- if (soupMessage) {
- statusCode = soupMessage->status_code;
- path = convertSoupMessageToURLPath(soupMessage);
- } else
- path = CString("(null)");
-
- GUniquePtr<char> description(g_strdup_printf("<NSURLResponse %s, http status code %d>", path.data(), statusCode));
- return CString(description.get());
-}
-
-static void willSendRequestCallback(WebKitWebView* webView, WebKitWebFrame* webFrame, WebKitWebResource* resource, WebKitNetworkRequest* request, WebKitNetworkResponse* response)
-{
-
-
- if (!done && gTestRunner->willSendRequestReturnsNull()) {
- // As requested by the TestRunner, don't perform the request.
- webkit_network_request_set_uri(request, "about:blank");
- return;
- }
-
- if (!done && gTestRunner->dumpResourceLoadCallbacks())
- printf("%s - willSendRequest %s redirectResponse %s\n",
- convertNetworkRequestToURLPath(request).data(),
- descriptionSuitableForTestResult(request).data(),
- descriptionSuitableForTestResult(response).data());
-
- SoupMessage* soupMessage = webkit_network_request_get_message(request);
- SoupURI* uri = soup_uri_new(webkit_network_request_get_uri(request));
-
- if (SOUP_URI_IS_VALID(uri)) {
- GUniquePtr<char> uriString(soup_uri_to_string(uri, FALSE));
-
- if (SOUP_URI_VALID_FOR_HTTP(uri) && g_strcmp0(uri->host, "127.0.0.1")
- && g_strcmp0(uri->host, "255.255.255.255")
- && g_ascii_strncasecmp(uri->host, "localhost", 9)) {
- printf("Blocked access to external URL %s\n", uriString.get());
- // Cancel load of blocked resource to avoid potential
- // network-related timeouts in tests.
- webkit_network_request_set_uri(request, "about:blank");
- soup_uri_free(uri);
- return;
- }
-
- const string& destination = gTestRunner->redirectionDestinationForURL(uriString.get());
- if (!destination.empty())
- webkit_network_request_set_uri(request, destination.c_str());
- }
-
- if (uri)
- soup_uri_free(uri);
-
- if (soupMessage) {
- const set<string>& clearHeaders = gTestRunner->willSendRequestClearHeaders();
- for (set<string>::const_iterator header = clearHeaders.begin(); header != clearHeaders.end(); ++header)
- soup_message_headers_remove(soupMessage->request_headers, header->c_str());
- }
-}
-
-
-static void didReceiveResponse(WebKitWebView* webView, WebKitWebFrame*, WebKitWebResource* webResource, WebKitNetworkResponse* response)
-{
- if (!done && gTestRunner->dumpResourceLoadCallbacks()) {
- CString responseDescription(descriptionSuitableForTestResult(response));
- CString path(convertWebResourceToURLPath(webResource));
- printf("%s - didReceiveResponse %s\n", path.data(), responseDescription.data());
- }
-
- // TODO: add "has MIME type" whenever dumpResourceResponseMIMETypes() is supported.
- // See https://bugs.webkit.org/show_bug.cgi?id=58222.
-}
-
-static void didFinishLoading(WebKitWebView* webView, WebKitWebFrame* webFrame, WebKitWebResource* webResource)
-{
- if (!done && gTestRunner->dumpResourceLoadCallbacks())
- printf("%s - didFinishLoading\n", convertWebResourceToURLPath(webResource).data());
-}
-
-static void didFailLoadingWithError(WebKitWebView* webView, WebKitWebFrame* webFrame, WebKitWebResource* webResource, GError* webError)
-{
- if (!done && gTestRunner->dumpResourceLoadCallbacks()) {
- CString webErrorString(descriptionSuitableForTestResult(webError, webResource));
- printf("%s - didFailLoadingWithError: %s\n", convertWebResourceToURLPath(webResource).data(),
- webErrorString.data());
- }
-}
-
-static void didRunInsecureContent(WebKitWebFrame*, WebKitSecurityOrigin*, const char* url)
-{
- if (!done && gTestRunner->dumpFrameLoadCallbacks())
- printf("didRunInsecureContent\n");
-}
-
-static gboolean webViewRunFileChooser(WebKitWebView*, WebKitFileChooserRequest*)
-{
- // We return TRUE to not propagate the event further so the
- // default file chooser dialog is not shown.
- return TRUE;
-}
-
-static void frameLoadEventCallback(WebKitWebFrame* frame, DumpRenderTreeSupportGtk::FrameLoadEvent event, const char* url)
-{
- if (done || !gTestRunner->dumpFrameLoadCallbacks())
- return;
-
- GUniquePtr<char> frameName(getFrameNameSuitableForTestResult(webkit_web_frame_get_web_view(frame), frame));
- switch (event) {
- case DumpRenderTreeSupportGtk::WillPerformClientRedirectToURL:
- ASSERT(url);
- printf("%s - willPerformClientRedirectToURL: %s \n", frameName.get(), url);
- break;
- case DumpRenderTreeSupportGtk::DidCancelClientRedirect:
- printf("%s - didCancelClientRedirectForFrame\n", frameName.get());
- break;
- case DumpRenderTreeSupportGtk::DidReceiveServerRedirectForProvisionalLoad:
- printf("%s - didReceiveServerRedirectForProvisionalLoadForFrame\n", frameName.get());
- break;
- case DumpRenderTreeSupportGtk::DidDisplayInsecureContent:
- printf ("didDisplayInsecureContent\n");
- break;
- case DumpRenderTreeSupportGtk::DidDetectXSS:
- printf ("didDetectXSS\n");
- break;
- default:
- ASSERT_NOT_REACHED();
- }
-}
-
-static bool authenticationCallback(CString& username, CString& password, WebKitWebResource* webResource)
-{
- CString description(convertWebResourceToURLPath(webResource));
-
- if (!gTestRunner->handlesAuthenticationChallenges()) {
- printf("%s - didReceiveAuthenticationChallenge - Simulating cancelled authentication sheet\n", description.data());
- return false;
- }
-
- username = gTestRunner->authenticationUsername().c_str();
- password = gTestRunner->authenticationPassword().c_str();
- printf("%s - didReceiveAuthenticationChallenge - Responding with %s:%s\n", description.data(), username.data(), password.data());
- return true;
-}
-
-static WebKitWebView* createWebView()
-{
- // It is important to declare DRT is running early so when creating
- // web view mock clients are used instead of proper ones.
- DumpRenderTreeSupportGtk::setDumpRenderTreeModeEnabled(true);
-
- DumpRenderTreeSupportGtk::setFrameLoadEventCallback(frameLoadEventCallback);
- DumpRenderTreeSupportGtk::setAuthenticationCallback(authenticationCallback);
-
- WebKitWebView* view = WEBKIT_WEB_VIEW(self_scrolling_webkit_web_view_new());
-
- g_object_connect(G_OBJECT(view),
- "signal::load-started", webViewLoadStarted, 0,
- "signal::load-finished", webViewLoadFinished, 0,
- "signal::load-error", webViewLoadError, 0,
- "signal::window-object-cleared", webViewWindowObjectCleared, 0,
- "signal::console-message", webViewConsoleMessage, 0,
- "signal::script-alert", webViewScriptAlert, 0,
- "signal::script-prompt", webViewScriptPrompt, 0,
- "signal::script-confirm", webViewScriptConfirm, 0,
- "signal::title-changed", webViewTitleChanged, 0,
- "signal::navigation-policy-decision-requested", webViewNavigationPolicyDecisionRequested, 0,
- "signal::status-bar-text-changed", webViewStatusBarTextChanged, 0,
- "signal::create-web-view", webViewCreate, 0,
- "signal::close-web-view", webViewClose, 0,
- "signal::database-quota-exceeded", databaseQuotaExceeded, 0,
- "signal::document-load-finished", webViewDocumentLoadFinished, 0,
- "signal::geolocation-policy-decision-requested", geolocationPolicyDecisionRequested, 0,
- "signal::onload-event", webViewOnloadEvent, 0,
- "signal::drag-begin", dragBeginCallback, 0,
- "signal::drag-end", dragEndCallback, 0,
- "signal::drag-failed", dragFailedCallback, 0,
- "signal::frame-created", frameCreatedCallback, 0,
- "signal::resource-request-starting", willSendRequestCallback, 0,
- "signal::resource-response-received", didReceiveResponse, 0,
- "signal::resource-load-finished", didFinishLoading, 0,
- "signal::resource-load-failed", didFailLoadingWithError, 0,
- "signal::run-file-chooser", webViewRunFileChooser, 0,
- NULL);
- connectEditingCallbacks(view);
-
- WebKitWebInspector* inspector = webkit_web_view_get_inspector(view);
- g_object_connect(G_OBJECT(inspector),
- "signal::inspect-web-view", webInspectorInspectWebView, 0,
- "signal::show-window", webInspectorShowWindow, 0,
- "signal::close-window", webInspectorCloseWindow, 0,
- NULL);
-
- if (webView) {
- WebKitWebSettings* settings = webkit_web_view_get_settings(webView);
- webkit_web_view_set_settings(view, settings);
- }
-
- // frame-created is not issued for main frame. That's why we must do this here
- WebKitWebFrame* frame = webkit_web_view_get_main_frame(view);
- g_signal_connect(frame, "notify::load-status", G_CALLBACK(webFrameLoadStatusNotified), NULL);
- g_signal_connect(frame, "insecure-content-run", G_CALLBACK(didRunInsecureContent), NULL);
-
- return view;
-}
-
-static WebKitWebView* webViewCreate(WebKitWebView* view, WebKitWebFrame* frame)
-{
- if (!gTestRunner->canOpenWindows())
- return 0;
-
- // Make sure that waitUntilDone has been called.
- ASSERT(gTestRunner->waitToDump());
-
- WebKitWebView* newWebView = createWebView();
- g_object_ref_sink(G_OBJECT(newWebView));
- webViewList = g_slist_prepend(webViewList, newWebView);
- return newWebView;
-}
-
-static void logHandler(const gchar* domain, GLogLevelFlags level, const gchar* message, gpointer data)
-{
- if (level < G_LOG_LEVEL_DEBUG)
- fprintf(stderr, "%s\n", message);
-}
-
-int main(int argc, char* argv[])
-{
- gtk_init(&argc, &argv);
-
- // Some plugins might try to use the GLib logger for printing debug
- // messages. This will cause tests to fail because of unexpected output.
- // We squelch all debug messages sent to the logger.
- g_log_set_default_handler(logHandler, 0);
-
- initializeGlobalsFromCommandLineOptions(argc, argv);
- initializeFonts();
-
- window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-#ifdef GTK_API_VERSION_2
- container = gtk_hbox_new(TRUE, 0);
-#else
- container = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
- gtk_box_set_homogeneous(GTK_BOX(container), TRUE);
-#endif
- gtk_container_add(GTK_CONTAINER(window), container);
- gtk_widget_show_all(window);
-
- webView = createWebView();
- gtk_box_pack_start(GTK_BOX(container), GTK_WIDGET(webView), TRUE, TRUE, 0);
- gtk_widget_realize(GTK_WIDGET(webView));
- gtk_widget_show_all(container);
- mainFrame = webkit_web_view_get_main_frame(webView);
-
- setDefaultsToConsistentStateValuesForTesting();
-
- gcController = new GCController();
-#if HAVE(ACCESSIBILITY)
- axController = new AccessibilityController();
-#endif
-
- if (useLongRunningServerMode(argc, argv)) {
- printSeparators = true;
- runTestingServerLoop();
- } else {
- printSeparators = (optind < argc-1 || (dumpPixelsForCurrentTest && dumpTree));
- for (int i = optind; i != argc; ++i)
- runTest(argv[i]);
- }
-
- delete gcController;
- gcController = 0;
-
-#if HAVE(ACCESSIBILITY)
- delete axController;
- axController = 0;
-#endif
-
- gtk_widget_destroy(window);
-
- return 0;
-}
diff --git a/Tools/DumpRenderTree/gtk/DumpRenderTreeGtk.h b/Tools/DumpRenderTree/gtk/DumpRenderTreeGtk.h
deleted file mode 100644
index 4b33458f3..000000000
--- a/Tools/DumpRenderTree/gtk/DumpRenderTreeGtk.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef DumpRenderTreeGtk_h
-#define DumpRenderTreeGtk_h
-
-#include <JavaScriptCore/JSBase.h>
-#include <glib.h>
-#include <libsoup/soup.h>
-#include <webkit/webkitdefines.h>
-#include <wtf/text/CString.h>
-
-extern WebKitWebFrame* mainFrame;
-extern WebKitWebFrame* topLoadingFrame;
-extern bool waitForPolicy;
-extern GSList* webViewList;
-
-gchar* JSStringCopyUTF8CString(JSStringRef jsString);
-CString getTopLevelPath();
-
-void setWaitToDumpWatchdog(guint timer);
-bool shouldSetWaitToDumpWatchdog();
-CString soupURIToStringPreservingPassword(SoupURI* soupURI);
-
-#endif // DumpRenderTreeGtk_h
diff --git a/Tools/DumpRenderTree/gtk/EditingCallbacks.cpp b/Tools/DumpRenderTree/gtk/EditingCallbacks.cpp
deleted file mode 100644
index 3c08f80b3..000000000
--- a/Tools/DumpRenderTree/gtk/EditingCallbacks.cpp
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2010 Igalia S.L.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "EditingCallbacks.h"
-
-#include "DumpRenderTree.h"
-#include "TestRunner.h"
-#include <gtk/gtk.h>
-#include <webkit/webkit.h>
-#include <wtf/gobject/GUniquePtr.h>
-#include <wtf/text/CString.h>
-
-static CString dumpNodePath(WebKitDOMNode* node)
-{
- GUniquePtr<gchar> nodeName(webkit_dom_node_get_node_name(node));
- GString* path = g_string_new(nodeName.get());
-
- WebKitDOMNode* parent = webkit_dom_node_get_parent_node(node);
- while (parent) {
- GUniquePtr<gchar> parentName(webkit_dom_node_get_node_name(parent));
-
- g_string_append(path, " > ");
- g_string_append(path, parentName.get());
- parent = webkit_dom_node_get_parent_node(parent);
- }
-
- GUniquePtr<gchar> pathBuffer(g_string_free(path, FALSE));
- return pathBuffer.get();
-}
-
-static CString dumpRange(WebKitDOMRange* range)
-{
- if (!range)
- return "(null)";
-
- GUniquePtr<gchar> dump(g_strdup_printf("range from %li of %s to %li of %s",
- webkit_dom_range_get_start_offset(range, 0),
- dumpNodePath(webkit_dom_range_get_start_container(range, 0)).data(),
- webkit_dom_range_get_end_offset(range, 0),
- dumpNodePath(webkit_dom_range_get_end_container(range, 0)).data()));
-
- return dump.get();
-}
-
-static const char* insertActionString(WebKitInsertAction action)
-{
- switch (action) {
- case WEBKIT_INSERT_ACTION_TYPED:
- return "WebViewInsertActionTyped";
- case WEBKIT_INSERT_ACTION_PASTED:
- return "WebViewInsertActionPasted";
- case WEBKIT_INSERT_ACTION_DROPPED:
- return "WebViewInsertActionDropped";
- }
- ASSERT_NOT_REACHED();
- return "WebViewInsertActionTyped";
-}
-
-static const char* selectionAffinityString(WebKitSelectionAffinity affinity)
-{
- switch (affinity) {
- case WEBKIT_SELECTION_AFFINITY_UPSTREAM:
- return "NSSelectionAffinityUpstream";
- case WEBKIT_SELECTION_AFFINITY_DOWNSTREAM:
- return "NSSelectionAffinityDownstream";
- }
- ASSERT_NOT_REACHED();
- return "NSSelectionAffinityUpstream";
-}
-
-gboolean shouldBeginEditing(WebKitWebView* webView, WebKitDOMRange* range)
-{
- if (!done && gTestRunner->dumpEditingCallbacks())
- printf("EDITING DELEGATE: shouldBeginEditingInDOMRange:%s\n", dumpRange(range).data());
- return TRUE;
-}
-
-gboolean shouldEndEditing(WebKitWebView* webView, WebKitDOMRange* range)
-{
- if (!done && gTestRunner->dumpEditingCallbacks())
- printf("EDITING DELEGATE: shouldEndEditingInDOMRange:%s\n", dumpRange(range).data());
- return TRUE;
-}
-
-gboolean shouldInsertNode(WebKitWebView* webView, WebKitDOMNode* node, WebKitDOMRange* range, WebKitInsertAction action)
-{
- if (!done && gTestRunner->dumpEditingCallbacks()) {
- printf("EDITING DELEGATE: shouldInsertNode:%s replacingDOMRange:%s givenAction:%s\n",
- dumpNodePath(node).data(), dumpRange(range).data(), insertActionString(action));
- }
- return TRUE;
-}
-
-gboolean shouldInsertText(WebKitWebView* webView, const gchar* text, WebKitDOMRange* range, WebKitInsertAction action)
-{
- if (!done && gTestRunner->dumpEditingCallbacks()) {
- printf("EDITING DELEGATE: shouldInsertText:%s replacingDOMRange:%s givenAction:%s\n",
- text, dumpRange(range).data(), insertActionString(action));
- }
- return TRUE;
-}
-
-gboolean shouldDeleteRange(WebKitWebView* webView, WebKitDOMRange* range)
-{
- if (!done && gTestRunner->dumpEditingCallbacks())
- printf("EDITING DELEGATE: shouldDeleteDOMRange:%s\n", dumpRange(range).data());
- return TRUE;
-}
-
-gboolean shouldShowDeleteInterfaceForElement(WebKitWebView* webView, WebKitDOMHTMLElement* element)
-{
- return FALSE;
-}
-
-gboolean shouldChangeSelectedRange(WebKitWebView* webView, WebKitDOMRange* fromRange, WebKitDOMRange* toRange, WebKitSelectionAffinity affinity, gboolean stillSelecting)
-{
- if (!done && gTestRunner->dumpEditingCallbacks()) {
- printf("EDITING DELEGATE: shouldChangeSelectedDOMRange:%s toDOMRange:%s affinity:%s stillSelecting:%s\n",
- dumpRange(fromRange).data(), dumpRange(toRange).data(), selectionAffinityString(affinity),
- stillSelecting ? "TRUE" : "FALSE");
- }
- return TRUE;
-}
-
-gboolean shouldApplyStyle(WebKitWebView* webView, WebKitDOMCSSStyleDeclaration* style, WebKitDOMRange* range)
-{
- if (!done && gTestRunner->dumpEditingCallbacks()) {
- GUniquePtr<gchar> styleText(webkit_dom_css_style_declaration_get_css_text(style));
- printf("EDITING DELEGATE: shouldApplyStyle:%s toElementsInDOMRange:%s\n",
- styleText.get(), dumpRange(range).data());
- }
- return TRUE;
-}
-
-void editingBegan(WebKitWebView*)
-{
- if (!done && gTestRunner->dumpEditingCallbacks())
- printf("EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification\n");
-}
-
-void userChangedContents(WebKitWebView*)
-{
- if (!done && gTestRunner->dumpEditingCallbacks())
- printf("EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification\n");
-}
-
-void editingEnded(WebKitWebView*)
-{
- if (!done && gTestRunner->dumpEditingCallbacks())
- printf("EDITING DELEGATE: webViewDidEndEditing:WebViewDidEndEditingNotification\n");
-}
-
-void selectionChanged(WebKitWebView*)
-{
- if (!done && gTestRunner->dumpEditingCallbacks())
- printf("EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification\n");
-}
-
-void connectEditingCallbacks(WebKitWebView* webView)
-{
- g_object_connect(G_OBJECT(webView),
- "signal::should-begin-editing", shouldBeginEditing, 0,
- "signal::should-end-editing", shouldEndEditing, 0,
- "signal::should-insert-node", shouldInsertNode, 0,
- "signal::should-insert-text", shouldInsertText, 0,
- "signal::should-delete-range", shouldDeleteRange, 0,
- "signal::should-show-delete-interface-for-element", shouldShowDeleteInterfaceForElement, 0,
- "signal::should-change-selected-range", shouldChangeSelectedRange, 0,
- "signal::should-apply-style", shouldApplyStyle, 0,
- "signal::editing-began", editingBegan, 0,
- "signal::user-changed-contents", userChangedContents, 0,
- "signal::editing-ended", editingEnded, 0,
- "signal::selection-changed", selectionChanged, 0,
- NULL);
-}
-
diff --git a/Tools/DumpRenderTree/gtk/EventSender.cpp b/Tools/DumpRenderTree/gtk/EventSender.cpp
deleted file mode 100644
index bd8e4fb8f..000000000
--- a/Tools/DumpRenderTree/gtk/EventSender.cpp
+++ /dev/null
@@ -1,1004 +0,0 @@
-/*
- * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
- * Copyright (C) 2009 Zan Dobersek <zandobersek@gmail.com>
- * Copyright (C) 2009 Holger Hans Peter Freyther
- * Copyright (C) 2010 Igalia S.L.
- * Copyright (C) 2012 ChangSeok Oh <shivamidow@gmail.com>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "EventSender.h"
-
-#include "DumpRenderTree.h"
-#include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
-#include <GRefPtrGtk.h>
-#include <GtkVersioning.h>
-#include <JavaScriptCore/JSObjectRef.h>
-#include <JavaScriptCore/JSRetainPtr.h>
-#include <JavaScriptCore/JSStringRef.h>
-#include <cstring>
-#include <gdk/gdk.h>
-#include <gdk/gdkkeysyms.h>
-#include <webkit/webkitwebframe.h>
-#include <webkit/webkitwebview.h>
-#include <wtf/ASCIICType.h>
-#include <wtf/Platform.h>
-#include <wtf/gobject/GUniquePtr.h>
-#include <wtf/text/CString.h>
-
-extern "C" {
- extern GtkMenu* webkit_web_view_get_context_menu(WebKitWebView*);
-}
-
-static bool dragMode;
-static int timeOffset = 0;
-
-static int lastMousePositionX;
-static int lastMousePositionY;
-static int lastClickPositionX;
-static int lastClickPositionY;
-static int lastClickTimeOffset;
-static int lastClickButton;
-static unsigned buttonCurrentlyDown;
-static int clickCount;
-GdkDragContext* currentDragSourceContext;
-
-struct DelayedMessage {
- GdkEvent* event;
- gulong delay;
-};
-
-static DelayedMessage msgQueue[1024];
-
-static unsigned endOfQueue;
-static unsigned startOfQueue;
-
-static const float zoomMultiplierRatio = 1.2f;
-
-// WebCore and layout tests assume this value.
-static const float pixelsPerScrollTick = 40;
-
-// Key event location code defined in DOM Level 3.
-enum KeyLocationCode {
- DOM_KEY_LOCATION_STANDARD = 0x00,
- DOM_KEY_LOCATION_LEFT = 0x01,
- DOM_KEY_LOCATION_RIGHT = 0x02,
- DOM_KEY_LOCATION_NUMPAD = 0x03
-};
-
-static void sendOrQueueEvent(GdkEvent*, bool = true);
-static void dispatchEvent(GdkEvent* event);
-static guint getStateFlags();
-
-static JSValueRef getDragModeCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
-{
- return JSValueMakeBoolean(context, dragMode);
-}
-
-static bool setDragModeCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
-{
- dragMode = JSValueToBoolean(context, value);
- return true;
-}
-
-static JSValueRef leapForwardCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- if (argumentCount > 0) {
- msgQueue[endOfQueue].delay = JSValueToNumber(context, arguments[0], exception);
- timeOffset += msgQueue[endOfQueue].delay;
- ASSERT(!exception || !*exception);
- }
-
- return JSValueMakeUndefined(context);
-}
-
-bool prepareMouseButtonEvent(GdkEvent* event, int eventSenderButtonNumber, guint modifiers)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- if (!view)
- return false;
-
- // The logic for mapping EventSender button numbers to GDK button
- // numbers originates from the Windows EventSender.
- int gdkButtonNumber = 3;
- if (eventSenderButtonNumber >= 0 && eventSenderButtonNumber <= 2)
- gdkButtonNumber = eventSenderButtonNumber + 1;
-
- // fast/events/mouse-click-events expects the 4th button
- // to be event->button = 1, so send a middle-button event.
- else if (eventSenderButtonNumber == 3)
- gdkButtonNumber = 2;
-
- event->button.button = gdkButtonNumber;
- event->button.x = lastMousePositionX;
- event->button.y = lastMousePositionY;
- event->button.window = gtk_widget_get_window(GTK_WIDGET(view));
- g_object_ref(event->button.window);
- event->button.device = getDefaultGDKPointerDevice(event->button.window);
- event->button.state = modifiers | getStateFlags();
- event->button.time = GDK_CURRENT_TIME;
- event->button.axes = 0;
-
- int xRoot, yRoot;
- gdk_window_get_root_coords(gtk_widget_get_window(GTK_WIDGET(view)), lastMousePositionX, lastMousePositionY, &xRoot, &yRoot);
- event->button.x_root = xRoot;
- event->button.y_root = yRoot;
-
- return true;
-}
-
-static JSValueRef getMenuItemTitleCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
-{
- GtkWidget* widget = GTK_WIDGET(JSObjectGetPrivate(object));
- CString label;
- if (GTK_IS_SEPARATOR_MENU_ITEM(widget))
- label = "<separator>";
- else
- label = gtk_menu_item_get_label(GTK_MENU_ITEM(widget));
-
- JSRetainPtr<JSStringRef> itemText(Adopt, JSStringCreateWithUTF8CString(label.data()));
- return JSValueMakeString(context, itemText.get());
-}
-
-static bool setMenuItemTitleCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
-{
- return true;
-}
-
-static JSValueRef menuItemClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- GtkMenuItem* item = GTK_MENU_ITEM(JSObjectGetPrivate(thisObject));
- gtk_menu_item_activate(item);
- return JSValueMakeUndefined(context);
-}
-
-static JSStaticFunction staticMenuItemFunctions[] = {
- { "click", menuItemClickCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { 0, 0, 0 }
-};
-
-static JSStaticValue staticMenuItemValues[] = {
- { "title", getMenuItemTitleCallback, setMenuItemTitleCallback, kJSPropertyAttributeNone },
- { 0, 0, 0, 0 }
-};
-
-static JSClassRef getMenuItemClass()
-{
- static JSClassRef menuItemClass = 0;
-
- if (!menuItemClass) {
- JSClassDefinition classDefinition = {
- 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- classDefinition.staticFunctions = staticMenuItemFunctions;
- classDefinition.staticValues = staticMenuItemValues;
-
- menuItemClass = JSClassCreate(&classDefinition);
- }
-
- return menuItemClass;
-}
-
-
-static JSValueRef contextClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- GdkEvent* pressEvent = gdk_event_new(GDK_BUTTON_PRESS);
-
- if (!prepareMouseButtonEvent(pressEvent, 2, 0)) {
- gdk_event_free(pressEvent);
- return JSObjectMakeArray(context, 0, 0, 0);
- }
-
- GdkEvent* releaseEvent = gdk_event_copy(pressEvent);
- sendOrQueueEvent(pressEvent);
-
- JSValueRef valueRef = JSObjectMakeArray(context, 0, 0, 0);
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- GtkMenu* gtkMenu = webkit_web_view_get_context_menu(view);
- if (gtkMenu) {
- GUniquePtr<GList> items(gtk_container_get_children(GTK_CONTAINER(gtkMenu)));
- JSValueRef arrayValues[g_list_length(items.get())];
- int index = 0;
- for (GList* item = g_list_first(items.get()); item; item = g_list_next(item)) {
- arrayValues[index] = JSObjectMake(context, getMenuItemClass(), item->data);
- index++;
- }
- if (index)
- valueRef = JSObjectMakeArray(context, index - 1, arrayValues, 0);
- }
-
- releaseEvent->type = GDK_BUTTON_RELEASE;
- sendOrQueueEvent(releaseEvent);
- return valueRef;
-}
-
-static gboolean sendClick(gpointer)
-{
- GdkEvent* pressEvent = gdk_event_new(GDK_BUTTON_PRESS);
-
- if (!prepareMouseButtonEvent(pressEvent, 1, 0)) {
- gdk_event_free(pressEvent);
- return FALSE;
- }
-
- GdkEvent* releaseEvent = gdk_event_copy(pressEvent);
- dispatchEvent(pressEvent);
- releaseEvent->type = GDK_BUTTON_RELEASE;
- dispatchEvent(releaseEvent);
-
- return FALSE;
-}
-
-static JSValueRef scheduleAsynchronousClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- g_idle_add_full(G_PRIORITY_DEFAULT, sendClick, 0, 0);
- return JSValueMakeUndefined(context);
-}
-
-static void updateClickCount(int button)
-{
- if (lastClickPositionX != lastMousePositionX
- || lastClickPositionY != lastMousePositionY
- || lastClickButton != button
- || timeOffset - lastClickTimeOffset >= 1)
- clickCount = 1;
- else
- clickCount++;
-}
-
-static guint gdkModifierFromJSValue(JSContextRef context, const JSValueRef value)
-{
- JSStringRef string = JSValueToStringCopy(context, value, 0);
- guint gdkModifier = 0;
- if (JSStringIsEqualToUTF8CString(string, "ctrlKey")
- || JSStringIsEqualToUTF8CString(string, "addSelectionKey"))
- gdkModifier = GDK_CONTROL_MASK;
- else if (JSStringIsEqualToUTF8CString(string, "shiftKey")
- || JSStringIsEqualToUTF8CString(string, "rangeSelectionKey"))
- gdkModifier = GDK_SHIFT_MASK;
- else if (JSStringIsEqualToUTF8CString(string, "altKey"))
- gdkModifier = GDK_MOD1_MASK;
-
- // Currently the metaKey as defined in WebCore/platform/gtk/PlatformMouseEventGtk.cpp
- // is GDK_META_MASK. This code must be kept in sync with that file.
- else if (JSStringIsEqualToUTF8CString(string, "metaKey"))
- gdkModifier = GDK_META_MASK;
-
- JSStringRelease(string);
- return gdkModifier;
-}
-
-static guint gdkModifersFromJSValue(JSContextRef context, const JSValueRef modifiers)
-{
- // The value may either be a string with a single modifier or an array of modifiers.
- if (JSValueIsString(context, modifiers))
- return gdkModifierFromJSValue(context, modifiers);
-
- JSObjectRef modifiersArray = JSValueToObject(context, modifiers, 0);
- if (!modifiersArray)
- return 0;
-
- guint gdkModifiers = 0;
- JSRetainPtr<JSStringRef> lengthProperty(Adopt, JSStringCreateWithUTF8CString("length"));
- int modifiersCount = JSValueToNumber(context, JSObjectGetProperty(context, modifiersArray, lengthProperty.get(), 0), 0);
- for (int i = 0; i < modifiersCount; ++i)
- gdkModifiers |= gdkModifierFromJSValue(context, JSObjectGetPropertyAtIndex(context, modifiersArray, i, 0));
- return gdkModifiers;
-}
-
-static JSValueRef mouseDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- int button = 0;
- if (argumentCount == 1) {
- button = static_cast<int>(JSValueToNumber(context, arguments[0], exception));
- g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context));
- }
- guint modifiers = argumentCount >= 2 ? gdkModifersFromJSValue(context, arguments[1]) : 0;
-
- GdkEvent* event = gdk_event_new(GDK_BUTTON_PRESS);
- if (!prepareMouseButtonEvent(event, button, modifiers)) {
- gdk_event_free(event);
- return JSValueMakeUndefined(context);
- }
-
- // If the same mouse button is already in the down position don't send another event as it may confuse Xvfb.
- if (buttonCurrentlyDown == event->button.button) {
- gdk_event_free(event);
- return JSValueMakeUndefined(context);
- }
-
- buttonCurrentlyDown = event->button.button;
-
- // Normally GDK will send both GDK_BUTTON_PRESS and GDK_2BUTTON_PRESS for
- // the second button press during double-clicks. WebKit GTK+ selectively
- // ignores the first GDK_BUTTON_PRESS of that pair using gdk_event_peek.
- // Since our events aren't ever going onto the GDK event queue, WebKit won't
- // be able to filter out the first GDK_BUTTON_PRESS, so we just don't send
- // it here. Eventually this code should probably figure out a way to get all
- // appropriate events onto the event queue and this work-around should be
- // removed.
- updateClickCount(event->button.button);
- if (clickCount == 2)
- event->type = GDK_2BUTTON_PRESS;
- else if (clickCount == 3)
- event->type = GDK_3BUTTON_PRESS;
-
- sendOrQueueEvent(event);
- return JSValueMakeUndefined(context);
-}
-
-static guint getStateFlags()
-{
- if (buttonCurrentlyDown == 1)
- return GDK_BUTTON1_MASK;
- if (buttonCurrentlyDown == 2)
- return GDK_BUTTON2_MASK;
- if (buttonCurrentlyDown == 3)
- return GDK_BUTTON3_MASK;
- return 0;
-}
-
-static JSValueRef mouseUpCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- int button = 0;
- if (argumentCount == 1) {
- button = static_cast<int>(JSValueToNumber(context, arguments[0], exception));
- g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context));
- }
- guint modifiers = argumentCount >= 2 ? gdkModifersFromJSValue(context, arguments[1]) : 0;
-
- GdkEvent* event = gdk_event_new(GDK_BUTTON_RELEASE);
- if (!prepareMouseButtonEvent(event, button, modifiers)) {
- gdk_event_free(event);
- return JSValueMakeUndefined(context);
- }
-
- lastClickPositionX = lastMousePositionX;
- lastClickPositionY = lastMousePositionY;
- lastClickButton = buttonCurrentlyDown;
- lastClickTimeOffset = timeOffset;
- buttonCurrentlyDown = 0;
-
- sendOrQueueEvent(event);
- return JSValueMakeUndefined(context);
-}
-
-static JSValueRef mouseMoveToCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- if (!view)
- return JSValueMakeUndefined(context);
-
- if (argumentCount < 2)
- return JSValueMakeUndefined(context);
-
- lastMousePositionX = (int)JSValueToNumber(context, arguments[0], exception);
- g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context));
- lastMousePositionY = (int)JSValueToNumber(context, arguments[1], exception);
- g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context));
-
- GdkEvent* event = gdk_event_new(GDK_MOTION_NOTIFY);
- event->motion.x = lastMousePositionX;
- event->motion.y = lastMousePositionY;
-
- event->motion.time = GDK_CURRENT_TIME;
- event->motion.window = gtk_widget_get_window(GTK_WIDGET(view));
- g_object_ref(event->motion.window);
- event->button.device = getDefaultGDKPointerDevice(event->motion.window);
-
- guint modifiers = argumentCount >= 3 ? gdkModifersFromJSValue(context, arguments[2]) : 0;
- event->motion.state = modifiers | getStateFlags();
- event->motion.axes = 0;
-
- int xRoot, yRoot;
- gdk_window_get_root_coords(gtk_widget_get_window(GTK_WIDGET(view)), lastMousePositionX, lastMousePositionY, &xRoot, &yRoot);
- event->motion.x_root = xRoot;
- event->motion.y_root = yRoot;
-
- sendOrQueueEvent(event, false);
- return JSValueMakeUndefined(context);
-}
-
-static JSValueRef mouseScrollByCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- if (!view)
- return JSValueMakeUndefined(context);
-
- if (argumentCount < 2)
- return JSValueMakeUndefined(context);
-
- int horizontal = (int)JSValueToNumber(context, arguments[0], exception);
- g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context));
- int vertical = (int)JSValueToNumber(context, arguments[1], exception);
- g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context));
-
- // Copy behaviour of Qt and EFL - just return in case of (0,0) mouse scroll
- if (!horizontal && !vertical)
- return JSValueMakeUndefined(context);
-
- GdkEvent* event = gdk_event_new(GDK_SCROLL);
- event->scroll.x = lastMousePositionX;
- event->scroll.y = lastMousePositionY;
- event->scroll.time = GDK_CURRENT_TIME;
- event->scroll.window = gtk_widget_get_window(GTK_WIDGET(view));
- g_object_ref(event->scroll.window);
-
- // GTK+ only supports one tick in each scroll event that is not smooth. For the cases of more than one direction,
- // and more than one step in a direction, we can only use smooth events, supported from Gtk 3.3.18.
-#if GTK_CHECK_VERSION(3, 3, 18)
- if ((horizontal && vertical) || horizontal > 1 || horizontal < -1 || vertical > 1 || vertical < -1) {
- event->scroll.direction = GDK_SCROLL_SMOOTH;
- event->scroll.delta_x = -horizontal;
- event->scroll.delta_y = -vertical;
-
- sendOrQueueEvent(event);
- return JSValueMakeUndefined(context);
- }
-#else
- g_return_val_if_fail((!vertical || !horizontal), JSValueMakeUndefined(context));
-#endif
-
- if (horizontal < 0)
- event->scroll.direction = GDK_SCROLL_RIGHT;
- else if (horizontal > 0)
- event->scroll.direction = GDK_SCROLL_LEFT;
- else if (vertical < 0)
- event->scroll.direction = GDK_SCROLL_DOWN;
- else if (vertical > 0)
- event->scroll.direction = GDK_SCROLL_UP;
- else
- g_assert_not_reached();
-
- sendOrQueueEvent(event);
- return JSValueMakeUndefined(context);
-}
-
-static JSValueRef continuousMouseScrollByCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
-#if GTK_CHECK_VERSION(3, 3, 18)
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- if (!view)
- return JSValueMakeUndefined(context);
-
- if (argumentCount < 2)
- return JSValueMakeUndefined(context);
-
- int horizontal = JSValueToNumber(context, arguments[0], exception);
- g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context));
- int vertical = JSValueToNumber(context, arguments[1], exception);
- g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context));
-
- // We do not yet support continuous scrolling by page.
- if (argumentCount >= 3 && JSValueToBoolean(context, arguments[2]))
- return JSValueMakeUndefined(context);
-
- GdkEvent* event = gdk_event_new(GDK_SCROLL);
- event->scroll.x = lastMousePositionX;
- event->scroll.y = lastMousePositionY;
- event->scroll.time = GDK_CURRENT_TIME;
- event->scroll.window = gtk_widget_get_window(GTK_WIDGET(view));
- g_object_ref(event->scroll.window);
-
- event->scroll.direction = GDK_SCROLL_SMOOTH;
- event->scroll.delta_x = -horizontal / pixelsPerScrollTick;
- event->scroll.delta_y = -vertical / pixelsPerScrollTick;
-
- sendOrQueueEvent(event);
-#endif
- return JSValueMakeUndefined(context);
-}
-
-static void dragWithFilesDragDataGetCallback(GtkWidget*, GdkDragContext*, GtkSelectionData *data, guint, guint, gpointer userData)
-{
- gtk_selection_data_set_uris(data, static_cast<gchar**>(userData));
-}
-
-static void dragWithFilesDragEndCallback(GtkWidget* widget, GdkDragContext*, gpointer userData)
-{
- g_signal_handlers_disconnect_by_func(widget, reinterpret_cast<void*>(dragWithFilesDragEndCallback), userData);
- g_signal_handlers_disconnect_by_func(widget, reinterpret_cast<void*>(dragWithFilesDragDataGetCallback), userData);
- g_strfreev(static_cast<gchar**>(userData));
-}
-
-static JSValueRef beginDragWithFilesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- if (argumentCount < 1)
- return JSValueMakeUndefined(context);
-
- JSObjectRef filesArray = JSValueToObject(context, arguments[0], exception);
- ASSERT(!exception || !*exception);
-
- const gchar* mainFrameURI = webkit_web_frame_get_uri(mainFrame);
- GRefPtr<GFile> testFile(adoptGRef(g_file_new_for_uri(mainFrameURI)));
- GRefPtr<GFile> parentDirectory(g_file_get_parent(testFile.get()));
- if (!parentDirectory)
- return JSValueMakeUndefined(context);
-
- // If this is an HTTP test, we still need to pass a local file path
- // to WebCore. Even though the file doesn't exist, this should be fine
- // for most tests.
- GUniquePtr<gchar> scheme(g_file_get_uri_scheme(parentDirectory.get()));
- if (g_str_equal(scheme.get(), "http") || g_str_equal(scheme.get(), "https")) {
- GUniquePtr<gchar> currentDirectory(g_get_current_dir());
- parentDirectory = adoptGRef(g_file_new_for_path(currentDirectory.get()));
- }
-
- JSStringRef lengthProperty = JSStringCreateWithUTF8CString("length");
- int filesArrayLength = JSValueToNumber(context, JSObjectGetProperty(context, filesArray, lengthProperty, 0), 0);
- JSStringRelease(lengthProperty);
-
- gchar** draggedFilesURIList = g_new0(gchar*, filesArrayLength + 1);
- for (int i = 0; i < filesArrayLength; ++i) {
- JSStringRef filenameString = JSValueToStringCopy(context,
- JSObjectGetPropertyAtIndex(context, filesArray, i, 0), 0);
- size_t bufferSize = JSStringGetMaximumUTF8CStringSize(filenameString);
- GUniquePtr<gchar> filenameBuffer(static_cast<gchar*>(g_malloc(bufferSize)));
- JSStringGetUTF8CString(filenameString, filenameBuffer.get(), bufferSize);
- JSStringRelease(filenameString);
-
- GRefPtr<GFile> dragFile(g_file_get_child(parentDirectory.get(), filenameBuffer.get()));
- draggedFilesURIList[i] = g_file_get_uri(dragFile.get());
- }
-
- GtkWidget* view = GTK_WIDGET(webkit_web_frame_get_web_view(mainFrame));
- g_object_connect(G_OBJECT(view),
- "signal::drag-end", dragWithFilesDragEndCallback, draggedFilesURIList,
- "signal::drag-data-get", dragWithFilesDragDataGetCallback, draggedFilesURIList,
- NULL);
-
- GdkEvent event;
- GdkWindow* viewGDKWindow = gtk_widget_get_window(view);
- memset(&event, 0, sizeof(event));
- event.type = GDK_MOTION_NOTIFY;
- event.motion.x = lastMousePositionX;
- event.motion.y = lastMousePositionY;
- event.motion.time = GDK_CURRENT_TIME;
- event.motion.window = viewGDKWindow;
- event.motion.device = getDefaultGDKPointerDevice(viewGDKWindow);
- event.motion.state = GDK_BUTTON1_MASK;
-
- int xRoot, yRoot;
- gdk_window_get_root_coords(viewGDKWindow, lastMousePositionX, lastMousePositionY, &xRoot, &yRoot);
- event.motion.x_root = xRoot;
- event.motion.y_root = yRoot;
-
- GtkTargetList* targetList = gtk_target_list_new(0, 0);
- gtk_target_list_add_uri_targets(targetList, 0);
- gtk_drag_begin(view, targetList, GDK_ACTION_COPY, 1, &event);
- gtk_target_list_unref(targetList);
-
- return JSValueMakeUndefined(context);
-}
-
-static void sendOrQueueEvent(GdkEvent* event, bool shouldReplaySavedEvents)
-{
- // Mouse move events are queued if the previous event was queued or if a
- // delay was set up by leapForward().
- if ((dragMode && buttonCurrentlyDown) || endOfQueue != startOfQueue || msgQueue[endOfQueue].delay) {
- msgQueue[endOfQueue++].event = event;
-
- if (shouldReplaySavedEvents)
- replaySavedEvents();
-
- return;
- }
-
- dispatchEvent(event);
-}
-
-static void dispatchEvent(GdkEvent* event)
-{
- DumpRenderTreeSupportGtk::layoutFrame(mainFrame);
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- if (!view) {
- gdk_event_free(event);
- return;
- }
-
- // The widget focus may have been lost in the course of the test,
- // so force another explicit focus grab here.
- gtk_widget_grab_focus(GTK_WIDGET(view));
- gtk_main_do_event(event);
-
- if (!currentDragSourceContext) {
- gdk_event_free(event);
- return;
- }
-
- if (event->type == GDK_MOTION_NOTIFY) {
- // WebKit has called gtk_drag_start(), but because the main loop isn't
- // running GDK internals don't know that the drag has started yet. Pump
- // the main loop a little bit so that GDK is in the correct state.
- while (gtk_events_pending())
- gtk_main_iteration();
-
- // Simulate a drag motion on the top-level GDK window.
- GtkWidget* parentWidget = gtk_widget_get_parent(GTK_WIDGET(view));
- GdkWindow* parentWidgetWindow = gtk_widget_get_window(parentWidget);
- gdk_drag_motion(currentDragSourceContext, parentWidgetWindow, GDK_DRAG_PROTO_XDND,
- event->motion.x_root, event->motion.y_root,
- gdk_drag_context_get_selected_action(currentDragSourceContext),
- gdk_drag_context_get_actions(currentDragSourceContext),
- GDK_CURRENT_TIME);
-
- } else if (currentDragSourceContext && event->type == GDK_BUTTON_RELEASE) {
- // We've released the mouse button, we should just be able to spin the
- // event loop here and have GTK+ send the appropriate notifications for
- // the end of the drag.
- while (gtk_events_pending())
- gtk_main_iteration();
- }
-
- gdk_event_free(event);
-}
-
-void replaySavedEvents()
-{
- // First send all the events that are ready to be sent
- while (startOfQueue < endOfQueue) {
- if (msgQueue[startOfQueue].delay) {
- g_usleep(msgQueue[startOfQueue].delay * 1000);
- msgQueue[startOfQueue].delay = 0;
- }
-
- dispatchEvent(msgQueue[startOfQueue++].event);
- }
-
- startOfQueue = 0;
- endOfQueue = 0;
-}
-
-static GdkEvent* createKeyPressEvent(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- g_return_val_if_fail(argumentCount >= 1, 0);
- guint modifiers = argumentCount >= 2 ? gdkModifersFromJSValue(context, arguments[1]) : 0;
-
- // handle location argument.
- int location = DOM_KEY_LOCATION_STANDARD;
- if (argumentCount > 2)
- location = (int)JSValueToNumber(context, arguments[2], exception);
-
- JSStringRef character = JSValueToStringCopy(context, arguments[0], exception);
- g_return_val_if_fail((!exception || !*exception), 0);
-
- int gdkKeySym = GDK_VoidSymbol;
- if (location == DOM_KEY_LOCATION_NUMPAD) {
- if (JSStringIsEqualToUTF8CString(character, "leftArrow"))
- gdkKeySym = GDK_KP_Left;
- else if (JSStringIsEqualToUTF8CString(character, "rightArrow"))
- gdkKeySym = GDK_KP_Right;
- else if (JSStringIsEqualToUTF8CString(character, "upArrow"))
- gdkKeySym = GDK_KP_Up;
- else if (JSStringIsEqualToUTF8CString(character, "downArrow"))
- gdkKeySym = GDK_KP_Down;
- else if (JSStringIsEqualToUTF8CString(character, "pageUp"))
- gdkKeySym = GDK_KP_Page_Up;
- else if (JSStringIsEqualToUTF8CString(character, "pageDown"))
- gdkKeySym = GDK_KP_Page_Down;
- else if (JSStringIsEqualToUTF8CString(character, "home"))
- gdkKeySym = GDK_KP_Home;
- else if (JSStringIsEqualToUTF8CString(character, "end"))
- gdkKeySym = GDK_KP_End;
- else if (JSStringIsEqualToUTF8CString(character, "insert"))
- gdkKeySym = GDK_KP_Insert;
- else if (JSStringIsEqualToUTF8CString(character, "delete"))
- gdkKeySym = GDK_KP_Delete;
- else
- // If we get some other key specified with the numpad location,
- // crash here, so we add it sooner rather than later.
- g_assert_not_reached();
- } else {
- if (JSStringIsEqualToUTF8CString(character, "leftArrow"))
- gdkKeySym = GDK_Left;
- else if (JSStringIsEqualToUTF8CString(character, "rightArrow"))
- gdkKeySym = GDK_Right;
- else if (JSStringIsEqualToUTF8CString(character, "upArrow"))
- gdkKeySym = GDK_Up;
- else if (JSStringIsEqualToUTF8CString(character, "downArrow"))
- gdkKeySym = GDK_Down;
- else if (JSStringIsEqualToUTF8CString(character, "pageUp"))
- gdkKeySym = GDK_Page_Up;
- else if (JSStringIsEqualToUTF8CString(character, "pageDown"))
- gdkKeySym = GDK_Page_Down;
- else if (JSStringIsEqualToUTF8CString(character, "home"))
- gdkKeySym = GDK_Home;
- else if (JSStringIsEqualToUTF8CString(character, "end"))
- gdkKeySym = GDK_End;
- else if (JSStringIsEqualToUTF8CString(character, "insert"))
- gdkKeySym = GDK_Insert;
- else if (JSStringIsEqualToUTF8CString(character, "delete"))
- gdkKeySym = GDK_Delete;
- else if (JSStringIsEqualToUTF8CString(character, "printScreen"))
- gdkKeySym = GDK_Print;
- else if (JSStringIsEqualToUTF8CString(character, "menu"))
- gdkKeySym = GDK_Menu;
- else if (JSStringIsEqualToUTF8CString(character, "F1"))
- gdkKeySym = GDK_F1;
- else if (JSStringIsEqualToUTF8CString(character, "F2"))
- gdkKeySym = GDK_F2;
- else if (JSStringIsEqualToUTF8CString(character, "F3"))
- gdkKeySym = GDK_F3;
- else if (JSStringIsEqualToUTF8CString(character, "F4"))
- gdkKeySym = GDK_F4;
- else if (JSStringIsEqualToUTF8CString(character, "F5"))
- gdkKeySym = GDK_F5;
- else if (JSStringIsEqualToUTF8CString(character, "F6"))
- gdkKeySym = GDK_F6;
- else if (JSStringIsEqualToUTF8CString(character, "F7"))
- gdkKeySym = GDK_F7;
- else if (JSStringIsEqualToUTF8CString(character, "F8"))
- gdkKeySym = GDK_F8;
- else if (JSStringIsEqualToUTF8CString(character, "F9"))
- gdkKeySym = GDK_F9;
- else if (JSStringIsEqualToUTF8CString(character, "F10"))
- gdkKeySym = GDK_F10;
- else if (JSStringIsEqualToUTF8CString(character, "F11"))
- gdkKeySym = GDK_F11;
- else if (JSStringIsEqualToUTF8CString(character, "F12"))
- gdkKeySym = GDK_F12;
- else if (JSStringIsEqualToUTF8CString(character, "leftAlt"))
- gdkKeySym = GDK_Alt_L;
- else if (JSStringIsEqualToUTF8CString(character, "leftControl"))
- gdkKeySym = GDK_Control_L;
- else if (JSStringIsEqualToUTF8CString(character, "leftShift"))
- gdkKeySym = GDK_Shift_L;
- else if (JSStringIsEqualToUTF8CString(character, "rightAlt"))
- gdkKeySym = GDK_Alt_R;
- else if (JSStringIsEqualToUTF8CString(character, "rightControl"))
- gdkKeySym = GDK_Control_R;
- else if (JSStringIsEqualToUTF8CString(character, "rightShift"))
- gdkKeySym = GDK_Shift_R;
- else {
- int charCode = JSStringGetCharactersPtr(character)[0];
- if (charCode == '\n' || charCode == '\r')
- gdkKeySym = GDK_Return;
- else if (charCode == '\t')
- gdkKeySym = GDK_Tab;
- else if (charCode == '\x8')
- gdkKeySym = GDK_BackSpace;
- else {
- gdkKeySym = gdk_unicode_to_keyval(charCode);
- if (WTF::isASCIIUpper(charCode))
- modifiers |= GDK_SHIFT_MASK;
- }
- }
- }
- JSStringRelease(character);
-
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- g_return_val_if_fail(view, 0);
-
- GdkEvent* pressEvent = gdk_event_new(GDK_KEY_PRESS);
- pressEvent->key.keyval = gdkKeySym;
- pressEvent->key.state = modifiers;
- pressEvent->key.window = gtk_widget_get_window(GTK_WIDGET(view));
- g_object_ref(pressEvent->key.window);
-#ifndef GTK_API_VERSION_2
- gdk_event_set_device(pressEvent, getDefaultGDKPointerDevice(pressEvent->key.window));
-#endif
-
- // When synthesizing an event, an invalid hardware_keycode value
- // can cause it to be badly processed by Gtk+.
- GUniqueOutPtr<GdkKeymapKey> keys;
- gint nKeys;
- if (gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), gdkKeySym, &keys.outPtr(), &nKeys))
- pressEvent->key.hardware_keycode = keys.get()[0].keycode;
-
- return pressEvent;
-}
-
-static void sendKeyDown(GdkEvent* pressEvent)
-{
- g_return_if_fail(pressEvent);
- GdkEvent* releaseEvent = gdk_event_copy(pressEvent);
- releaseEvent->type = GDK_KEY_RELEASE;
-
- dispatchEvent(pressEvent);
- dispatchEvent(releaseEvent);
-
- DumpRenderTreeSupportGtk::deliverAllMutationsIfNecessary();
-}
-
-static JSValueRef keyDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- GdkEvent* pressEvent = createKeyPressEvent(context, argumentCount, arguments, exception);
- sendKeyDown(pressEvent);
-
- return JSValueMakeUndefined(context);
-}
-
-static void zoomIn(gboolean fullContentsZoom)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- if (!view)
- return;
-
- webkit_web_view_set_full_content_zoom(view, fullContentsZoom);
- gfloat currentZoom = webkit_web_view_get_zoom_level(view);
- webkit_web_view_set_zoom_level(view, currentZoom * zoomMultiplierRatio);
-}
-
-static void zoomOut(gboolean fullContentsZoom)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- if (!view)
- return;
-
- webkit_web_view_set_full_content_zoom(view, fullContentsZoom);
- gfloat currentZoom = webkit_web_view_get_zoom_level(view);
- webkit_web_view_set_zoom_level(view, currentZoom / zoomMultiplierRatio);
-}
-
-static JSValueRef textZoomInCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- zoomIn(FALSE);
- return JSValueMakeUndefined(context);
-}
-
-static JSValueRef textZoomOutCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- zoomOut(FALSE);
- return JSValueMakeUndefined(context);
-}
-
-static JSValueRef zoomPageInCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- zoomIn(TRUE);
- return JSValueMakeUndefined(context);
-}
-
-static JSValueRef zoomPageOutCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- zoomOut(TRUE);
- return JSValueMakeUndefined(context);
-}
-
-static JSValueRef scalePageByCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- if (argumentCount < 3)
- return JSValueMakeUndefined(context);
-
- float scaleFactor = JSValueToNumber(context, arguments[0], exception);
- float x = JSValueToNumber(context, arguments[1], exception);
- float y = JSValueToNumber(context, arguments[2], exception);
-
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- if (!view)
- return JSValueMakeUndefined(context);
-
- DumpRenderTreeSupportGtk::scalePageBy(view, scaleFactor, x, y);
-
- return JSValueMakeUndefined(context);
-}
-
-static gboolean sendAsynchronousKeyDown(gpointer userData)
-{
- sendKeyDown(static_cast<GdkEvent*>(userData));
- return FALSE;
-}
-
-static JSValueRef scheduleAsynchronousKeyDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- GdkEvent* pressEvent = createKeyPressEvent(context, argumentCount, arguments, exception);
- if (pressEvent)
- g_idle_add_full(G_PRIORITY_DEFAULT, sendAsynchronousKeyDown, static_cast<gpointer>(pressEvent), 0);
-
- return JSValueMakeUndefined(context);
-}
-
-static JSValueRef clearTouchPointsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- return JSValueMakeUndefined(context);
-}
-
-static JSStaticFunction staticFunctions[] = {
- { "mouseScrollBy", mouseScrollByCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "continuousMouseScrollBy", continuousMouseScrollByCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "contextClick", contextClickCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "mouseDown", mouseDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "mouseUp", mouseUpCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "mouseMoveTo", mouseMoveToCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "beginDragWithFiles", beginDragWithFilesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "leapForward", leapForwardCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "keyDown", keyDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "textZoomIn", textZoomInCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "textZoomOut", textZoomOutCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "zoomPageIn", zoomPageInCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "zoomPageOut", zoomPageOutCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "scheduleAsynchronousClick", scheduleAsynchronousClickCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "scalePageBy", scalePageByCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "scheduleAsynchronousKeyDown", scheduleAsynchronousKeyDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
-
- { 0, 0, 0 }
-};
-
-static JSStaticValue staticValues[] = {
- { "dragMode", getDragModeCallback, setDragModeCallback, kJSPropertyAttributeNone },
- { 0, 0, 0, 0 }
-};
-
-static JSClassRef getClass(JSContextRef context)
-{
- static JSClassRef eventSenderClass = 0;
-
- if (!eventSenderClass) {
- JSClassDefinition classDefinition = {
- 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- classDefinition.staticFunctions = staticFunctions;
- classDefinition.staticValues = staticValues;
-
- eventSenderClass = JSClassCreate(&classDefinition);
- }
-
- return eventSenderClass;
-}
-
-JSObjectRef makeEventSender(JSContextRef context, bool isTopFrame)
-{
- if (isTopFrame) {
- dragMode = true;
-
- // Fly forward in time one second when the main frame loads. This will
- // ensure that when a test begins clicking in the same location as
- // a previous test, those clicks won't be interpreted as continuations
- // of the previous test's click sequences.
- timeOffset += 1000;
-
- lastMousePositionX = lastMousePositionY = 0;
- lastClickPositionX = lastClickPositionY = 0;
- lastClickTimeOffset = 0;
- lastClickButton = 0;
- buttonCurrentlyDown = 0;
- clickCount = 0;
-
- endOfQueue = 0;
- startOfQueue = 0;
-
- currentDragSourceContext = 0;
- }
-
- return JSObjectMake(context, getClass(context), 0);
-}
-
-void dragBeginCallback(GtkWidget*, GdkDragContext* context, gpointer)
-{
- currentDragSourceContext = context;
-}
-
-void dragEndCallback(GtkWidget*, GdkDragContext* context, gpointer)
-{
- currentDragSourceContext = 0;
-}
-
-gboolean dragFailedCallback(GtkWidget*, GdkDragContext* context, gpointer)
-{
- // Return TRUE here to disable the stupid GTK+ drag failed animation,
- // which introduces asynchronous behavior into our drags.
- return TRUE;
-}
diff --git a/Tools/DumpRenderTree/gtk/EventSender.h b/Tools/DumpRenderTree/gtk/EventSender.h
deleted file mode 100644
index f440f0d3d..000000000
--- a/Tools/DumpRenderTree/gtk/EventSender.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
- * Copyright (C) 2009 Holger Hans Peter Freyther
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef EventSender_h
-#define EventSender_h
-
-typedef const struct OpaqueJSContext* JSContextRef;
-typedef struct OpaqueJSValue* JSObjectRef;
-
-JSObjectRef makeEventSender(JSContextRef context, bool isTopFrame);
-void replaySavedEvents();
-void dragBeginCallback(GtkWidget*, GdkDragContext*, gpointer);
-void dragEndCallback(GtkWidget*, GdkDragContext*, gpointer);
-gboolean dragFailedCallback(GtkWidget*, GdkDragContext*, gpointer);
-
-#endif
diff --git a/Tools/DumpRenderTree/gtk/GCControllerGtk.cpp b/Tools/DumpRenderTree/gtk/GCControllerGtk.cpp
deleted file mode 100644
index 4eb5d6ec9..000000000
--- a/Tools/DumpRenderTree/gtk/GCControllerGtk.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "GCController.h"
-
-#include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
-
-#include <glib.h>
-#include <webkit/webkit.h>
-
-void GCController::collect() const
-{
- DumpRenderTreeSupportGtk::gcCollectJavascriptObjects();
-}
-
-void GCController::collectOnAlternateThread(bool waitUntilDone) const
-{
- DumpRenderTreeSupportGtk::gcCollectJavascriptObjectsOnAlternateThread(waitUntilDone);
-}
-
-size_t GCController::getJSObjectCount() const
-{
- return DumpRenderTreeSupportGtk::gcCountJavascriptObjects();
-}
diff --git a/Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp b/Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp
deleted file mode 100644
index 0a800ec13..000000000
--- a/Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2009 Zan Dobersek <zandobersek@gmail.com>
- * Copyright (C) 2010 Igalia S.L.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#include "DumpRenderTree.h"
-#include "GtkVersioning.h"
-#include "PixelDumpSupportCairo.h"
-#include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
-#include <webkit/webkit.h>
-
-static void paintOverlay(cairo_surface_t* surface)
-{
- cairo_t* context = cairo_create(surface);
-
- // Paint a transparent black overlay from which the repainted rectangles are then cleared.
- // The alpha component of the overlay should have a value of 0.66, as on other ports.
- cairo_set_source_rgba(context, 0.0, 0.0, 0.0, 0.66);
- cairo_rectangle(context, 0, 0, cairo_image_surface_get_width(surface), cairo_image_surface_get_height(surface));
- cairo_fill(context);
-
- GSList* trackedRectsList = DumpRenderTreeSupportGtk::trackedRepaintRects(mainFrame);
- for (GSList* listElement = trackedRectsList; listElement; listElement = g_slist_next(listElement)) {
- GdkRectangle* rect = static_cast<GdkRectangle*>(listElement->data);
-
- cairo_set_operator(context, CAIRO_OPERATOR_CLEAR);
- cairo_rectangle(context, rect->x, rect->y, rect->width, rect->height);
- cairo_fill(context);
- }
-
- g_slist_free_full(trackedRectsList, g_free);
- cairo_destroy(context);
-}
-
-static void fillRepaintOverlayIntoContext(cairo_t* context, gint width, gint height)
-{
- cairo_surface_t* overlaySurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
- paintOverlay(overlaySurface);
-
- cairo_set_source_surface(context, overlaySurface, 0, 0);
- cairo_rectangle(context, 0, 0, width, height);
- cairo_fill(context);
-
- cairo_surface_destroy(overlaySurface);
-}
-
-PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool, bool, bool, bool drawSelectionRect)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- GtkWidget* viewContainer = gtk_widget_get_parent(GTK_WIDGET(view));
- gint width, height;
-#ifdef GTK_API_VERSION_2
- GdkPixmap* pixmap = gtk_widget_get_snapshot(viewContainer, 0);
- gdk_pixmap_get_size(pixmap, &width, &height);
-#else
- width = gtk_widget_get_allocated_width(viewContainer);
- height = gtk_widget_get_allocated_height(viewContainer);
-#endif
-
- while (gtk_events_pending())
- gtk_main_iteration();
-
- cairo_surface_t* imageSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
- cairo_t* context = cairo_create(imageSurface);
-
-#ifdef GTK_API_VERSION_2
- gdk_cairo_set_source_pixmap(context, pixmap, 0, 0);
- cairo_paint(context);
- g_object_unref(pixmap);
-#else
- gtk_widget_draw(viewContainer, context);
-#endif
-
- if (DumpRenderTreeSupportGtk::isTrackingRepaints(mainFrame))
- fillRepaintOverlayIntoContext(context, width, height);
-
- if (drawSelectionRect) {
- cairo_rectangle_int_t rectangle;
- DumpRenderTreeSupportGtk::rectangleForSelection(mainFrame, &rectangle);
-
- cairo_set_line_width(context, 1.0);
- cairo_rectangle(context, rectangle.x, rectangle.y, rectangle.width, rectangle.height);
- cairo_set_source_rgba(context, 1.0, 0.0, 0.0, 1.0);
- cairo_stroke(context);
- }
-
- cairo_surface_destroy(imageSurface);
- return BitmapContext::createByAdoptingBitmapAndContext(0, context);
-}
diff --git a/Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.cpp b/Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.cpp
deleted file mode 100644
index d77cfd5f1..000000000
--- a/Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2011 Igalia S.L.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "SelfScrollingWebKitWebView.h"
-
-#include <webkit/webkit.h>
-
-G_BEGIN_DECLS
-
-#ifdef GTK_API_VERSION_2
-static void sizeRequestMethod(GtkWidget*, GtkRequisition*);
-#else
-static void getPreferredSizeMethod(GtkWidget*, gint* minimum, gint* natural);
-#endif
-
-G_DEFINE_TYPE(SelfScrollingWebKitWebView, self_scrolling_webkit_web_view, WEBKIT_TYPE_WEB_VIEW)
-
-static void self_scrolling_webkit_web_view_class_init(SelfScrollingWebKitWebViewClass* klass)
-{
- GtkWidgetClass* widgetClass = GTK_WIDGET_CLASS(klass);
-#ifdef GTK_API_VERSION_2
- widgetClass->size_request = sizeRequestMethod;
-#else
- widgetClass->get_preferred_width = getPreferredSizeMethod;
- widgetClass->get_preferred_height = getPreferredSizeMethod;
-#endif
-}
-
-static void self_scrolling_webkit_web_view_init(SelfScrollingWebKitWebView* webView)
-{
-}
-
-GtkWidget* self_scrolling_webkit_web_view_new()
-{
- return GTK_WIDGET(g_object_new(self_scrolling_webkit_web_view_get_type(), "self-scrolling", TRUE, NULL));
-}
-
-#ifdef GTK_API_VERSION_2
-static void sizeRequestMethod(GtkWidget*, GtkRequisition* requisition)
-{
- requisition->width = 1;
- requisition->height = 1;
-}
-#else
-static void getPreferredSizeMethod(GtkWidget*, gint* minimum, gint* natural)
-{
- *minimum = 1;
- *natural = 1;
-}
-#endif
-
-G_END_DECLS
diff --git a/Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.h b/Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.h
deleted file mode 100644
index 648d38c97..000000000
--- a/Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2011 Igalia S.L.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef SelfScrollingWebKitWebView_h
-#define SelfScrollingWebKitWebView_h
-
-#include <webkit/webkit.h>
-
-G_BEGIN_DECLS
-
-typedef struct _SelfScrollingWebKitWebView SelfScrollingWebKitWebView;
-typedef struct _SelfScrollingWebKitWebViewClass SelfScrollingWebKitWebViewClass;
-
-struct _SelfScrollingWebKitWebView {
- WebKitWebView web_view;
-};
-
-struct _SelfScrollingWebKitWebViewClass {
- WebKitWebViewClass parent_class;
-};
-
-GtkWidget* self_scrolling_webkit_web_view_new();
-
-G_END_DECLS
-
-#endif // SelfScrollingWebKitWebView_h
diff --git a/Tools/DumpRenderTree/gtk/TestRunnerGtk.cpp b/Tools/DumpRenderTree/gtk/TestRunnerGtk.cpp
deleted file mode 100644
index c0b2deca2..000000000
--- a/Tools/DumpRenderTree/gtk/TestRunnerGtk.cpp
+++ /dev/null
@@ -1,914 +0,0 @@
-/*
- * Copyright (C) 2007, 2012 Apple Inc. All rights reserved.
- * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
- * Copyright (C) 2008 Nuanti Ltd.
- * Copyright (C) 2009 Jan Michael Alonzo <jmalonzo@gmail.com>
- * Copyright (C) 2009,2011 Collabora Ltd.
- * Copyright (C) 2010 Joone Hur <joone@kldp.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "TestRunner.h"
-
-#include "DumpRenderTree.h"
-#include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
-#include "WorkQueue.h"
-#include "WorkQueueItem.h"
-#include <JavaScriptCore/JSRetainPtr.h>
-#include <JavaScriptCore/JSStringRef.h>
-#include <cstring>
-#include <iostream>
-#include <sstream>
-#include <stdio.h>
-#include <glib.h>
-#include <libsoup/soup.h>
-#include <webkit/webkit.h>
-#include <wtf/gobject/GUniquePtr.h>
-#include <wtf/text/WTFString.h>
-
-extern "C" {
-void webkit_web_inspector_execute_script(WebKitWebInspector* inspector, long callId, const gchar* script);
-}
-
-TestRunner::~TestRunner()
-{
- // FIXME: implement
-}
-
-void TestRunner::addDisallowedURL(JSStringRef url)
-{
- // FIXME: implement
-}
-
-void TestRunner::clearBackForwardList()
-{
- WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
- WebKitWebBackForwardList* list = webkit_web_view_get_back_forward_list(webView);
- WebKitWebHistoryItem* item = webkit_web_back_forward_list_get_current_item(list);
- g_object_ref(item);
-
- // We clear the history by setting the back/forward list's capacity to 0
- // then restoring it back and adding back the current item.
- gint limit = webkit_web_back_forward_list_get_limit(list);
- webkit_web_back_forward_list_set_limit(list, 0);
- webkit_web_back_forward_list_set_limit(list, limit);
- webkit_web_back_forward_list_add_item(list, item);
- webkit_web_back_forward_list_go_to_item(list, item);
- g_object_unref(item);
-}
-
-JSStringRef TestRunner::copyDecodedHostName(JSStringRef name)
-{
- // FIXME: implement
- return 0;
-}
-
-JSStringRef TestRunner::copyEncodedHostName(JSStringRef name)
-{
- // FIXME: implement
- return 0;
-}
-
-void TestRunner::dispatchPendingLoadRequests()
-{
- // FIXME: Implement for testing fix for 6727495
-}
-
-void TestRunner::display()
-{
- displayWebView();
-}
-
-void TestRunner::keepWebHistory()
-{
- // FIXME: implement
-}
-
-size_t TestRunner::webHistoryItemCount()
-{
- WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
- WebKitWebBackForwardList* list = webkit_web_view_get_back_forward_list(webView);
-
- if (!list)
- return -1;
-
- // We do not add the current page to the total count as it's not
- // considered in DRT tests
- return webkit_web_back_forward_list_get_back_length(list) +
- webkit_web_back_forward_list_get_forward_length(list);
-}
-
-void TestRunner::notifyDone()
-{
- if (m_waitToDump && !topLoadingFrame && !WorkQueue::shared()->count())
- dump();
- m_waitToDump = false;
- waitForPolicy = false;
-}
-
-JSStringRef TestRunner::pathToLocalResource(JSContextRef context, JSStringRef url)
-{
- GUniquePtr<char> urlCString(JSStringCopyUTF8CString(url));
- if (!g_str_has_prefix(urlCString.get(), "file:///tmp/LayoutTests/"))
- return JSStringRetain(url);
-
- const char* layoutTestsSuffix = urlCString.get() + strlen("file:///tmp/");
- GUniquePtr<char> testPath(g_build_filename(getTopLevelPath().data(), layoutTestsSuffix, nullptr));
- GUniquePtr<char> testURI(g_filename_to_uri(testPath.get(), 0, 0));
- return JSStringCreateWithUTF8CString(testURI.get());
-}
-
-void TestRunner::queueLoad(JSStringRef url, JSStringRef target)
-{
- GUniquePtr<gchar> relativeURL(JSStringCopyUTF8CString(url));
- SoupURI* baseURI = soup_uri_new(webkit_web_frame_get_uri(mainFrame));
- SoupURI* absoluteURI = soup_uri_new_with_base(baseURI, relativeURL.get());
- soup_uri_free(baseURI);
-
- if (!absoluteURI) {
- WorkQueue::shared()->queue(new LoadItem(url, target));
- return;
- }
-
- CString absoluteURIString = soupURIToStringPreservingPassword(absoluteURI);
- JSRetainPtr<JSStringRef> absoluteURL(Adopt, JSStringCreateWithUTF8CString(absoluteURIString.data()));
- WorkQueue::shared()->queue(new LoadItem(absoluteURL.get(), target));
- soup_uri_free(absoluteURI);
-}
-
-void TestRunner::setAcceptsEditing(bool acceptsEditing)
-{
- WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
- webkit_web_view_set_editable(webView, acceptsEditing);
-}
-
-void TestRunner::setAlwaysAcceptCookies(bool alwaysAcceptCookies)
-{
- SoupSession* session = webkit_get_default_session();
- SoupCookieJar* jar = reinterpret_cast<SoupCookieJar*>(soup_session_get_feature(session, SOUP_TYPE_COOKIE_JAR));
-
- /* If the jar was not created - we create it on demand, i.e, just
- in case we have HTTP requests - then we must create it here in
- order to set the proper accept policy */
- if (!jar) {
- jar = soup_cookie_jar_new();
- soup_session_add_feature(session, SOUP_SESSION_FEATURE(jar));
- g_object_unref(jar);
- }
-
- SoupCookieJarAcceptPolicy policy;
-
- if (alwaysAcceptCookies)
- policy = SOUP_COOKIE_JAR_ACCEPT_ALWAYS;
- else
- policy = SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY;
-
- g_object_set(G_OBJECT(jar), SOUP_COOKIE_JAR_ACCEPT_POLICY, policy, NULL);
-}
-
-void TestRunner::setCustomPolicyDelegate(bool setDelegate, bool permissive)
-{
- // FIXME: implement
-}
-
-void TestRunner::waitForPolicyDelegate()
-{
- waitForPolicy = true;
- setWaitToDump(true);
-}
-
-void TestRunner::setScrollbarPolicy(JSStringRef orientation, JSStringRef policy)
-{
- // FIXME: implement
-}
-
-void TestRunner::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef protocol, JSStringRef host, bool includeSubdomains)
-{
- gchar* sourceOriginGChar = JSStringCopyUTF8CString(sourceOrigin);
- gchar* protocolGChar = JSStringCopyUTF8CString(protocol);
- gchar* hostGChar = JSStringCopyUTF8CString(host);
- DumpRenderTreeSupportGtk::whiteListAccessFromOrigin(sourceOriginGChar, protocolGChar, hostGChar, includeSubdomains);
- g_free(sourceOriginGChar);
- g_free(protocolGChar);
- g_free(hostGChar);
-}
-
-void TestRunner::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef protocol, JSStringRef host, bool includeSubdomains)
-{
- GUniquePtr<gchar> sourceOriginGChar(JSStringCopyUTF8CString(sourceOrigin));
- GUniquePtr<gchar> protocolGChar(JSStringCopyUTF8CString(protocol));
- GUniquePtr<gchar> hostGChar(JSStringCopyUTF8CString(host));
- DumpRenderTreeSupportGtk::removeWhiteListAccessFromOrigin(sourceOriginGChar.get(), protocolGChar.get(), hostGChar.get(), includeSubdomains);
-}
-
-void TestRunner::setMainFrameIsFirstResponder(bool flag)
-{
- // FIXME: implement
-}
-
-void TestRunner::setTabKeyCyclesThroughElements(bool cycles)
-{
- WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
- WebKitWebSettings* settings = webkit_web_view_get_settings(webView);
- g_object_set(G_OBJECT(settings), "tab-key-cycles-through-elements", cycles, NULL);
-}
-
-void TestRunner::setUseDashboardCompatibilityMode(bool flag)
-{
- // FIXME: implement
-}
-
-static gchar* userStyleSheet = NULL;
-static gboolean userStyleSheetEnabled = TRUE;
-
-void TestRunner::setUserStyleSheetEnabled(bool flag)
-{
- userStyleSheetEnabled = flag;
-
- WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
- WebKitWebSettings* settings = webkit_web_view_get_settings(webView);
- if (flag && userStyleSheet)
- g_object_set(G_OBJECT(settings), "user-stylesheet-uri", userStyleSheet, NULL);
- else
- g_object_set(G_OBJECT(settings), "user-stylesheet-uri", "", NULL);
-}
-
-void TestRunner::setUserStyleSheetLocation(JSStringRef path)
-{
- g_free(userStyleSheet);
- userStyleSheet = JSStringCopyUTF8CString(path);
- if (userStyleSheetEnabled)
- setUserStyleSheetEnabled(true);
-}
-
-void TestRunner::setValueForUser(JSContextRef context, JSValueRef nodeObject, JSStringRef value)
-{
- DumpRenderTreeSupportGtk::setValueForUser(context, nodeObject, value);
-}
-
-void TestRunner::setViewModeMediaFeature(JSStringRef mode)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
-
- char* viewMode = JSStringCopyUTF8CString(mode);
-
- if (!g_strcmp0(viewMode, "windowed"))
- webkit_web_view_set_view_mode(view, WEBKIT_WEB_VIEW_VIEW_MODE_WINDOWED);
- else if (!g_strcmp0(viewMode, "floating"))
- webkit_web_view_set_view_mode(view, WEBKIT_WEB_VIEW_VIEW_MODE_FLOATING);
- else if (!g_strcmp0(viewMode, "fullscreen"))
- webkit_web_view_set_view_mode(view, WEBKIT_WEB_VIEW_VIEW_MODE_FULLSCREEN);
- else if (!g_strcmp0(viewMode, "maximized"))
- webkit_web_view_set_view_mode(view, WEBKIT_WEB_VIEW_VIEW_MODE_MAXIMIZED);
- else if (!g_strcmp0(viewMode, "minimized"))
- webkit_web_view_set_view_mode(view, WEBKIT_WEB_VIEW_VIEW_MODE_MINIMIZED);
-
- g_free(viewMode);
-}
-
-void TestRunner::setWindowIsKey(bool windowIsKey)
-{
- // FIXME: implement
-}
-
-static gboolean waitToDumpWatchdogFired(void*)
-{
- setWaitToDumpWatchdog(0);
- gTestRunner->waitToDumpWatchdogTimerFired();
- return FALSE;
-}
-
-void TestRunner::setWaitToDump(bool waitUntilDone)
-{
- static const int timeoutSeconds = 30;
-
- m_waitToDump = waitUntilDone;
- if (m_waitToDump && shouldSetWaitToDumpWatchdog()) {
- guint id = g_timeout_add_seconds(timeoutSeconds, waitToDumpWatchdogFired, 0);
- g_source_set_name_by_id(id, "[WebKit] waitToDumpWatchdogFired");
- setWaitToDumpWatchdog(id);
- }
-}
-
-int TestRunner::windowCount()
-{
- // +1 -> including the main view
- return g_slist_length(webViewList) + 1;
-}
-
-void TestRunner::setPrivateBrowsingEnabled(bool flag)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
-
- WebKitWebSettings* settings = webkit_web_view_get_settings(view);
- g_object_set(G_OBJECT(settings), "enable-private-browsing", flag, NULL);
-}
-
-void TestRunner::setJavaScriptCanAccessClipboard(bool flag)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
-
- WebKitWebSettings* settings = webkit_web_view_get_settings(view);
- g_object_set(G_OBJECT(settings), "javascript-can-access-clipboard", flag, NULL);
-}
-
-void TestRunner::setXSSAuditorEnabled(bool flag)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
-
- WebKitWebSettings* settings = webkit_web_view_get_settings(view);
- g_object_set(G_OBJECT(settings), "enable-xss-auditor", flag, NULL);
-}
-
-void TestRunner::setSpatialNavigationEnabled(bool flag)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
-
- WebKitWebSettings* settings = webkit_web_view_get_settings(view);
- g_object_set(G_OBJECT(settings), "enable-spatial-navigation", flag, NULL);
-}
-
-void TestRunner::setAllowUniversalAccessFromFileURLs(bool flag)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
-
- WebKitWebSettings* settings = webkit_web_view_get_settings(view);
- g_object_set(G_OBJECT(settings), "enable-universal-access-from-file-uris", flag, NULL);
-}
-
-void TestRunner::setAllowFileAccessFromFileURLs(bool flag)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
-
- WebKitWebSettings* settings = webkit_web_view_get_settings(view);
- g_object_set(G_OBJECT(settings), "enable-file-access-from-file-uris", flag, NULL);
-}
-
-void TestRunner::setAuthorAndUserStylesEnabled(bool flag)
-{
- // FIXME: implement
-}
-
-void TestRunner::setMockDeviceOrientation(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma)
-{
- // FIXME: Implement for DeviceOrientation layout tests.
- // See https://bugs.webkit.org/show_bug.cgi?id=30335.
-}
-
-void TestRunner::setMockGeolocationPosition(double latitude, double longitude, double accuracy, bool, double, bool, double, bool, double, bool, double)
-{
- WebKitWebView* view = WEBKIT_WEB_VIEW(g_slist_nth_data(webViewList, 0));
- if (!view)
- view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
-
- DumpRenderTreeSupportGtk::setMockGeolocationPosition(view, latitude, longitude, accuracy);
-}
-
-void TestRunner::setMockGeolocationPositionUnavailableError(JSStringRef message)
-{
- WebKitWebView* view = WEBKIT_WEB_VIEW(g_slist_nth_data(webViewList, 0));
- if (!view)
- view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
-
- GUniquePtr<gchar> cMessage(JSStringCopyUTF8CString(message));
- DumpRenderTreeSupportGtk::setMockGeolocationPositionUnavailableError(view, cMessage.get());
-}
-
-void TestRunner::setGeolocationPermission(bool allow)
-{
- setGeolocationPermissionCommon(allow);
- WebKitWebView* view = WEBKIT_WEB_VIEW(g_slist_nth_data(webViewList, 0));
- if (!view)
- view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
-
- DumpRenderTreeSupportGtk::setMockGeolocationPermission(view, allow);
-}
-
-int TestRunner::numberOfPendingGeolocationPermissionRequests()
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- if (!view)
- view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
-
- return DumpRenderTreeSupportGtk::numberOfPendingGeolocationPermissionRequests(view);
-}
-
-void TestRunner::addMockSpeechInputResult(JSStringRef result, double confidence, JSStringRef language)
-{
- // FIXME: Implement for speech input layout tests.
- // See https://bugs.webkit.org/show_bug.cgi?id=39485.
-}
-
-void TestRunner::setMockSpeechInputDumpRect(bool flag)
-{
- // FIXME: Implement for speech input layout tests.
- // See https://bugs.webkit.org/show_bug.cgi?id=39485.
-}
-
-void TestRunner::startSpeechInput(JSContextRef inputElement)
-{
- // FIXME: Implement for speech input layout tests.
- // See https://bugs.webkit.org/show_bug.cgi?id=39485.
-}
-
-void TestRunner::setIconDatabaseEnabled(bool enabled)
-{
- WebKitIconDatabase* database = webkit_get_icon_database();
- if (enabled) {
- GUniquePtr<gchar> iconDatabasePath(g_build_filename(g_get_tmp_dir(), "DumpRenderTree", "icondatabase", nullptr));
- webkit_icon_database_set_path(database, iconDatabasePath.get());
- } else
- webkit_icon_database_set_path(database, 0);
-}
-
-void TestRunner::setPopupBlockingEnabled(bool flag)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
-
- WebKitWebSettings* settings = webkit_web_view_get_settings(view);
- g_object_set(G_OBJECT(settings), "javascript-can-open-windows-automatically", !flag, NULL);
-
-}
-
-void TestRunner::setPluginsEnabled(bool flag)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
-
- WebKitWebSettings* settings = webkit_web_view_get_settings(view);
- g_object_set(G_OBJECT(settings), "enable-plugins", flag, NULL);
-}
-
-void TestRunner::execCommand(JSStringRef name, JSStringRef value)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
-
- gchar* cName = JSStringCopyUTF8CString(name);
- gchar* cValue = JSStringCopyUTF8CString(value);
- DumpRenderTreeSupportGtk::executeCoreCommandByName(view, cName, cValue);
- g_free(cName);
- g_free(cValue);
-}
-
-bool TestRunner::findString(JSContextRef context, JSStringRef target, JSObjectRef optionsArray)
-{
- WebKitFindOptions findOptions = 0;
- WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(webView);
-
- JSRetainPtr<JSStringRef> lengthPropertyName(Adopt, JSStringCreateWithUTF8CString("length"));
- JSValueRef lengthValue = JSObjectGetProperty(context, optionsArray, lengthPropertyName.get(), 0);
- if (!JSValueIsNumber(context, lengthValue))
- return false;
-
- GUniquePtr<gchar> targetString(JSStringCopyUTF8CString(target));
-
- size_t length = static_cast<size_t>(JSValueToNumber(context, lengthValue, 0));
- for (size_t i = 0; i < length; ++i) {
- JSValueRef value = JSObjectGetPropertyAtIndex(context, optionsArray, i, 0);
- if (!JSValueIsString(context, value))
- continue;
-
- JSRetainPtr<JSStringRef> optionName(Adopt, JSValueToStringCopy(context, value, 0));
-
- if (JSStringIsEqualToUTF8CString(optionName.get(), "CaseInsensitive"))
- findOptions |= WebKit::WebFindOptionsCaseInsensitive;
- else if (JSStringIsEqualToUTF8CString(optionName.get(), "AtWordStarts"))
- findOptions |= WebKit::WebFindOptionsAtWordStarts;
- else if (JSStringIsEqualToUTF8CString(optionName.get(), "TreatMedialCapitalAsWordStart"))
- findOptions |= WebKit::WebFindOptionsTreatMedialCapitalAsWordStart;
- else if (JSStringIsEqualToUTF8CString(optionName.get(), "Backwards"))
- findOptions |= WebKit::WebFindOptionsBackwards;
- else if (JSStringIsEqualToUTF8CString(optionName.get(), "WrapAround"))
- findOptions |= WebKit::WebFindOptionsWrapAround;
- else if (JSStringIsEqualToUTF8CString(optionName.get(), "StartInSelection"))
- findOptions |= WebKit::WebFindOptionsStartInSelection;
- }
-
- return DumpRenderTreeSupportGtk::findString(webView, targetString.get(), findOptions);
-}
-
-bool TestRunner::isCommandEnabled(JSStringRef name)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
-
- gchar* cName = JSStringCopyUTF8CString(name);
- bool result = DumpRenderTreeSupportGtk::isCommandEnabled(view, cName);
- g_free(cName);
- return result;
-}
-
-void TestRunner::setCacheModel(int cacheModel)
-{
- // These constants are derived from the Mac cache model enum in Source/WebKit/mac/WebView/WebPreferences.h.
- switch (cacheModel) {
- case 0:
- webkit_set_cache_model(WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER);
- break;
- case 1:
- webkit_set_cache_model(WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER);
- break;
- case 2:
- webkit_set_cache_model(WEBKIT_CACHE_MODEL_WEB_BROWSER);
- break;
- default:
- ASSERT_NOT_REACHED();
- }
-}
-
-void TestRunner::setPersistentUserStyleSheetLocation(JSStringRef jsURL)
-{
- // FIXME: implement
-}
-
-void TestRunner::clearPersistentUserStyleSheet()
-{
- // FIXME: implement
-}
-
-void TestRunner::clearAllApplicationCaches()
-{
- // FIXME: Implement to support application cache quotas.
-}
-
-void TestRunner::clearApplicationCacheForOrigin(OpaqueJSString*)
-{
- // FIXME: Implement to support deleting all application caches for an origin.
-}
-
-long long TestRunner::localStorageDiskUsageForOrigin(JSStringRef originIdentifier)
-{
- // FIXME: Implement to support getting disk usage in bytes for an origin.
- return 0;
-}
-
-JSValueRef TestRunner::originsWithApplicationCache(JSContextRef context)
-{
- // FIXME: Implement to get origins that contain application caches.
- return JSValueMakeUndefined(context);
-}
-
-long long TestRunner::applicationCacheDiskUsageForOrigin(JSStringRef name)
-{
- // FIXME: implement
- return 0;
-}
-
-void TestRunner::clearAllDatabases()
-{
- webkit_remove_all_web_databases();
-}
-
-void TestRunner::setDatabaseQuota(unsigned long long quota)
-{
- WebKitSecurityOrigin* origin = webkit_web_frame_get_security_origin(mainFrame);
- webkit_security_origin_set_web_database_quota(origin, quota);
-}
-
-JSValueRef TestRunner::originsWithLocalStorage(JSContextRef context)
-{
- // FIXME: implement
- return JSValueMakeUndefined(context);
-}
-
-void TestRunner::deleteAllLocalStorage()
-{
- // FIXME: implement
-}
-
-void TestRunner::deleteLocalStorageForOrigin(JSStringRef originIdentifier)
-{
- // FIXME: implement
-}
-
-void TestRunner::observeStorageTrackerNotifications(unsigned number)
-{
- // FIXME: implement
-}
-
-void TestRunner::syncLocalStorage()
-{
- // FIXME: implement
-}
-
-void TestRunner::setDomainRelaxationForbiddenForURLScheme(bool forbidden, JSStringRef scheme)
-{
- GUniquePtr<gchar> urlScheme(JSStringCopyUTF8CString(scheme));
- DumpRenderTreeSupportGtk::setDomainRelaxationForbiddenForURLScheme(forbidden, urlScheme.get());
-}
-
-void TestRunner::goBack()
-{
- WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
- webkit_web_view_go_back(webView);
-}
-
-void TestRunner::setDefersLoading(bool defers)
-{
- WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
- DumpRenderTreeSupportGtk::setDefersLoading(webView, defers);
-}
-
-void TestRunner::setAppCacheMaximumSize(unsigned long long size)
-{
- webkit_application_cache_set_maximum_size(size);
-}
-
-static gboolean booleanFromValue(gchar* value)
-{
- return !g_ascii_strcasecmp(value, "true") || !g_ascii_strcasecmp(value, "1");
-}
-
-void TestRunner::overridePreference(JSStringRef key, JSStringRef value)
-{
- GUniquePtr<gchar> originalName(JSStringCopyUTF8CString(key));
- GUniquePtr<gchar> valueAsString(JSStringCopyUTF8CString(value));
-
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
-
- // This transformation could be handled by a hash table (and it once was), but
- // having it prominent, makes it easier for people from other ports to keep the
- // list up to date.
- const gchar* propertyName = 0;
- if (g_str_equal(originalName.get(), "WebKitJavaScriptEnabled"))
- propertyName = "enable-scripts";
- else if (g_str_equal(originalName.get(), "WebKitDefaultFontSize"))
- propertyName = "default-font-size";
- else if (g_str_equal(originalName.get(), "WebKitEnableCaretBrowsing"))
- propertyName = "enable-caret-browsing";
- else if (g_str_equal(originalName.get(), "WebKitUsesPageCachePreferenceKey"))
- propertyName = "enable-page-cache";
- else if (g_str_equal(originalName.get(), "WebKitPluginsEnabled"))
- propertyName = "enable-plugins";
- else if (g_str_equal(originalName.get(), "WebKitHyperlinkAuditingEnabled"))
- propertyName = "enable-hyperlink-auditing";
- else if (g_str_equal(originalName.get(), "WebKitWebGLEnabled"))
- propertyName = "enable-webgl";
- else if (g_str_equal(originalName.get(), "WebKitWebAudioEnabled"))
- propertyName = "enable-webaudio";
- else if (g_str_equal(originalName.get(), "WebKitDisplayImagesKey"))
- propertyName = "auto-load-images";
- else if (g_str_equal(originalName.get(), "WebKitShouldRespectImageOrientation"))
- propertyName = "respect-image-orientation";
- else if (g_str_equal(originalName.get(), "WebKitMediaSourceEnabled"))
- propertyName = "enable-mediasource";
- else if (g_str_equal(originalName.get(), "WebKitTabToLinksPreferenceKey")) {
- DumpRenderTreeSupportGtk::setLinksIncludedInFocusChain(booleanFromValue(valueAsString.get()));
- return;
- } else if (g_str_equal(originalName.get(), "WebKitPageCacheSupportsPluginsPreferenceKey")) {
- DumpRenderTreeSupportGtk::setPageCacheSupportsPlugins(webkit_web_frame_get_web_view(mainFrame), booleanFromValue(valueAsString.get()));
- return;
- } else if (g_str_equal(originalName.get(), "WebKitCSSGridLayoutEnabled")) {
- DumpRenderTreeSupportGtk::setCSSGridLayoutEnabled(webkit_web_frame_get_web_view(mainFrame), booleanFromValue(valueAsString.get()));
- return;
- } else if (g_str_equal(originalName.get(), "WebKitCSSRegionsEnabled")) {
- DumpRenderTreeSupportGtk::setCSSRegionsEnabled(webkit_web_frame_get_web_view(mainFrame), booleanFromValue(valueAsString.get()));
- return;
- } else {
- fprintf(stderr, "TestRunner::overridePreference tried to override "
- "unknown preference '%s'.\n", originalName.get());
- return;
- }
-
- WebKitWebSettings* settings = webkit_web_view_get_settings(view);
- GParamSpec* pspec = g_object_class_find_property(G_OBJECT_CLASS(
- WEBKIT_WEB_SETTINGS_GET_CLASS(settings)), propertyName);
- GValue currentPropertyValue = { 0, { { 0 } } };
- g_value_init(&currentPropertyValue, pspec->value_type);
-
- if (G_VALUE_HOLDS_STRING(&currentPropertyValue))
- g_object_set(settings, propertyName, valueAsString.get(), NULL);
- else if (G_VALUE_HOLDS_BOOLEAN(&currentPropertyValue))
- g_object_set(G_OBJECT(settings), propertyName, booleanFromValue(valueAsString.get()), NULL);
- else if (G_VALUE_HOLDS_INT(&currentPropertyValue))
- g_object_set(G_OBJECT(settings), propertyName, atoi(valueAsString.get()), NULL);
- else if (G_VALUE_HOLDS_FLOAT(&currentPropertyValue)) {
- gfloat newValue = g_ascii_strtod(valueAsString.get(), 0);
- g_object_set(G_OBJECT(settings), propertyName, newValue, NULL);
- } else
- fprintf(stderr, "TestRunner::overridePreference failed to override "
- "preference '%s'.\n", originalName.get());
-}
-
-void TestRunner::addUserScript(JSStringRef source, bool runAtStart, bool allFrames)
-{
- GUniquePtr<gchar> sourceCode(JSStringCopyUTF8CString(source));
- DumpRenderTreeSupportGtk::addUserScript(mainFrame, sourceCode.get(), runAtStart, allFrames);
-}
-
-void TestRunner::addUserStyleSheet(JSStringRef source, bool allFrames)
-{
- GUniquePtr<gchar> sourceCode(JSStringCopyUTF8CString(source));
- DumpRenderTreeSupportGtk::addUserStyleSheet(mainFrame, sourceCode.get(), allFrames);
- // FIXME: needs more investigation why userscripts/user-style-top-frame-only.html fails when allFrames is false.
-
-}
-
-void TestRunner::setDeveloperExtrasEnabled(bool enabled)
-{
- WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
- WebKitWebSettings* webSettings = webkit_web_view_get_settings(webView);
-
- g_object_set(webSettings, "enable-developer-extras", enabled, NULL);
-}
-
-void TestRunner::showWebInspector()
-{
- WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
- WebKitWebInspector* inspector = webkit_web_view_get_inspector(webView);
-
- webkit_web_inspector_show(inspector);
-}
-
-void TestRunner::closeWebInspector()
-{
- WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
- WebKitWebInspector* inspector = webkit_web_view_get_inspector(webView);
-
- webkit_web_inspector_close(inspector);
-}
-
-void TestRunner::evaluateInWebInspector(long callId, JSStringRef script)
-{
- WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
- WebKitWebInspector* inspector = webkit_web_view_get_inspector(webView);
- char* scriptString = JSStringCopyUTF8CString(script);
-
- webkit_web_inspector_execute_script(inspector, callId, scriptString);
- g_free(scriptString);
-}
-
-void TestRunner::evaluateScriptInIsolatedWorldAndReturnValue(unsigned worldID, JSObjectRef globalObject, JSStringRef script)
-{
- // FIXME: Implement this.
-}
-
-void TestRunner::evaluateScriptInIsolatedWorld(unsigned worldID, JSObjectRef globalObject, JSStringRef script)
-{
- // FIXME: Implement this.
-}
-
-void TestRunner::removeAllVisitedLinks()
-{
- // FIXME: Implement this.
-}
-
-bool TestRunner::callShouldCloseOnWebView()
-{
- return DumpRenderTreeSupportGtk::shouldClose(mainFrame);
-}
-
-void TestRunner::apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data, JSStringRef baseURL)
-{
-
-}
-
-void TestRunner::apiTestGoToCurrentBackForwardItem()
-{
-
-}
-
-void TestRunner::setWebViewEditable(bool)
-{
-}
-
-void TestRunner::authenticateSession(JSStringRef, JSStringRef, JSStringRef)
-{
-}
-
-void TestRunner::abortModal()
-{
-}
-
-void TestRunner::setSerializeHTTPLoads(bool serialize)
-{
- DumpRenderTreeSupportGtk::setSerializeHTTPLoads(serialize);
-}
-
-void TestRunner::setTextDirection(JSStringRef direction)
-{
- GUniquePtr<gchar> writingDirection(JSStringCopyUTF8CString(direction));
-
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
-
- if (g_str_equal(writingDirection.get(), "auto"))
- gtk_widget_set_direction(GTK_WIDGET(view), GTK_TEXT_DIR_NONE);
- else if (g_str_equal(writingDirection.get(), "ltr"))
- gtk_widget_set_direction(GTK_WIDGET(view), GTK_TEXT_DIR_LTR);
- else if (g_str_equal(writingDirection.get(), "rtl"))
- gtk_widget_set_direction(GTK_WIDGET(view), GTK_TEXT_DIR_RTL);
- else
- fprintf(stderr, "TestRunner::setTextDirection called with unknown direction: '%s'.\n", writingDirection.get());
-}
-
-void TestRunner::addChromeInputField()
-{
-}
-
-void TestRunner::removeChromeInputField()
-{
-}
-
-void TestRunner::focusWebView()
-{
-}
-
-void TestRunner::setBackingScaleFactor(double)
-{
-}
-
-void TestRunner::grantWebNotificationPermission(JSStringRef origin)
-{
-}
-
-void TestRunner::denyWebNotificationPermission(JSStringRef jsOrigin)
-{
-}
-
-void TestRunner::removeAllWebNotificationPermissions()
-{
-}
-
-void TestRunner::simulateWebNotificationClick(JSValueRef jsNotification)
-{
-}
-
-void TestRunner::simulateLegacyWebNotificationClick(JSStringRef title)
-{
-}
-
-void TestRunner::resetPageVisibility()
-{
- WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
- DumpRenderTreeSupportGtk::setPageVisibility(webView, WebCore::PageVisibilityStateVisible, true);
-}
-
-void TestRunner::setPageVisibility(const char* visibility)
-{
- WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
- String visibilityString(visibility);
- WebCore::PageVisibilityState visibilityState = WebCore::PageVisibilityStateVisible;
-
- if (visibilityString == "visible")
- visibilityState = WebCore::PageVisibilityStateVisible;
- else if (visibilityString == "hidden")
- visibilityState = WebCore::PageVisibilityStateHidden;
- else
- return;
-
- DumpRenderTreeSupportGtk::setPageVisibility(webView, visibilityState, false);
-}
-
-void TestRunner::setAutomaticLinkDetectionEnabled(bool)
-{
- // FIXME: Implement this.
-}
-
-void TestRunner::setStorageDatabaseIdleInterval(double)
-{
- // FIXME: Implement this.
-}
-
-void TestRunner::closeIdleLocalStorageDatabases()
-{
-}
diff --git a/Tools/DumpRenderTree/gtk/TextInputController.cpp b/Tools/DumpRenderTree/gtk/TextInputController.cpp
deleted file mode 100644
index aee5597ed..000000000
--- a/Tools/DumpRenderTree/gtk/TextInputController.cpp
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2011 Igalia S.L.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "TextInputController.h"
-
-#include "DumpRenderTree.h"
-#include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
-#include <GUniquePtrGtk.h>
-#include <JavaScriptCore/JSObjectRef.h>
-#include <JavaScriptCore/JSRetainPtr.h>
-#include <JavaScriptCore/JSStringRef.h>
-#include <cstring>
-#include <webkit/webkit.h>
-
-static JSValueRef setMarkedTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
- if (argumentCount < 3)
- return JSValueMakeUndefined(context);
-
- JSStringRef string = JSValueToStringCopy(context, arguments[0], exception);
- ASSERT(!exception || !*exception);
-
- size_t bufferSize = JSStringGetMaximumUTF8CStringSize(string);
- GUniquePtr<gchar> stringBuffer(static_cast<gchar*>(g_malloc(bufferSize)));
- JSStringGetUTF8CString(string, stringBuffer.get(), bufferSize);
- JSStringRelease(string);
-
- int start = static_cast<int>(JSValueToNumber(context, arguments[1], exception));
- ASSERT(!exception || !*exception);
-
- int length = static_cast<int>(JSValueToNumber(context, arguments[2], exception));
- ASSERT(!exception || !*exception);
-
- DumpRenderTreeSupportGtk::setComposition(view, stringBuffer.get(), start, length);
- return JSValueMakeUndefined(context);
-}
-
-static JSValueRef hasMarkedTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
- return JSValueMakeBoolean(context, DumpRenderTreeSupportGtk::hasComposition(view));
-}
-
-static JSValueRef markedRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
-
- int start, length;
- if (!DumpRenderTreeSupportGtk::compositionRange(view, &start, &length))
- return JSValueMakeUndefined(context);
-
- JSValueRef arrayValues[2];
- arrayValues[0] = JSValueMakeNumber(context, start);
- arrayValues[1] = JSValueMakeNumber(context, length);
- JSObjectRef arrayObject = JSObjectMakeArray(context, 2, arrayValues, exception);
- ASSERT(!exception || !*exception);
- return arrayObject;
-}
-
-static JSValueRef insertTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
-
- if (argumentCount < 1)
- return JSValueMakeUndefined(context);
-
- JSStringRef string = JSValueToStringCopy(context, arguments[0], exception);
- ASSERT(!exception || !*exception);
-
- size_t bufferSize = JSStringGetMaximumUTF8CStringSize(string);
- GUniquePtr<gchar> stringBuffer(static_cast<gchar*>(g_malloc(bufferSize)));
- JSStringGetUTF8CString(string, stringBuffer.get(), bufferSize);
- JSStringRelease(string);
-
- DumpRenderTreeSupportGtk::confirmComposition(view, stringBuffer.get());
- return JSValueMakeUndefined(context);
-}
-
-static JSValueRef unmarkTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
-
- DumpRenderTreeSupportGtk::confirmComposition(view, 0);
- return JSValueMakeUndefined(context);
-}
-
-static JSValueRef firstRectForCharacterRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
- if (argumentCount < 2)
- return JSValueMakeUndefined(context);
-
- int location = static_cast<int>(JSValueToNumber(context, arguments[0], exception));
- ASSERT(!exception || !*exception);
-
- int length = static_cast<int>(JSValueToNumber(context, arguments[1], exception));
- ASSERT(!exception || !*exception);
-
- cairo_rectangle_int_t rect;
- if (!DumpRenderTreeSupportGtk::firstRectForCharacterRange(view, location, length, &rect))
- return JSValueMakeUndefined(context);
-
- JSValueRef arrayValues[4];
- arrayValues[0] = JSValueMakeNumber(context, rect.x);
- arrayValues[1] = JSValueMakeNumber(context, rect.y);
- arrayValues[2] = JSValueMakeNumber(context, rect.width);
- arrayValues[3] = JSValueMakeNumber(context, rect.height);
- JSObjectRef arrayObject = JSObjectMakeArray(context, 4, arrayValues, exception);
- ASSERT(!exception || !*exception);
-
- return arrayObject;
-}
-
-static JSValueRef selectedRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
-
- int start, length;
- if (!DumpRenderTreeSupportGtk::selectedRange(view, &start, &length))
- return JSValueMakeUndefined(context);
-
- JSValueRef arrayValues[2];
- arrayValues[0] = JSValueMakeNumber(context, start);
- arrayValues[1] = JSValueMakeNumber(context, length);
- JSObjectRef arrayObject = JSObjectMakeArray(context, 2, arrayValues, exception);
- ASSERT(!exception || !*exception);
-
- return arrayObject;
-}
-
-static JSValueRef doCommandCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- ASSERT(view);
- if (argumentCount < 1)
- return JSValueMakeUndefined(context);
-
- JSStringRef string = JSValueToStringCopy(context, arguments[0], exception);
- ASSERT(!exception || !*exception);
-
- size_t bufferSize = JSStringGetMaximumUTF8CStringSize(string);
- GUniquePtr<gchar> stringBuffer(static_cast<gchar*>(g_malloc(bufferSize)));
- JSStringGetUTF8CString(string, stringBuffer.get(), bufferSize);
- JSStringRelease(string);
-
- DumpRenderTreeSupportGtk::doCommand(view, stringBuffer.get());
- return JSValueMakeUndefined(context);
-}
-
-static JSStaticFunction staticFunctions[] = {
- { "setMarkedText", setMarkedTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "hasMarkedText", hasMarkedTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "markedRange", markedRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "insertText", insertTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "unmarkText", unmarkTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "firstRectForCharacterRange", firstRectForCharacterRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "selectedRange", selectedRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "doCommand", doCommandCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { 0, 0, 0 }
-};
-
-static JSClassRef getClass(JSContextRef context)
-{
- static JSClassRef textInputControllerClass = 0;
-
- if (!textInputControllerClass) {
- JSClassDefinition classDefinition = {
- 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- classDefinition.staticFunctions = staticFunctions;
-
- textInputControllerClass = JSClassCreate(&classDefinition);
- }
-
- return textInputControllerClass;
-}
-
-JSObjectRef makeTextInputController(JSContextRef context)
-{
- return JSObjectMake(context, getClass(context), 0);
-}
diff --git a/Tools/DumpRenderTree/gtk/WorkQueueItemGtk.cpp b/Tools/DumpRenderTree/gtk/WorkQueueItemGtk.cpp
deleted file mode 100644
index 95461276e..000000000
--- a/Tools/DumpRenderTree/gtk/WorkQueueItemGtk.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2007 Alp Toker <alp@atoker.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include "WorkQueueItem.h"
-
-#include "DumpRenderTree.h"
-
-#include <JavaScriptCore/JSStringRef.h>
-#include <string.h>
-#include <webkit/webkit.h>
-#include <wtf/gobject/GUniquePtr.h>
-
-// Returns a newly allocated UTF-8 character buffer which must be freed with g_free()
-gchar* JSStringCopyUTF8CString(JSStringRef jsString)
-{
- size_t dataSize = JSStringGetMaximumUTF8CStringSize(jsString);
- gchar* utf8 = (gchar*)g_malloc(dataSize);
- JSStringGetUTF8CString(jsString, utf8, dataSize);
-
- return utf8;
-}
-
-bool LoadItem::invoke() const
-{
- gchar* targetString = JSStringCopyUTF8CString(m_target.get());
-
- WebKitWebFrame* targetFrame;
- if (!strlen(targetString))
- targetFrame = mainFrame;
- else
- targetFrame = webkit_web_frame_find_frame(mainFrame, targetString);
- g_free(targetString);
-
- gchar* urlString = JSStringCopyUTF8CString(m_url.get());
- WebKitNetworkRequest* request = webkit_network_request_new(urlString);
- g_free(urlString);
- webkit_web_frame_load_request(targetFrame, request);
- g_object_unref(request);
-
- return true;
-}
-
-bool LoadHTMLStringItem::invoke() const
-{
- GUniquePtr<gchar> content(JSStringCopyUTF8CString(m_content.get()));
- GUniquePtr<gchar> baseURL(JSStringCopyUTF8CString(m_baseURL.get()));
-
- if (m_unreachableURL) {
- GUniquePtr<gchar> unreachableURL(JSStringCopyUTF8CString(m_unreachableURL.get()));
- webkit_web_frame_load_alternate_string(mainFrame, content.get(), baseURL.get(), unreachableURL.get());
- return true;
- }
- webkit_web_frame_load_string(mainFrame, content.get(), 0, 0, baseURL.get());
- return true;
-}
-
-bool ReloadItem::invoke() const
-{
- webkit_web_frame_reload(mainFrame);
- return true;
-}
-
-bool ScriptItem::invoke() const
-{
- WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
- gchar* scriptString = JSStringCopyUTF8CString(m_script.get());
- webkit_web_view_execute_script(webView, scriptString);
- g_free(scriptString);
- return true;
-}
-
-bool BackForwardItem::invoke() const
-{
- WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
- if (m_howFar == 1)
- webkit_web_view_go_forward(webView);
- else if (m_howFar == -1)
- webkit_web_view_go_back(webView);
- else {
- WebKitWebBackForwardList* webBackForwardList = webkit_web_view_get_back_forward_list(webView);
- WebKitWebHistoryItem* item = webkit_web_back_forward_list_get_nth_item(webBackForwardList, m_howFar);
- webkit_web_view_go_to_back_forward_item(webView, item);
- }
- return true;
-}
diff --git a/Tools/GNUmakefile.am b/Tools/GNUmakefile.am
deleted file mode 100644
index 115e09bfc..000000000
--- a/Tools/GNUmakefile.am
+++ /dev/null
@@ -1,277 +0,0 @@
-noinst_PROGRAMS += \
- Programs/ImageDiff
-
-if ENABLE_WEBKIT1
-noinst_PROGRAMS += \
- Programs/DumpRenderTree
-endif
-
-# libWebCoreInternals
-# We must split off the window.internals implementation into a separate
-# convenience library because it requires a different include path order
-# to prefer the WebCore config.h over the DumpRenderTree config.h
-noinst_LTLIBRARIES += libWebCoreInternals.la
-libWebCoreInternals_la_SOURCES = \
- Source/WebCore/bindings/js/JSDOMWrapper.cpp \
- Source/WebCore/bindings/js/JSDOMWrapper.h \
- Source/WebCore/testing/MallocStatistics.h \
- Source/WebCore/testing/MemoryInfo.h \
- Source/WebCore/testing/Internals.cpp \
- Source/WebCore/testing/Internals.h \
- Source/WebCore/testing/InternalSettings.cpp \
- Source/WebCore/testing/InternalSettings.h \
- Source/WebCore/testing/TypeConversions.h \
- Source/WebCore/testing/js/WebCoreTestSupport.cpp \
- Source/WebCore/testing/js/WebCoreTestSupport.h
-
-libwebcoreinternals_built_sources += \
- DerivedSources/WebCore/InternalSettingsGenerated.cpp \
- DerivedSources/WebCore/InternalSettingsGenerated.h \
- DerivedSources/WebCore/JSMallocStatistics.cpp \
- DerivedSources/WebCore/JSMallocStatistics.h \
- DerivedSources/WebCore/JSMemoryInfo.cpp \
- DerivedSources/WebCore/JSMemoryInfo.h \
- DerivedSources/WebCore/JSInternals.cpp \
- DerivedSources/WebCore/JSInternals.h \
- DerivedSources/WebCore/JSInternalSettings.cpp \
- DerivedSources/WebCore/JSInternalSettings.h \
- DerivedSources/WebCore/JSInternalSettingsGenerated.cpp \
- DerivedSources/WebCore/JSInternalSettingsGenerated.h \
- DerivedSources/WebCore/JSTypeConversions.cpp \
- DerivedSources/WebCore/JSTypeConversions.h
-
-nodist_libWebCoreInternals_la_SOURCES = $(libwebcoreinternals_built_sources)
-BUILT_SOURCES += $(libwebcoreinternals_built_sources)
-
-libWebCoreInternals_la_CPPFLAGS = \
- $(global_cppflags) \
- $(platform_cppflags) \
- $(platformgtk_cppflags) \
- $(webcore_cppflags) \
- $(webcoregtk_cppflags) \
- $(javascriptcore_cppflags) \
- $(CAIRO_CFLAGS) \
- $(FREETYPE_CFLAGS) \
- $(LIBSOUP_CFLAGS) \
- $(PANGO_CFLAGS) \
- -I$(top_builddir)/DerivedSources \
- -I$(top_builddir)/DerivedSources/WebCore
-
-libWebCoreInternals_la_CXXFLAGS = \
- $(global_cxxflags) \
- $(libWebCoreInternals_la_CFLAGS)
-
-libWebCoreInternals_la_CFLAGS = \
- -fno-strict-aliasing \
- $(javascriptcore_cflags)
-
-# DumpRenderTree
-Programs_DumpRenderTree_CPPFLAGS = \
- $(global_cppflags) \
- -DTOP_LEVEL_DIR=\"${shell pwd}/${srcdir}\" \
- -I$(srcdir)/Tools/DumpRenderTree \
- -I$(srcdir)/Tools/DumpRenderTree/atk \
- -I$(srcdir)/Tools/DumpRenderTree/cairo \
- -I$(srcdir)/Tools/DumpRenderTree/gtk \
- -I$(srcdir)/Source/WebKit/gtk \
- -I$(srcdir)/Source/WebCore/platform/gtk \
- -I$(srcdir)/Source/WebCore/testing/js \
- -I$(top_builddir)/DerivedSources \
- -I$(top_builddir)/Source/WebKit/gtk \
- $(javascriptcore_cppflags) \
- $(platform_cppflags) \
- $(platformgtk_cppflags) \
- $(webcore_cppflags)
-
-if TARGET_X11_OR_WAYLAND
-Programs_DumpRenderTree_CPPFLAGS += \
- -DTEST_PLUGIN_DIR=\"${shell pwd}/${top_builddir}/TestNetscapePlugin/.libs\" \
- -DFONTS_CONF_DIR=\"${shell pwd}/${srcdir}/Tools/DumpRenderTree/gtk/fonts\"
-endif
-
-Programs_DumpRenderTree_SOURCES = \
- Source/WebCore/platform/gtk/GtkVersioning.c \
- Tools/DumpRenderTree/DumpRenderTree.h \
- Tools/DumpRenderTree/DumpRenderTreeCommon.cpp \
- Tools/DumpRenderTree/DumpRenderTreePrefix.h \
- Tools/DumpRenderTree/AccessibilityController.cpp \
- Tools/DumpRenderTree/AccessibilityController.h \
- Tools/DumpRenderTree/AccessibilityTextMarker.cpp \
- Tools/DumpRenderTree/AccessibilityTextMarker.h \
- Tools/DumpRenderTree/AccessibilityUIElement.cpp \
- Tools/DumpRenderTree/AccessibilityUIElement.h \
- Tools/DumpRenderTree/CyclicRedundancyCheck.cpp \
- Tools/DumpRenderTree/CyclicRedundancyCheck.h \
- Tools/DumpRenderTree/GCController.cpp \
- Tools/DumpRenderTree/GCController.h \
- Tools/DumpRenderTree/JavaScriptThreading.h \
- Tools/DumpRenderTree/TestRunner.cpp \
- Tools/DumpRenderTree/TestRunner.h \
- Tools/DumpRenderTree/PixelDumpSupport.cpp \
- Tools/DumpRenderTree/PixelDumpSupport.h \
- Tools/DumpRenderTree/WorkQueue.cpp \
- Tools/DumpRenderTree/WorkQueue.h \
- Tools/DumpRenderTree/WorkQueueItem.h \
- Tools/DumpRenderTree/config.h \
- Tools/DumpRenderTree/atk/AccessibilityCallbacks.h \
- Tools/DumpRenderTree/atk/AccessibilityCallbacksAtk.cpp \
- Tools/DumpRenderTree/atk/AccessibilityControllerAtk.cpp \
- Tools/DumpRenderTree/atk/AccessibilityNotificationHandlerAtk.cpp \
- Tools/DumpRenderTree/atk/AccessibilityNotificationHandlerAtk.h \
- Tools/DumpRenderTree/atk/AccessibilityUIElementAtk.cpp \
- Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp \
- Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.h \
- Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp \
- Tools/DumpRenderTree/gtk/DumpRenderTree.cpp \
- Tools/DumpRenderTree/gtk/DumpRenderTreeGtk.h \
- Tools/DumpRenderTree/gtk/EditingCallbacks.h \
- Tools/DumpRenderTree/gtk/EditingCallbacks.cpp \
- Tools/DumpRenderTree/gtk/EventSender.h \
- Tools/DumpRenderTree/gtk/EventSender.cpp \
- Tools/DumpRenderTree/gtk/GCControllerGtk.cpp \
- Tools/DumpRenderTree/gtk/TestRunnerGtk.cpp \
- Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp \
- Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.cpp \
- Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.h \
- Tools/DumpRenderTree/gtk/TextInputController.h \
- Tools/DumpRenderTree/gtk/TextInputController.cpp \
- Tools/DumpRenderTree/gtk/WorkQueueItemGtk.cpp
-
-Programs_DumpRenderTree_CXXFLAGS = \
- $(global_cxxflags) \
- $(Programs_DumpRenderTree_CFLAGS)
-
-Programs_DumpRenderTree_CFLAGS = \
- -fno-strict-aliasing \
- $(global_cflags) \
- $(CAIRO_CFLAGS) \
- $(GTK_CFLAGS) \
- $(LIBSOUP_CFLAGS)
-
-Programs_DumpRenderTree_LDADD = \
- libjavascriptcoregtk-@WEBKITGTK_API_MAJOR_VERSION@.@WEBKITGTK_API_MINOR_VERSION@.la \
- libwebkitgtk-@WEBKITGTK_API_MAJOR_VERSION@.@WEBKITGTK_API_MINOR_VERSION@.la \
- libPlatform.la \
- libPlatformGtk.la \
- libWebCorePlatform.la \
- libWebCoreModules.la \
- libWebCoreInternals.la \
- $(CAIRO_LIBS) \
- $(GTK_LIBS) \
- $(GLIB_LIBS) \
- $(LIBSOUP_LIBS) \
- $(FREETYPE_LIBS) \
- $(WINMM_LIBS) \
- $(XRENDER_LIBS) \
- $(XT_LIBS)
-
-Programs_DumpRenderTree_LDFLAGS = \
- -no-install
-
-# ImageDiff
-Programs_ImageDiff_CPPFLAGS = $(global_cppflags)
-
-Programs_ImageDiff_SOURCES = \
- Tools/ImageDiff/gtk/ImageDiff.cpp
-
-Programs_ImageDiff_CXXFLAGS = \
- $(global_cxxflags) \
- $(global_cppflags) \
- $(Programs_ImageDiff_CFLAGS)
-
-Programs_ImageDiff_CFLAGS = \
- -fno-strict-aliasing \
- $(global_cflags) \
- $(GTK_CFLAGS)
-
-Programs_ImageDiff_LDADD = \
- $(GTK_LIBS)
-
-Programs_ImageDiff_LDFLAGS = \
- -no-install
-
-# clean target
-CLEANFILES += \
- Programs/DumpRenderTree \
- Programs/GtkLauncher \
- Programs/ImageDiff
-
-if TARGET_X11
-
-# Build TestNetscapePlugin only for X11
-# since we don't support plugins for non-X11 builds at the moment.
-noinst_LTLIBRARIES += \
- TestNetscapePlugin/libTestNetscapePlugin.la
-
-TestNetscapePlugin_libTestNetscapePlugin_la_CPPFLAGS = \
- -I$(srcdir)/Tools/DumpRenderTree \
- -I$(srcdir)/Source/WebCore \
- -I$(srcdir)/Source/WebCore/bridge \
- -I$(srcdir)/Source/WebCore/plugins \
- -I$(srcdir)/Tools/DumpRenderTree/TestNetscapePlugIn \
- -I$(srcdir)/Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders \
- $(global_cppflags) \
- $(javascriptcore_cppflags) \
- -Wno-missing-format-attribute
-
-# For the Gtk port we want to use XP_UNIX both on X11 and Mac
-if !TARGET_WIN32
-TestNetscapePlugin_libTestNetscapePlugin_la_CPPFLAGS += -DXP_UNIX
-endif
-
-# Add MOZ_X11 only for X11 targets
-if TARGET_X11
-TestNetscapePlugin_libTestNetscapePlugin_la_CPPFLAGS += -DMOZ_X11
-endif
-
-TestNetscapePlugin_libTestNetscapePlugin_la_SOURCES = \
- Tools/DumpRenderTree/TestNetscapePlugIn/Tests/DocumentOpenInDestroyStream.cpp \
- Tools/DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSAfterRemovingPluginElement.cpp \
- Tools/DumpRenderTree/TestNetscapePlugIn/Tests/FormValue.cpp \
- Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLNotifyWithURLThatFailsToLoad.cpp \
- Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLWithJavaScriptURL.cpp \
- Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLWithJavaScriptURLDestroyingPlugin.cpp \
- Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetUserAgentWithNullNPPFromNPPNew.cpp \
- Tools/DumpRenderTree/TestNetscapePlugIn/Tests/LogNPPSetWindow.cpp \
- Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPDeallocateCalledBeforeNPShutdown.cpp \
- Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPPNewFails.cpp \
- Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPPSetWindowCalledDuringDestruction.cpp \
- Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeCallsWithNullNPP.cpp \
- Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeObjectFromDestroyedPlugin.cpp \
- Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeRemoveProperty.cpp \
- Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NullNPPGetValuePointer.cpp \
- Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PassDifferentNPPStruct.cpp \
- Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PluginScriptableNPObjectInvokeDefault.cpp \
- Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PrivateBrowsing.cpp \
- Tools/DumpRenderTree/TestNetscapePlugIn/Tests/ToStringAndValueOfObject.cpp \
- Tools/DumpRenderTree/TestNetscapePlugIn/Tests/x11/CallInvalidateRectWithNullNPPArgument.cpp \
- Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp \
- Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h \
- Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp \
- Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.h \
- Tools/DumpRenderTree/TestNetscapePlugIn/TestObject.cpp \
- Tools/DumpRenderTree/TestNetscapePlugIn/TestObject.h \
- Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp \
- Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npapi.h \
- Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npfunctions.h \
- Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npruntime.h
-
-TestNetscapePlugin_libTestNetscapePlugin_la_LDFLAGS = \
- -rpath ${shell pwd}/$(top_builddir)/../unix/TestNetscapePlugin/.libs \
- $(no_undefined) \
- -avoid-version \
- -module
-
-CLEANFILES += TestNetscapePlugin/libTestNetscapePlugin.la
-endif
-
-check-local:
- $(top_srcdir)/Tools/Scripts/run-gtk-tests --timeout=-1
- $(top_srcdir)/Tools/gtk/check-for-webkitdom-api-breaks
-
-EXTRA_DIST += \
- Tools/jhbuild/jhbuildutils.py \
- Tools/Scripts/VCSUtils.pm \
- Tools/Scripts/run-gtk-tests \
- Tools/Scripts/webkit-build-directory \
- Tools/Scripts/webkitdirs.pm
diff --git a/Tools/GtkLauncher/GNUmakefile.am b/Tools/GtkLauncher/GNUmakefile.am
deleted file mode 100644
index 31ca2fba9..000000000
--- a/Tools/GtkLauncher/GNUmakefile.am
+++ /dev/null
@@ -1,42 +0,0 @@
-if ENABLE_WEBKIT1
-noinst_PROGRAMS += \
- Programs/GtkLauncher
-endif
-
-# GtkLauncher
-Programs_GtkLauncher_CPPFLAGS = \
- -I$(srcdir)/Source/WebKit/gtk \
- -I$(srcdir)/Source/WebCore/platform/network/soup/cache/ \
- -I$(top_builddir)/Source/WebKit/gtk \
- -I$(top_builddir)/DerivedSources \
- -DWEBKIT_EXEC_PATH=\"${shell pwd}/$(top_builddir)/Programs/\" \
- $(global_cppflags) \
- $(javascriptcore_cppflags)
-
-Programs_GtkLauncher_SOURCES = \
- Tools/GtkLauncher/LauncherInspectorWindow.c \
- Tools/GtkLauncher/LauncherInspectorWindow.h \
- Tools/GtkLauncher/main.c
-
-Programs_GtkLauncher_CFLAGS = \
- -ansi \
- -fno-strict-aliasing \
- $(global_cflags) \
- $(FREETYPE_CFLAGS) \
- $(GTK_CFLAGS) \
- $(LIBSOUP_CFLAGS) \
- $(GSTREAMER_CFLAGS)
-
-Programs_GtkLauncher_LDADD = \
- libwebkitgtk-@WEBKITGTK_API_MAJOR_VERSION@.@WEBKITGTK_API_MINOR_VERSION@.la \
- libjavascriptcoregtk-@WEBKITGTK_API_MAJOR_VERSION@.@WEBKITGTK_API_MINOR_VERSION@.la \
- $(FREETYPE_LIBS) \
- $(GTK_LIBS) \
- $(GLIB_LIBS) \
- $(LIBSOUP_LIBS) \
- $(WINMM_LIBS) \
- $(GSTREAMER_LIBS)
-
-Programs_GtkLauncher_LDFLAGS = \
- -no-install
-
diff --git a/Tools/GtkLauncher/LauncherInspectorWindow.c b/Tools/GtkLauncher/LauncherInspectorWindow.c
deleted file mode 100644
index 8ee9fcfb4..000000000
--- a/Tools/GtkLauncher/LauncherInspectorWindow.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2012 Igalia S.L.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "LauncherInspectorWindow.h"
-
-struct _LauncherInspectorWindow {
- GtkWindow parent;
-
- WebKitWebInspector *inspector;
- GtkWidget *webView;
-};
-
-struct _LauncherInspectorWindowClass {
- GtkWindowClass parent;
-};
-
-G_DEFINE_TYPE(LauncherInspectorWindow, launcher_inspector_window, GTK_TYPE_WINDOW)
-
-static void launcherInspectorWindowFinalize(GObject *gObject)
-{
- LauncherInspectorWindow *inspectorWindow = LAUNCHER_INSPECTOR_WINDOW(gObject);
- if (inspectorWindow->inspector)
- g_object_unref(inspectorWindow->inspector);
-
- G_OBJECT_CLASS(launcher_inspector_window_parent_class)->finalize(gObject);
-}
-
-static void launcher_inspector_window_init(LauncherInspectorWindow *inspectorWindow)
-{
- gtk_window_set_title(GTK_WINDOW(inspectorWindow), "Web Inspector");
- gtk_window_set_default_size(GTK_WINDOW(inspectorWindow), 800, 600);
-}
-
-static void launcher_inspector_window_class_init(LauncherInspectorWindowClass *klass)
-{
- GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
- gobjectClass->finalize = launcherInspectorWindowFinalize;
-}
-
-static void inspectedURIChanged(WebKitWebInspector *inspector, GParamSpec *paramSpec, LauncherInspectorWindow *inspectorWindow)
-{
- gchar *title = g_strdup_printf("Web Inspector - %s", webkit_web_inspector_get_inspected_uri(inspector));
- gtk_window_set_title(GTK_WINDOW(inspectorWindow), title);
- g_free(title);
-}
-
-static gboolean showInspectorWindow(WebKitWebInspector *inspector, LauncherInspectorWindow *inspectorWindow)
-{
- gtk_widget_show(GTK_WIDGET(inspectorWindow));
- return TRUE;
-}
-
-static gboolean closeInspectorWindow(WebKitWebInspector *inspector, LauncherInspectorWindow *inspectorWindow)
-{
- gtk_widget_hide(GTK_WIDGET(inspectorWindow));
- return TRUE;
-}
-
-static void inspectorWindowDestroyed(gpointer inspector, GObject* inspectorWindow)
-{
- g_signal_handlers_disconnect_by_data(inspector, inspectorWindow);
-}
-
-GtkWidget *launcherInspectorWindowNew(WebKitWebInspector *inspector, GtkWindow *parent)
-{
- LauncherInspectorWindow *inspectorWindow = LAUNCHER_INSPECTOR_WINDOW(g_object_new(LAUNCHER_TYPE_INSPECTOR_WINDOW, "type", GTK_WINDOW_TOPLEVEL, NULL));
- inspectorWindow->inspector = g_object_ref(inspector);
- inspectorWindow->webView = webkit_web_view_new();
- gtk_window_set_transient_for(GTK_WINDOW(inspectorWindow), parent);
-
- GtkWidget *scrolledWindow = gtk_scrolled_window_new(NULL, NULL);
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledWindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_container_add(GTK_CONTAINER(scrolledWindow), inspectorWindow->webView);
- gtk_widget_show(inspectorWindow->webView);
-
- gtk_container_add(GTK_CONTAINER(inspectorWindow), scrolledWindow);
- gtk_widget_show(scrolledWindow);
-
- g_signal_connect(inspector, "notify::inspected-uri", G_CALLBACK(inspectedURIChanged), inspectorWindow);
- g_signal_connect(inspector, "show-window", G_CALLBACK(showInspectorWindow), inspectorWindow);
- g_signal_connect(inspector, "close-window", G_CALLBACK(closeInspectorWindow), inspectorWindow);
-
- g_object_weak_ref(G_OBJECT(inspectorWindow), inspectorWindowDestroyed, inspector);
-
- return GTK_WIDGET(inspectorWindow);
-}
-
-WebKitWebView *launcherInspectorWindowGetWebView(LauncherInspectorWindow *inspectorWindow)
-{
- g_return_val_if_fail(LAUNCHER_IS_INSPECTOR_WINDOW(inspectorWindow), 0);
-
- return WEBKIT_WEB_VIEW(inspectorWindow->webView);
-}
diff --git a/Tools/GtkLauncher/main.c b/Tools/GtkLauncher/main.c
deleted file mode 100644
index c1b74814a..000000000
--- a/Tools/GtkLauncher/main.c
+++ /dev/null
@@ -1,564 +0,0 @@
-/*
- * Copyright (C) 2006, 2007 Apple Inc.
- * Copyright (C) 2007 Alp Toker <alp@atoker.com>
- * Copyright (C) 2011 Lukasz Slachciak
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H
-#ifdef BUILDING_WITH_CMAKE
-#include "cmakeconfig.h"
-#else
-#include "autotoolsconfig.h"
-#endif
-#endif
-
-#include "LauncherInspectorWindow.h"
-#include <errno.h>
-#include <gdk/gdkkeysyms.h>
-#ifdef WTF_USE_GSTREAMER
-#include <gst/gst.h>
-#endif
-#include <gtk/gtk.h>
-#include <stdlib.h>
-#include <string.h>
-#include <webkit/webkit.h>
-
-static gint windowCount = 0;
-
-static GtkWidget* createWindow(WebKitWebView** outWebView);
-
-static void activateUriEntryCb(GtkWidget* entry, gpointer data)
-{
- WebKitWebView *webView = g_object_get_data(G_OBJECT(entry), "web-view");
- const gchar* uri = gtk_entry_get_text(GTK_ENTRY(entry));
- g_assert(uri);
- gtk_entry_set_icon_from_pixbuf(GTK_ENTRY(entry), GTK_ENTRY_ICON_PRIMARY, 0);
- webkit_web_view_load_uri(webView, uri);
-}
-
-static void updateTitle(GtkWindow* window, WebKitWebView* webView)
-{
- GString *string = g_string_new(webkit_web_view_get_title(webView));
- gdouble loadProgress = webkit_web_view_get_progress(webView) * 100;
- g_string_append(string, " - WebKit Launcher");
- if (loadProgress < 100)
- g_string_append_printf(string, " (%f%%)", loadProgress);
- gchar *title = g_string_free(string, FALSE);
- gtk_window_set_title(window, title);
- g_free(title);
-}
-
-static void linkHoverCb(WebKitWebView* page, const gchar* title, const gchar* link, GtkStatusbar* statusbar)
-{
- guint statusContextId =
- GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(statusbar), "link-hover-context"));
- /* underflow is allowed */
- gtk_statusbar_pop(statusbar, statusContextId);
- if (link)
- gtk_statusbar_push(statusbar, statusContextId, link);
-}
-
-static void notifyTitleCb(WebKitWebView* webView, GParamSpec* pspec, GtkWidget* window)
-{
- updateTitle(GTK_WINDOW(window), webView);
-}
-
-static void notifyLoadStatusCb(WebKitWebView* webView, GParamSpec* pspec, GtkWidget* uriEntry)
-{
- if (webkit_web_view_get_load_status(webView) == WEBKIT_LOAD_COMMITTED) {
- WebKitWebFrame *frame = webkit_web_view_get_main_frame(webView);
- const gchar *uri = webkit_web_frame_get_uri(frame);
- if (uri)
- gtk_entry_set_text(GTK_ENTRY(uriEntry), uri);
- }
-}
-
-static void notifyProgressCb(WebKitWebView* webView, GParamSpec* pspec, GtkWidget* window)
-{
- updateTitle(GTK_WINDOW(window), webView);
-}
-
-static void destroyCb(GtkWidget* widget, GtkWidget* window)
-{
- if (g_atomic_int_dec_and_test(&windowCount))
- gtk_main_quit();
-}
-
-static void goBackCb(GtkWidget* widget, WebKitWebView* webView)
-{
- webkit_web_view_go_back(webView);
-}
-
-static void goForwardCb(GtkWidget* widget, WebKitWebView* webView)
-{
- webkit_web_view_go_forward(webView);
-}
-
-static void reloadCb(GtkWidget* widget, WebKitWebView* webView)
-{
- webkit_web_view_reload(webView);
-}
-
-static WebKitWebView*
-createWebViewCb(WebKitWebView* webView, WebKitWebFrame* web_frame, GtkWidget* window)
-{
- WebKitWebView *newWebView;
- createWindow(&newWebView);
- webkit_web_view_set_settings(newWebView, webkit_web_view_get_settings(webView));
- return newWebView;
-}
-
-static gboolean webViewReadyCb(WebKitWebView* webView, GtkWidget* window)
-{
- gtk_widget_grab_focus(GTK_WIDGET(webView));
- gtk_widget_show_all(window);
- return FALSE;
-}
-
-static gboolean closeWebViewCb(WebKitWebView* webView, GtkWidget* window)
-{
- gtk_widget_destroy(window);
- return TRUE;
-}
-
-static gboolean webViewFullscreenMessageWindowClose(GtkWidget *dialog)
-{
- if (GTK_IS_WIDGET(dialog))
- gtk_widget_destroy(dialog);
- return FALSE;
-}
-
-static gboolean webViewWindowStateEvent(GtkWidget *widget, GdkEventWindowState *event, WebKitWebView *webView)
-{
- if (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) {
- WebKitWebFrame *frame = webkit_web_view_get_main_frame(webView);
- const gchar *uri = webkit_web_frame_get_uri(frame);
- GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(webView));
- if (!gtk_widget_is_toplevel(window) || !GTK_IS_WINDOW(window) || GTK_IS_OFFSCREEN_WINDOW(window))
- window = 0;
-
- GtkWidget *dialog = gtk_message_dialog_new(window ? GTK_WINDOW(window) : 0,
- GTK_DIALOG_MODAL,
- GTK_MESSAGE_INFO,
- GTK_BUTTONS_CLOSE,
- "%s is now full screen. Press ESC or f to exit.", uri);
- g_signal_connect_swapped(dialog, "response", G_CALLBACK(gtk_widget_destroy), dialog);
- guint id = g_timeout_add(1500, (GSourceFunc) webViewFullscreenMessageWindowClose, dialog);
- g_source_set_name_by_id(id, "[WebKit] webViewFullscreenMessageWindowClose");
- gtk_dialog_run(GTK_DIALOG(dialog));
- }
- return TRUE;
-}
-
-static void hideWidget(GtkWidget* widget, gpointer data)
-{
- if (!GTK_IS_SCROLLED_WINDOW(widget))
- gtk_widget_hide(widget);
-}
-
-static void showWidget(GtkWidget* widget, gpointer data)
-{
- if (!GTK_IS_SCROLLED_WINDOW(widget))
- gtk_widget_show(widget);
-}
-
-static gboolean webViewEnteringFullScreen(WebKitWebView *webView, GObject *element, GtkWidget* vbox)
-{
- WebKitWebFrame *frame = webkit_web_view_get_main_frame(webView);
- const gchar *uri = webkit_web_frame_get_uri(frame);
- GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(webView));
- if (!gtk_widget_is_toplevel(window) || !GTK_IS_WINDOW(window) || GTK_IS_OFFSCREEN_WINDOW(window))
- window = 0;
-
- GtkWidget *dialog = gtk_message_dialog_new(window ? GTK_WINDOW(window) : 0,
- GTK_DIALOG_MODAL,
- GTK_MESSAGE_INFO,
- GTK_BUTTONS_YES_NO,
- "Allow full screen display of %s ?", uri);
- gint result = gtk_dialog_run(GTK_DIALOG(dialog));
- if (result == GTK_RESPONSE_YES) {
- gtk_container_foreach(GTK_CONTAINER(vbox), (GtkCallback) hideWidget, NULL);
- gtk_widget_destroy(GTK_WIDGET(dialog));
- return FALSE;
- }
- gtk_widget_destroy(GTK_WIDGET(dialog));
- return TRUE;
-}
-
-static gboolean webViewLeavingFullScreen(WebKitWebView *webView, GObject *element, GtkWidget* vbox)
-{
- GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(webView));
- if (gtk_widget_is_toplevel(window) && GTK_IS_WINDOW(window) && !GTK_IS_OFFSCREEN_WINDOW(window))
- g_signal_handlers_disconnect_by_func(window, G_CALLBACK(webViewWindowStateEvent), webView);
- gtk_container_foreach(GTK_CONTAINER(vbox), (GtkCallback) showWidget, NULL);
- return FALSE;
-}
-
-static void iconLoadedCb(WebKitWebView* webView, const char* iconURI, GtkWidget* uriEntry)
-{
- GdkPixbuf *icon = webkit_web_view_try_get_favicon_pixbuf(webView, 16, 16);
- if (!icon)
- return;
-
- gtk_entry_set_icon_from_pixbuf(GTK_ENTRY(uriEntry), GTK_ENTRY_ICON_PRIMARY, icon);
- g_object_unref(icon);
-}
-
-static GtkWidget *inspectorInspectWebViewCb(WebKitWebInspector *inspector, WebKitWebView *webView, GtkWindow* window)
-{
- GtkWidget *inspectorWindow = launcherInspectorWindowNew(inspector, window);
- return GTK_WIDGET(launcherInspectorWindowGetWebView(LAUNCHER_INSPECTOR_WINDOW(inspectorWindow)));
-}
-
-static GtkWidget* createBrowser(GtkWidget* window, GtkWidget* uriEntry, GtkWidget* statusbar, WebKitWebView* webView, GtkWidget* vbox)
-{
- char *iconDatabasePath;
- GtkWidget *scrolledWindow = gtk_scrolled_window_new(NULL, NULL);
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledWindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-
- gtk_container_add(GTK_CONTAINER(scrolledWindow), GTK_WIDGET(webView));
-
- iconDatabasePath = g_build_filename(g_get_user_cache_dir(), "GtkLauncher", "icondatabase", NULL);
- webkit_favicon_database_set_path(webkit_get_favicon_database(), iconDatabasePath);
- g_free(iconDatabasePath);
-
- g_signal_connect(webView, "notify::title", G_CALLBACK(notifyTitleCb), window);
- g_signal_connect(webView, "notify::load-status", G_CALLBACK(notifyLoadStatusCb), uriEntry);
- g_signal_connect(webView, "notify::progress", G_CALLBACK(notifyProgressCb), window);
- g_signal_connect(webView, "icon-loaded", G_CALLBACK(iconLoadedCb), uriEntry);
- g_signal_connect(webView, "hovering-over-link", G_CALLBACK(linkHoverCb), statusbar);
- g_signal_connect(webView, "create-web-view", G_CALLBACK(createWebViewCb), window);
- g_signal_connect(webView, "web-view-ready", G_CALLBACK(webViewReadyCb), window);
- g_signal_connect(webView, "close-web-view", G_CALLBACK(closeWebViewCb), window);
- g_signal_connect(webView, "entering-fullscreen", G_CALLBACK(webViewEnteringFullScreen), vbox);
- g_signal_connect(webView, "leaving-fullscreen", G_CALLBACK(webViewLeavingFullScreen), vbox);
- g_signal_connect(webkit_web_view_get_inspector(webView), "inspect-web-view", G_CALLBACK(inspectorInspectWebViewCb), window);
-
- return scrolledWindow;
-}
-
-static GtkWidget* createStatusbar()
-{
- GtkStatusbar *statusbar = GTK_STATUSBAR(gtk_statusbar_new());
- guint statusContextId = gtk_statusbar_get_context_id(statusbar, "Link Hover");
- g_object_set_data(G_OBJECT(statusbar), "link-hover-context",
- GUINT_TO_POINTER(statusContextId));
-
- return GTK_WIDGET(statusbar);
-}
-
-static GtkWidget* createToolbar(GtkWidget* window, GtkWidget* uriEntry, WebKitWebView* webView)
-{
- GtkWidget *toolbar = gtk_toolbar_new();
-
- gtk_orientable_set_orientation(GTK_ORIENTABLE(toolbar), GTK_ORIENTATION_HORIZONTAL);
- gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_BOTH_HORIZ);
-
- GtkToolItem *item;
-
- /* Keyboard accelerators */
- GtkAccelGroup *accelGroup = gtk_accel_group_new();
- gtk_window_add_accel_group(GTK_WINDOW(window), accelGroup);
-
- /* the back button */
- item = gtk_tool_button_new_from_stock(GTK_STOCK_GO_BACK);
- g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(goBackCb), webView);
- gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
-
- /* The forward button */
- item = gtk_tool_button_new_from_stock(GTK_STOCK_GO_FORWARD);
- g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(goForwardCb), webView);
- gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
-
- /* The reload button */
- item = gtk_tool_button_new_from_stock(GTK_STOCK_REFRESH);
- g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(reloadCb), webView);
- gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
- gtk_widget_add_accelerator(GTK_WIDGET(item), "clicked", accelGroup, GDK_KEY_F5, 0, GTK_ACCEL_VISIBLE);
-
- /* The URL entry */
- item = gtk_tool_item_new();
- gtk_tool_item_set_expand(item, TRUE);
- gtk_container_add(GTK_CONTAINER(item), uriEntry);
- g_signal_connect(G_OBJECT(uriEntry), "activate", G_CALLBACK(activateUriEntryCb), NULL);
- gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
-
- /* The go button */
- g_object_set_data(G_OBJECT(uriEntry), "web-view", webView);
- item = gtk_tool_button_new_from_stock(GTK_STOCK_OK);
- g_signal_connect_swapped(G_OBJECT(item), "clicked", G_CALLBACK(activateUriEntryCb), (gpointer)uriEntry);
- gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
-
- return toolbar;
-}
-
-static GtkWidget* createWindow(WebKitWebView** outWebView)
-{
- WebKitWebView *webView;
- GtkWidget *vbox;
- GtkWidget *window;
- GtkWidget *uriEntry;
- GtkWidget *statusbar;
-
- g_atomic_int_inc(&windowCount);
-
- window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
- gtk_widget_set_name(window, "GtkLauncher");
-
- webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- uriEntry = gtk_entry_new();
-
-#ifdef GTK_API_VERSION_2
- vbox = gtk_vbox_new(FALSE, 0);
-#else
- vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
-#endif
- statusbar = createStatusbar();
- gtk_box_pack_start(GTK_BOX(vbox), createToolbar(window, uriEntry, webView), FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(vbox), createBrowser(window, uriEntry, statusbar, webView, vbox), TRUE, TRUE, 0);
- gtk_box_pack_start(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0);
-
- gtk_container_add(GTK_CONTAINER(window), vbox);
-
- g_signal_connect(window, "destroy", G_CALLBACK(destroyCb), NULL);
-
- if (outWebView)
- *outWebView = webView;
-
- return window;
-}
-
-static gchar* filenameToURL(const char* filename)
-{
- if (!g_file_test(filename, G_FILE_TEST_EXISTS))
- return NULL;
-
- GFile *gfile = g_file_new_for_path(filename);
- gchar *fileURL = g_file_get_uri(gfile);
- g_object_unref(gfile);
-
- return fileURL;
-}
-
-static gboolean parseOptionEntryCallback(const gchar *optionNameFull, const gchar *value, WebKitWebSettings *webSettings, GError **error)
-{
- if (strlen(optionNameFull) <= 2) {
- g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "Invalid option %s", optionNameFull);
- return FALSE;
- }
-
- /* We have two -- in option name so remove them. */
- const gchar *optionName = optionNameFull + 2;
- GParamSpec *spec = g_object_class_find_property(G_OBJECT_GET_CLASS(webSettings), optionName);
- if (!spec) {
- g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "Cannot find web settings for option %s", optionNameFull);
- return FALSE;
- }
-
- switch (G_PARAM_SPEC_VALUE_TYPE(spec)) {
- case G_TYPE_BOOLEAN: {
- gboolean propertyValue = TRUE;
- if (value && g_ascii_strcasecmp(value, "true") && strcmp(value, "1"))
- propertyValue = FALSE;
- g_object_set(G_OBJECT(webSettings), optionName, propertyValue, NULL);
- break;
- }
- case G_TYPE_STRING:
- g_object_set(G_OBJECT(webSettings), optionName, value, NULL);
- break;
- case G_TYPE_INT: {
- glong propertyValue;
- gchar *end;
-
- errno = 0;
- propertyValue = g_ascii_strtoll(value, &end, 0);
- if (errno == ERANGE || propertyValue > G_MAXINT || propertyValue < G_MININT) {
- g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Integer value '%s' for %s out of range", value, optionNameFull);
- return FALSE;
- }
- if (errno || value == end) {
- g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Cannot parse integer value '%s' for %s", value, optionNameFull);
- return FALSE;
- }
- g_object_set(G_OBJECT(webSettings), optionName, propertyValue, NULL);
- break;
- }
- case G_TYPE_FLOAT: {
- gdouble propertyValue;
- gchar *end;
-
- errno = 0;
- propertyValue = g_ascii_strtod(value, &end);
- if (errno == ERANGE || propertyValue > G_MAXFLOAT || propertyValue < G_MINFLOAT) {
- g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Float value '%s' for %s out of range", value, optionNameFull);
- return FALSE;
- }
- if (errno || value == end) {
- g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Cannot parse float value '%s' for %s", value, optionNameFull);
- return FALSE;
- }
- g_object_set(G_OBJECT(webSettings), optionName, propertyValue, NULL);
- break;
- }
- default:
- g_assert_not_reached();
- }
-
- return TRUE;
-}
-
-static gboolean isValidParameterType(GType gParamType)
-{
- return (gParamType == G_TYPE_BOOLEAN || gParamType == G_TYPE_STRING || gParamType == G_TYPE_INT
- || gParamType == G_TYPE_FLOAT);
-}
-
-static GOptionEntry* getOptionEntriesFromWebKitWebSettings(WebKitWebSettings *webSettings)
-{
- GParamSpec **propertySpecs;
- GOptionEntry *optionEntries;
- guint numProperties, numEntries, i;
-
- propertySpecs = g_object_class_list_properties(G_OBJECT_GET_CLASS(webSettings), &numProperties);
- if (!propertySpecs)
- return NULL;
-
- optionEntries = g_new0(GOptionEntry, numProperties + 1);
- numEntries = 0;
- for (i = 0; i < numProperties; i++) {
- GParamSpec *param = propertySpecs[i];
-
- /* Fill in structures only for writable and not construct-only properties. */
- if (!param || !(param->flags & G_PARAM_WRITABLE) || (param->flags & G_PARAM_CONSTRUCT_ONLY))
- continue;
-
- GType gParamType = G_PARAM_SPEC_VALUE_TYPE(param);
- if (!isValidParameterType(gParamType))
- continue;
-
- GOptionEntry *optionEntry = &optionEntries[numEntries++];
- optionEntry->long_name = g_param_spec_get_name(param);
-
- /* There is no easy way to figure our short name for generated option entries.
- optionEntry.short_name=*/
- /* For bool arguments "enable" type make option argument not required. */
- if (gParamType == G_TYPE_BOOLEAN && (strstr(optionEntry->long_name, "enable")))
- optionEntry->flags = G_OPTION_FLAG_OPTIONAL_ARG;
- optionEntry->arg = G_OPTION_ARG_CALLBACK;
- optionEntry->arg_data = parseOptionEntryCallback;
- optionEntry->description = g_param_spec_get_blurb(param);
- optionEntry->arg_description = g_type_name(gParamType);
- }
- g_free(propertySpecs);
-
- return optionEntries;
-}
-
-static gboolean addWebSettingsGroupToContext(GOptionContext *context, WebKitWebSettings* webkitSettings)
-{
- GOptionEntry *optionEntries = getOptionEntriesFromWebKitWebSettings(webkitSettings);
- if (!optionEntries)
- return FALSE;
-
- GOptionGroup *webSettingsGroup = g_option_group_new("websettings",
- "WebKitWebSettings writable properties for default WebKitWebView",
- "WebKitWebSettings properties",
- webkitSettings,
- NULL);
- g_option_group_add_entries(webSettingsGroup, optionEntries);
- g_free(optionEntries);
-
- /* Option context takes ownership of the group. */
- g_option_context_add_group(context, webSettingsGroup);
-
- return TRUE;
-}
-
-int main(int argc, char* argv[])
-{
- WebKitWebSettings *webkitSettings = 0;
- const gchar **uriArguments = 0;
- const GOptionEntry commandLineOptions[] =
- {
- { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &uriArguments, 0, "[URL]" },
- { 0, 0, 0, 0, 0, 0, 0 }
- };
-
- gtk_init(&argc, &argv);
-
- GOptionContext *context = g_option_context_new(0);
- g_option_context_add_main_entries(context, commandLineOptions, 0);
- g_option_context_add_group(context, gtk_get_option_group(TRUE));
-#ifdef WTF_USE_GSTREAMER
- g_option_context_add_group(context, gst_init_get_option_group());
-#endif
- webkitSettings = webkit_web_settings_new();
- g_object_set(webkitSettings, "enable-developer-extras", TRUE, NULL);
- if (!addWebSettingsGroupToContext(context, webkitSettings)) {
- g_object_unref(webkitSettings);
- webkitSettings = 0;
- }
-
- GError *error = 0;
- if (!g_option_context_parse(context, &argc, &argv, &error)) {
- g_printerr("Cannot parse arguments: %s\n", error->message);
- g_error_free(error);
- g_option_context_free(context);
-
- return 1;
- }
- g_option_context_free(context);
-
-#ifdef SOUP_TYPE_PROXY_RESOLVER_DEFAULT
- soup_session_add_feature_by_type(webkit_get_default_session(), SOUP_TYPE_PROXY_RESOLVER_DEFAULT);
-#else
- const char *httpProxy = g_getenv("http_proxy");
- if (httpProxy) {
- SoupURI *proxyUri = soup_uri_new(httpProxy);
- g_object_set(webkit_get_default_session(), SOUP_SESSION_PROXY_URI, proxyUri, NULL);
- soup_uri_free(proxyUri);
- }
-#endif
-
- WebKitWebView *webView;
- GtkWidget *main_window = createWindow(&webView);
-
- if (webkitSettings) {
- webkit_web_view_set_settings(WEBKIT_WEB_VIEW(webView), webkitSettings);
- g_object_unref(webkitSettings);
- }
-
- const gchar *uri = (uriArguments ? uriArguments[0] : "http://www.google.com/");
- gchar *fileURL = filenameToURL(uri);
-
- webkit_web_view_load_uri(webView, fileURL ? fileURL : uri);
- g_free(fileURL);
-
- gtk_widget_grab_focus(GTK_WIDGET(webView));
- gtk_widget_show_all(main_window);
- gtk_main();
-
- return 0;
-}
diff --git a/Tools/ImageDiff/CMakeLists.txt b/Tools/ImageDiff/CMakeLists.txt
new file mode 100644
index 000000000..fdc584d42
--- /dev/null
+++ b/Tools/ImageDiff/CMakeLists.txt
@@ -0,0 +1,14 @@
+set(IMAGE_DIFF_DIR "${TOOLS_DIR}/ImageDiff")
+
+set(IMAGE_DIFF_SYSTEM_INCLUDE_DIRECTORIES "")
+
+set(IMAGE_DIFF_LIBRARIES
+ WTF
+)
+
+WEBKIT_INCLUDE_CONFIG_FILES_IF_EXISTS()
+
+include_directories(${IMAGE_DIFF_INCLUDE_DIRECTORIES})
+include_directories(SYSTEM ${IMAGE_DIFF_SYSTEM_INCLUDE_DIRECTORIES})
+add_executable(ImageDiff ${IMAGE_DIFF_SOURCES})
+target_link_libraries(ImageDiff ${IMAGE_DIFF_LIBRARIES})
diff --git a/Tools/ImageDiff/PlatformGTK.cmake b/Tools/ImageDiff/PlatformGTK.cmake
new file mode 100644
index 000000000..8b37ca08b
--- /dev/null
+++ b/Tools/ImageDiff/PlatformGTK.cmake
@@ -0,0 +1,11 @@
+set(IMAGE_DIFF_SOURCES
+ ${IMAGE_DIFF_DIR}/gtk/ImageDiff.cpp
+)
+
+list(APPEND IMAGE_DIFF_SYSTEM_INCLUDE_DIRECTORIES
+ ${GTK_INCLUDE_DIRS}
+)
+
+list(APPEND IMAGE_DIFF_LIBRARIES
+ ${GTK_LIBRARIES}
+)
diff --git a/Tools/ImageDiff/gtk/ImageDiff.cpp b/Tools/ImageDiff/gtk/ImageDiff.cpp
index 2cb9f3bce..5a128d1e3 100644
--- a/Tools/ImageDiff/gtk/ImageDiff.cpp
+++ b/Tools/ImageDiff/gtk/ImageDiff.cpp
@@ -11,7 +11,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -30,6 +30,7 @@
#include <algorithm>
#include <cmath>
#include <cstdio>
+#include <cstdlib>
#include <cstring>
#include <gdk/gdk.h>
@@ -63,23 +64,27 @@ GdkPixbuf* readPixbufFromStdin(long imageSize)
}
gdk_pixbuf_loader_close(loader, 0);
- GdkPixbuf* decodedImage = gdk_pixbuf_loader_get_pixbuf(loader);
- g_object_ref(decodedImage);
+ GdkPixbuf* decodedImage = GDK_PIXBUF(g_object_ref(gdk_pixbuf_loader_get_pixbuf(loader)));
+ g_object_unref(loader);
return decodedImage;
}
-GdkPixbuf* differenceImageFromDifferenceBuffer(unsigned char* buffer, int width, int height)
+GdkPixbuf* differenceImageFromDifferenceBuffer(unsigned char* buffer, int width, int height, float maxDistance)
{
GdkPixbuf* image = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, width, height);
if (!image)
return image;
+ bool shouldNormalize = maxDistance > 0 && maxDistance < 1;
int rowStride = gdk_pixbuf_get_rowstride(image);
unsigned char* diffPixels = gdk_pixbuf_get_pixels(image);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
unsigned char* diffPixel = diffPixels + (y * rowStride) + (x * 3);
- diffPixel[0] = diffPixel[1] = diffPixel[2] = *buffer++;
+ unsigned char bufferPixel = *buffer++;
+ if (shouldNormalize)
+ bufferPixel /= maxDistance;
+ diffPixel[0] = diffPixel[1] = diffPixel[2] = bufferPixel;
}
}
@@ -140,7 +145,7 @@ float calculateDifference(GdkPixbuf* baselineImage, GdkPixbuf* actualImage, GdkP
else {
difference = roundf(difference * 100.0f) / 100.0f;
difference = max(difference, 0.01f); // round to 2 decimal places
- *differenceImage = differenceImageFromDifferenceBuffer(diffBuffer, width, height);
+ *differenceImage = differenceImageFromDifferenceBuffer(diffBuffer, width, height, maxDistance);
}
free(diffBuffer);
diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.h b/Tools/MiniBrowser/MBToolbarItem.h
index d885801b9..9971d4c10 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.h
+++ b/Tools/MiniBrowser/MBToolbarItem.h
@@ -23,35 +23,5 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef JSWrapper_h
-#define JSWrapper_h
-
-#include "JSWrappable.h"
-#include <JavaScriptCore/JSRetainPtr.h>
-
-namespace WTR {
-
-// FIXME: If necessary, we can do wrapper caching here.
-class JSWrapper {
-public:
- static JSValueRef wrap(JSContextRef context, JSWrappable* object);
- static JSWrappable* unwrap(JSContextRef context, JSValueRef value);
-
- static void initialize(JSContextRef, JSObjectRef);
- static void finalize(JSObjectRef);
-};
-
-inline JSValueRef toJS(JSContextRef context, JSWrappable* impl)
-{
- return JSWrapper::wrap(context, impl);
-}
-
-inline void setProperty(JSContextRef context, JSObjectRef object, const char* propertyName, JSWrappable* value, JSPropertyAttributes attributes, JSValueRef* exception)
-{
- JSRetainPtr<JSStringRef> propertyNameString(Adopt, JSStringCreateWithUTF8CString(propertyName));
- JSObjectSetProperty(context, object, propertyNameString.get(), JSWrapper::wrap(context, value), attributes, exception);
-}
-
-} // namespace WTR
-
-#endif // JSWrapper_h
+@interface MBToolbarItem : NSToolbarItem
+@end
diff --git a/Tools/MiniBrowser/MiniBrowserWebProcessPlugIn.h b/Tools/MiniBrowser/MiniBrowserWebProcessPlugIn.h
new file mode 100644
index 000000000..ff16bf5dc
--- /dev/null
+++ b/Tools/MiniBrowser/MiniBrowserWebProcessPlugIn.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <WebKit/WKWebProcessPlugIn.h>
+
+#if WK_API_ENABLED
+
+@interface MiniBrowserWebProcessPlugIn : NSObject <WKWebProcessPlugIn>
+
+@end
+
+#endif // WK_API_ENABLED
diff --git a/Tools/MiniBrowser/gtk/BrowserDownloadsBar.c b/Tools/MiniBrowser/gtk/BrowserDownloadsBar.c
index 5f0e620e5..b0ec3ce14 100644
--- a/Tools/MiniBrowser/gtk/BrowserDownloadsBar.c
+++ b/Tools/MiniBrowser/gtk/BrowserDownloadsBar.c
@@ -23,6 +23,7 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "cmakeconfig.h"
#include "BrowserDownloadsBar.h"
#include <glib/gi18n.h>
diff --git a/Tools/MiniBrowser/gtk/BrowserSearchBar.c b/Tools/MiniBrowser/gtk/BrowserSearchBar.c
index 7585b564d..22930c4c5 100644
--- a/Tools/MiniBrowser/gtk/BrowserSearchBar.c
+++ b/Tools/MiniBrowser/gtk/BrowserSearchBar.c
@@ -23,9 +23,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "cmakeconfig.h"
#include "BrowserSearchBar.h"
-
static const char *searchEntryFailedStyle = "GtkEntry#searchEntry {background-color: #ff6666;}";
struct _BrowserSearchBar {
@@ -63,7 +63,7 @@ static void doSearch(BrowserSearchBar *searchBar)
if (!gtk_entry_get_icon_stock(entry, GTK_ENTRY_ICON_SECONDARY))
gtk_entry_set_icon_from_stock(entry, GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
- WebKitFindOptions options = WEBKIT_FIND_OPTIONS_NONE;
+ WebKitFindOptions options = WEBKIT_FIND_OPTIONS_WRAP_AROUND;
if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(searchBar->caseCheckButton)))
options |= WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE;
if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(searchBar->begginigWordCheckButton)))
@@ -274,9 +274,13 @@ void browser_search_bar_open(BrowserSearchBar *searchBar)
{
g_return_if_fail(BROWSER_IS_SEARCH_BAR(searchBar));
+ GtkEntry *entry = GTK_ENTRY(searchBar->entry);
+
gtk_widget_show(GTK_WIDGET(searchBar));
- gtk_widget_grab_focus(GTK_WIDGET(searchBar->entry));
- gtk_editable_select_region(GTK_EDITABLE(searchBar->entry), 0, -1);
+ gtk_widget_grab_focus(GTK_WIDGET(entry));
+ gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1);
+ if (gtk_entry_get_text_length(entry))
+ doSearch(searchBar);
}
void browser_search_bar_close(BrowserSearchBar *searchBar)
diff --git a/Tools/MiniBrowser/gtk/BrowserSettingsDialog.c b/Tools/MiniBrowser/gtk/BrowserSettingsDialog.c
index 1e4dcd804..511b3db04 100644
--- a/Tools/MiniBrowser/gtk/BrowserSettingsDialog.c
+++ b/Tools/MiniBrowser/gtk/BrowserSettingsDialog.c
@@ -55,6 +55,34 @@ struct _BrowserSettingsDialogClass {
G_DEFINE_TYPE(BrowserSettingsDialog, browser_settings_dialog, GTK_TYPE_DIALOG)
+static const char *hardwareAccelerationPolicyToString(WebKitHardwareAccelerationPolicy policy)
+{
+ switch (policy) {
+ case WEBKIT_HARDWARE_ACCELERATION_POLICY_ALWAYS:
+ return "always";
+ case WEBKIT_HARDWARE_ACCELERATION_POLICY_NEVER:
+ return "never";
+ case WEBKIT_HARDWARE_ACCELERATION_POLICY_ON_DEMAND:
+ return "ondemand";
+ }
+
+ g_assert_not_reached();
+ return "ondemand";
+}
+
+static int stringToHardwareAccelerationPolicy(const char *policy)
+{
+ if (!g_ascii_strcasecmp(policy, "always"))
+ return WEBKIT_HARDWARE_ACCELERATION_POLICY_ALWAYS;
+ if (!g_ascii_strcasecmp(policy, "never"))
+ return WEBKIT_HARDWARE_ACCELERATION_POLICY_NEVER;
+ if (!g_ascii_strcasecmp(policy, "ondemand"))
+ return WEBKIT_HARDWARE_ACCELERATION_POLICY_ON_DEMAND;
+
+ g_warning("Invalid value %s for hardware-acceleration-policy setting valid values are always, never and ondemand", policy);
+ return -1;
+}
+
static void cellRendererChanged(GtkCellRenderer *renderer, const char *path, const GValue *value, BrowserSettingsDialog *dialog)
{
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(dialog->settingsList));
@@ -62,12 +90,21 @@ static void cellRendererChanged(GtkCellRenderer *renderer, const char *path, con
GtkTreeIter iter;
gtk_tree_model_get_iter(model, &iter, treePath);
+ gboolean updateTreeStore = TRUE;
char *name;
gtk_tree_model_get(model, &iter, SETTINGS_LIST_COLUMN_NAME, &name, -1);
- g_object_set_property(G_OBJECT(dialog->settings), name, value);
+ if (!g_strcmp0(name, "hardware-acceleration-policy")) {
+ int policy = stringToHardwareAccelerationPolicy(g_value_get_string(value));
+ if (policy != -1)
+ webkit_settings_set_hardware_acceleration_policy(dialog->settings, policy);
+ else
+ updateTreeStore = FALSE;
+ } else
+ g_object_set_property(G_OBJECT(dialog->settings), name, value);
g_free(name);
- gtk_list_store_set(GTK_LIST_STORE(model), &iter, SETTINGS_LIST_COLUMN_VALUE, value, -1);
+ if (updateTreeStore)
+ gtk_list_store_set(GTK_LIST_STORE(model), &iter, SETTINGS_LIST_COLUMN_VALUE, value, -1);
gtk_tree_path_free(treePath);
}
@@ -134,10 +171,19 @@ static void browserSettingsDialogConstructed(GObject *object)
GParamSpec *property = properties[i];
const char *name = g_param_spec_get_name(property);
const char *nick = g_param_spec_get_nick(property);
+ char *blurb = g_markup_escape_text(g_param_spec_get_blurb(property), -1);
GValue value = { 0, { { 0 } } };
- g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(property));
- g_object_get_property(G_OBJECT(settings), name, &value);
+ if (!g_strcmp0(name, "hardware-acceleration-policy")) {
+ g_value_init(&value, G_TYPE_STRING);
+ g_value_set_string(&value, hardwareAccelerationPolicyToString(webkit_settings_get_hardware_acceleration_policy(settings)));
+ char *extendedBlutb = g_strdup_printf("%s (always, never or ondemand)", blurb);
+ g_free(blurb);
+ blurb = extendedBlutb;
+ } else {
+ g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(property));
+ g_object_get_property(G_OBJECT(settings), name, &value);
+ }
GtkAdjustment *adjustment = NULL;
if (G_PARAM_SPEC_VALUE_TYPE(property) == G_TYPE_UINT) {
@@ -146,7 +192,6 @@ static void browserSettingsDialogConstructed(GObject *object)
uIntProperty->maximum, 1, 1, 1);
}
- char *blurb = g_markup_escape_text(g_param_spec_get_blurb(property), -1);
GtkTreeIter iter;
gtk_list_store_append(model, &iter);
gtk_list_store_set(model, &iter,
diff --git a/Tools/MiniBrowser/gtk/BrowserTab.c b/Tools/MiniBrowser/gtk/BrowserTab.c
new file mode 100644
index 000000000..a6b2ea42e
--- /dev/null
+++ b/Tools/MiniBrowser/gtk/BrowserTab.c
@@ -0,0 +1,552 @@
+/*
+ * Copyright (C) 2016 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H && defined(BUILDING_WITH_CMAKE)
+#include "cmakeconfig.h"
+#endif
+#include "BrowserTab.h"
+
+#include "BrowserSearchBar.h"
+#include "BrowserWindow.h"
+#include <string.h>
+
+enum {
+ PROP_0,
+
+ PROP_VIEW
+};
+
+struct _BrowserTab {
+ GtkBox parent;
+
+ WebKitWebView *webView;
+ BrowserSearchBar *searchBar;
+ GtkWidget *statusLabel;
+ gboolean wasSearchingWhenEnteredFullscreen;
+ gboolean inspectorIsVisible;
+ GtkWidget *fullScreenMessageLabel;
+ guint fullScreenMessageLabelId;
+
+ /* Tab Title */
+ GtkWidget *titleBox;
+ GtkWidget *titleLabel;
+ GtkWidget *titleSpinner;
+ GtkWidget *titleCloseButton;
+};
+
+struct _BrowserTabClass {
+ GtkBoxClass parent;
+};
+
+G_DEFINE_TYPE(BrowserTab, browser_tab, GTK_TYPE_BOX)
+
+static void titleChanged(WebKitWebView *webView, GParamSpec *pspec, BrowserTab *tab)
+{
+ const char *title = webkit_web_view_get_title(webView);
+ if (title && *title)
+ gtk_label_set_text(GTK_LABEL(tab->titleLabel), title);
+}
+
+static void isLoadingChanged(WebKitWebView *webView, GParamSpec *paramSpec, BrowserTab *tab)
+{
+ if (webkit_web_view_is_loading(webView)) {
+ gtk_spinner_start(GTK_SPINNER(tab->titleSpinner));
+ gtk_widget_show(tab->titleSpinner);
+ } else {
+ gtk_spinner_stop(GTK_SPINNER(tab->titleSpinner));
+ gtk_widget_hide(tab->titleSpinner);
+ }
+}
+
+static gboolean decidePolicy(WebKitWebView *webView, WebKitPolicyDecision *decision, WebKitPolicyDecisionType decisionType, BrowserTab *tab)
+{
+ if (decisionType != WEBKIT_POLICY_DECISION_TYPE_RESPONSE)
+ return FALSE;
+
+ WebKitResponsePolicyDecision *responseDecision = WEBKIT_RESPONSE_POLICY_DECISION(decision);
+ if (webkit_response_policy_decision_is_mime_type_supported(responseDecision))
+ return FALSE;
+
+ WebKitWebResource *mainResource = webkit_web_view_get_main_resource(webView);
+ WebKitURIRequest *request = webkit_response_policy_decision_get_request(responseDecision);
+ const char *requestURI = webkit_uri_request_get_uri(request);
+ if (g_strcmp0(webkit_web_resource_get_uri(mainResource), requestURI))
+ return FALSE;
+
+ webkit_policy_decision_download(decision);
+ return TRUE;
+}
+
+static void removeChildIfInfoBar(GtkWidget *child, GtkContainer *tab)
+{
+ if (GTK_IS_INFO_BAR(child))
+ gtk_container_remove(tab, child);
+}
+
+static void loadChanged(WebKitWebView *webView, WebKitLoadEvent loadEvent, BrowserTab *tab)
+{
+ if (loadEvent != WEBKIT_LOAD_STARTED)
+ return;
+
+ gtk_container_foreach(GTK_CONTAINER(tab), (GtkCallback)removeChildIfInfoBar, tab);
+}
+
+static GtkWidget *createInfoBarQuestionMessage(const char *title, const char *text)
+{
+ GtkWidget *dialog = gtk_info_bar_new_with_buttons("No", GTK_RESPONSE_NO, "Yes", GTK_RESPONSE_YES, NULL);
+ gtk_info_bar_set_message_type(GTK_INFO_BAR(dialog), GTK_MESSAGE_QUESTION);
+
+ GtkWidget *contentBox = gtk_info_bar_get_content_area(GTK_INFO_BAR(dialog));
+ gtk_orientable_set_orientation(GTK_ORIENTABLE(contentBox), GTK_ORIENTATION_VERTICAL);
+ gtk_box_set_spacing(GTK_BOX(contentBox), 0);
+
+ GtkWidget *label = gtk_label_new(NULL);
+ gchar *markup = g_strdup_printf("<span size='xx-large' weight='bold'>%s</span>", title);
+ gtk_label_set_markup(GTK_LABEL(label), markup);
+ g_free(markup);
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+ gtk_label_set_selectable(GTK_LABEL(label), TRUE);
+ gtk_misc_set_alignment(GTK_MISC(label), 0., 0.5);
+ gtk_box_pack_start(GTK_BOX(contentBox), label, FALSE, FALSE, 2);
+ gtk_widget_show(label);
+
+ label = gtk_label_new(text);
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+ gtk_label_set_selectable(GTK_LABEL(label), TRUE);
+ gtk_misc_set_alignment(GTK_MISC(label), 0., 0.5);
+ gtk_box_pack_start(GTK_BOX(contentBox), label, FALSE, FALSE, 0);
+ gtk_widget_show(label);
+
+ return dialog;
+}
+
+static void tlsErrorsDialogResponse(GtkWidget *dialog, gint response, BrowserTab *tab)
+{
+ if (response == GTK_RESPONSE_YES) {
+ const char *failingURI = (const char *)g_object_get_data(G_OBJECT(dialog), "failingURI");
+ GTlsCertificate *certificate = (GTlsCertificate *)g_object_get_data(G_OBJECT(dialog), "certificate");
+ SoupURI *uri = soup_uri_new(failingURI);
+ webkit_web_context_allow_tls_certificate_for_host(webkit_web_view_get_context(tab->webView), certificate, uri->host);
+ soup_uri_free(uri);
+ webkit_web_view_load_uri(tab->webView, failingURI);
+ }
+ gtk_widget_destroy(dialog);
+}
+
+static gboolean loadFailedWithTLSerrors(WebKitWebView *webView, const char *failingURI, GTlsCertificate *certificate, GTlsCertificateFlags errors, BrowserTab *tab)
+{
+ gchar *text = g_strdup_printf("Failed to load %s: Do you want to continue ignoring the TLS errors?", failingURI);
+ GtkWidget *dialog = createInfoBarQuestionMessage("Invalid TLS Certificate", text);
+ g_free(text);
+ g_object_set_data_full(G_OBJECT(dialog), "failingURI", g_strdup(failingURI), g_free);
+ g_object_set_data_full(G_OBJECT(dialog), "certificate", g_object_ref(certificate), g_object_unref);
+
+ g_signal_connect(dialog, "response", G_CALLBACK(tlsErrorsDialogResponse), tab);
+
+ gtk_box_pack_start(GTK_BOX(tab), dialog, FALSE, FALSE, 0);
+ gtk_box_reorder_child(GTK_BOX(tab), dialog, 0);
+ gtk_widget_show(dialog);
+
+ return TRUE;
+}
+
+static void permissionRequestDialogResponse(GtkWidget *dialog, gint response, WebKitPermissionRequest *request)
+{
+ switch (response) {
+ case GTK_RESPONSE_YES:
+ webkit_permission_request_allow(request);
+ break;
+ default:
+ webkit_permission_request_deny(request);
+ break;
+ }
+
+ gtk_widget_destroy(dialog);
+ g_object_unref(request);
+}
+
+static gboolean decidePermissionRequest(WebKitWebView *webView, WebKitPermissionRequest *request, BrowserTab *tab)
+{
+ const gchar *title = NULL;
+ gchar *text = NULL;
+
+ if (WEBKIT_IS_GEOLOCATION_PERMISSION_REQUEST(request)) {
+ title = "Geolocation request";
+ text = g_strdup("Allow geolocation request?");
+ } else if (WEBKIT_IS_NOTIFICATION_PERMISSION_REQUEST(request)) {
+ title = "Notification request";
+ text = g_strdup("Allow notifications request?");
+ } else if (WEBKIT_IS_USER_MEDIA_PERMISSION_REQUEST(request)) {
+ title = "UserMedia request";
+ gboolean is_for_audio_device = webkit_user_media_permission_is_for_audio_device(WEBKIT_USER_MEDIA_PERMISSION_REQUEST(request));
+ gboolean is_for_video_device = webkit_user_media_permission_is_for_video_device(WEBKIT_USER_MEDIA_PERMISSION_REQUEST(request));
+ const char *mediaType = NULL;
+ if (is_for_audio_device) {
+ if (is_for_video_device)
+ mediaType = "audio/video";
+ else
+ mediaType = "audio";
+ } else if (is_for_video_device)
+ mediaType = "video";
+ text = g_strdup_printf("Allow access to %s device?", mediaType);
+ } else if (WEBKIT_IS_INSTALL_MISSING_MEDIA_PLUGINS_PERMISSION_REQUEST(request)) {
+ title = "Media plugin missing request";
+ text = g_strdup_printf("The media backend was unable to find a plugin to play the requested media:\n%s.\nAllow to search and install the missing plugin?",
+ webkit_install_missing_media_plugins_permission_request_get_description(WEBKIT_INSTALL_MISSING_MEDIA_PLUGINS_PERMISSION_REQUEST(request)));
+ } else
+ return FALSE;
+
+ GtkWidget *dialog = createInfoBarQuestionMessage(title, text);
+ g_free(text);
+ g_signal_connect(dialog, "response", G_CALLBACK(permissionRequestDialogResponse), g_object_ref(request));
+
+ gtk_box_pack_start(GTK_BOX(tab), dialog, FALSE, FALSE, 0);
+ gtk_box_reorder_child(GTK_BOX(tab), dialog, 0);
+ gtk_widget_show(dialog);
+
+ return TRUE;
+}
+
+#if GTK_CHECK_VERSION(3, 12, 0)
+static void colorChooserRGBAChanged(GtkColorChooser *colorChooser, GParamSpec *paramSpec, WebKitColorChooserRequest *request)
+{
+ GdkRGBA rgba;
+ gtk_color_chooser_get_rgba(colorChooser, &rgba);
+ webkit_color_chooser_request_set_rgba(request, &rgba);
+}
+
+static void popoverColorClosed(GtkWidget *popover, WebKitColorChooserRequest *request)
+{
+ webkit_color_chooser_request_finish(request);
+}
+
+static void colorChooserRequestFinished(WebKitColorChooserRequest *request, GtkWidget *popover)
+{
+ g_object_unref(request);
+ gtk_widget_destroy(popover);
+}
+
+static gboolean runColorChooserCallback(WebKitWebView *webView, WebKitColorChooserRequest *request, BrowserTab *tab)
+{
+ GtkWidget *popover = gtk_popover_new(GTK_WIDGET(webView));
+
+ GdkRectangle rectangle;
+ webkit_color_chooser_request_get_element_rectangle(request, &rectangle);
+ gtk_popover_set_pointing_to(GTK_POPOVER(popover), &rectangle);
+
+ GtkWidget *colorChooser = gtk_color_chooser_widget_new();
+ GdkRGBA rgba;
+ webkit_color_chooser_request_get_rgba(request, &rgba);
+ gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(colorChooser), &rgba);
+ g_signal_connect(colorChooser, "notify::rgba", G_CALLBACK(colorChooserRGBAChanged), request);
+ gtk_container_add(GTK_CONTAINER(popover), colorChooser);
+ gtk_widget_show(colorChooser);
+
+ g_object_ref(request);
+ g_signal_connect_object(popover, "hide", G_CALLBACK(popoverColorClosed), request, 0);
+ g_signal_connect_object(request, "finished", G_CALLBACK(colorChooserRequestFinished), popover, 0);
+
+ gtk_widget_show(popover);
+
+ return TRUE;
+}
+#endif /* GTK_CHECK_VERSION(3, 12, 0) */
+
+static gboolean inspectorOpenedInWindow(WebKitWebInspector *inspector, BrowserTab *tab)
+{
+ tab->inspectorIsVisible = TRUE;
+ return FALSE;
+}
+
+static gboolean inspectorClosed(WebKitWebInspector *inspector, BrowserTab *tab)
+{
+ tab->inspectorIsVisible = FALSE;
+ return FALSE;
+}
+
+static void browserTabSetProperty(GObject *object, guint propId, const GValue *value, GParamSpec *pspec)
+{
+ BrowserTab *tab = BROWSER_TAB(object);
+
+ switch (propId) {
+ case PROP_VIEW:
+ tab->webView = g_value_get_object(value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
+ }
+}
+
+static void browserTabFinalize(GObject *gObject)
+{
+ BrowserTab *tab = BROWSER_TAB(gObject);
+
+ if (tab->fullScreenMessageLabelId)
+ g_source_remove(tab->fullScreenMessageLabelId);
+
+ G_OBJECT_CLASS(browser_tab_parent_class)->finalize(gObject);
+}
+
+static void browser_tab_init(BrowserTab *tab)
+{
+ gtk_orientable_set_orientation(GTK_ORIENTABLE(tab), GTK_ORIENTATION_VERTICAL);
+}
+
+static void browserTabConstructed(GObject *gObject)
+{
+ BrowserTab *tab = BROWSER_TAB(gObject);
+
+ G_OBJECT_CLASS(browser_tab_parent_class)->constructed(gObject);
+
+ tab->searchBar = BROWSER_SEARCH_BAR(browser_search_bar_new(tab->webView));
+ gtk_box_pack_start(GTK_BOX(tab), GTK_WIDGET(tab->searchBar), FALSE, FALSE, 0);
+
+ GtkWidget *overlay = gtk_overlay_new();
+ gtk_box_pack_start(GTK_BOX(tab), overlay, TRUE, TRUE, 0);
+ gtk_widget_show(overlay);
+
+ tab->statusLabel = gtk_label_new(NULL);
+ gtk_widget_set_halign(tab->statusLabel, GTK_ALIGN_START);
+ gtk_widget_set_valign(tab->statusLabel, GTK_ALIGN_END);
+ gtk_widget_set_margin_left(tab->statusLabel, 1);
+ gtk_widget_set_margin_right(tab->statusLabel, 1);
+ gtk_widget_set_margin_top(tab->statusLabel, 1);
+ gtk_widget_set_margin_bottom(tab->statusLabel, 1);
+ gtk_overlay_add_overlay(GTK_OVERLAY(overlay), tab->statusLabel);
+
+ tab->fullScreenMessageLabel = gtk_label_new(NULL);
+ gtk_widget_set_halign(tab->fullScreenMessageLabel, GTK_ALIGN_CENTER);
+ gtk_widget_set_valign(tab->fullScreenMessageLabel, GTK_ALIGN_CENTER);
+ gtk_widget_set_no_show_all(tab->fullScreenMessageLabel, TRUE);
+ gtk_overlay_add_overlay(GTK_OVERLAY(overlay), tab->fullScreenMessageLabel);
+
+ gtk_container_add(GTK_CONTAINER(overlay), GTK_WIDGET(tab->webView));
+ gtk_widget_show(GTK_WIDGET(tab->webView));
+
+ tab->titleBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
+
+ GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_widget_set_halign(hbox, GTK_ALIGN_CENTER);
+
+ tab->titleSpinner = gtk_spinner_new();
+ gtk_box_pack_start(GTK_BOX(hbox), tab->titleSpinner, FALSE, FALSE, 0);
+
+ tab->titleLabel = gtk_label_new(NULL);
+ gtk_label_set_ellipsize(GTK_LABEL(tab->titleLabel), PANGO_ELLIPSIZE_END);
+ gtk_label_set_single_line_mode(GTK_LABEL(tab->titleLabel), TRUE);
+ gtk_misc_set_padding(GTK_MISC(tab->titleLabel), 0, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), tab->titleLabel, FALSE, FALSE, 0);
+ gtk_widget_show(tab->titleLabel);
+
+ gtk_box_pack_start(GTK_BOX(tab->titleBox), hbox, TRUE, TRUE, 0);
+ gtk_widget_show(hbox);
+
+ tab->titleCloseButton = gtk_button_new();
+ g_signal_connect_swapped(tab->titleCloseButton, "clicked", G_CALLBACK(gtk_widget_destroy), tab);
+ gtk_button_set_relief(GTK_BUTTON(tab->titleCloseButton), GTK_RELIEF_NONE);
+ gtk_button_set_focus_on_click(GTK_BUTTON(tab->titleCloseButton), FALSE);
+
+ GtkWidget *image = gtk_image_new_from_icon_name("window-close-symbolic", GTK_ICON_SIZE_MENU);
+ gtk_container_add(GTK_CONTAINER(tab->titleCloseButton), image);
+ gtk_widget_show(image);
+
+ gtk_box_pack_start(GTK_BOX(tab->titleBox), tab->titleCloseButton, FALSE, FALSE, 0);
+ gtk_widget_show(tab->titleCloseButton);
+
+ g_signal_connect(tab->webView, "notify::title", G_CALLBACK(titleChanged), tab);
+ g_signal_connect(tab->webView, "notify::is-loading", G_CALLBACK(isLoadingChanged), tab);
+ g_signal_connect(tab->webView, "decide-policy", G_CALLBACK(decidePolicy), tab);
+ g_signal_connect(tab->webView, "load-changed", G_CALLBACK(loadChanged), tab);
+ g_signal_connect(tab->webView, "load-failed-with-tls-errors", G_CALLBACK(loadFailedWithTLSerrors), tab);
+ g_signal_connect(tab->webView, "permission-request", G_CALLBACK(decidePermissionRequest), tab);
+#if GTK_CHECK_VERSION(3, 12, 0)
+ g_signal_connect(tab->webView, "run-color-chooser", G_CALLBACK(runColorChooserCallback), tab);
+#endif
+
+ WebKitWebInspector *inspector = webkit_web_view_get_inspector(tab->webView);
+ g_signal_connect(inspector, "open-window", G_CALLBACK(inspectorOpenedInWindow), tab);
+ g_signal_connect(inspector, "closed", G_CALLBACK(inspectorClosed), tab);
+
+ if (webkit_web_view_is_editable(tab->webView))
+ webkit_web_view_load_html(tab->webView, "<html></html>", "file:///");
+}
+
+static void browser_tab_class_init(BrowserTabClass *klass)
+{
+ GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
+ gobjectClass->constructed = browserTabConstructed;
+ gobjectClass->set_property = browserTabSetProperty;
+ gobjectClass->finalize = browserTabFinalize;
+
+ g_object_class_install_property(
+ gobjectClass,
+ PROP_VIEW,
+ g_param_spec_object(
+ "view",
+ "View",
+ "The web view of this tab",
+ WEBKIT_TYPE_WEB_VIEW,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static char *getInternalURI(const char *uri)
+{
+ /* Internally we use minibrowser-about: as about: prefix is ignored by WebKit. */
+ if (g_str_has_prefix(uri, "about:") && !g_str_equal(uri, "about:blank"))
+ return g_strconcat(BROWSER_ABOUT_SCHEME, uri + strlen ("about"), NULL);
+
+ return g_strdup(uri);
+}
+
+/* Public API. */
+GtkWidget *browser_tab_new(WebKitWebView *view)
+{
+ g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(view), NULL);
+
+ return GTK_WIDGET(g_object_new(BROWSER_TYPE_TAB, "view", view, NULL));
+}
+
+WebKitWebView *browser_tab_get_web_view(BrowserTab *tab)
+{
+ g_return_val_if_fail(BROWSER_IS_TAB(tab), NULL);
+
+ return tab->webView;
+}
+
+void browser_tab_load_uri(BrowserTab *tab, const char *uri)
+{
+ g_return_if_fail(BROWSER_IS_TAB(tab));
+ g_return_if_fail(uri);
+
+ if (!g_str_has_prefix(uri, "javascript:")) {
+ char *internalURI = getInternalURI(uri);
+ webkit_web_view_load_uri(tab->webView, internalURI);
+ g_free(internalURI);
+ return;
+ }
+
+ webkit_web_view_run_javascript(tab->webView, strstr(uri, "javascript:"), NULL, NULL, NULL);
+}
+
+GtkWidget *browser_tab_get_title_widget(BrowserTab *tab)
+{
+ g_return_val_if_fail(BROWSER_IS_TAB(tab), NULL);
+
+ return tab->titleBox;
+}
+
+void browser_tab_set_status_text(BrowserTab *tab, const char *text)
+{
+ g_return_if_fail(BROWSER_IS_TAB(tab));
+
+ gtk_label_set_text(GTK_LABEL(tab->statusLabel), text);
+ gtk_widget_set_visible(tab->statusLabel, !!text);
+}
+
+void browser_tab_toggle_inspector(BrowserTab *tab)
+{
+ g_return_if_fail(BROWSER_IS_TAB(tab));
+
+ WebKitWebInspector *inspector = webkit_web_view_get_inspector(tab->webView);
+ if (!tab->inspectorIsVisible) {
+ webkit_web_inspector_show(inspector);
+ tab->inspectorIsVisible = TRUE;
+ } else
+ webkit_web_inspector_close(inspector);
+}
+
+void browser_tab_start_search(BrowserTab *tab)
+{
+ g_return_if_fail(BROWSER_IS_TAB(tab));
+
+ if (!gtk_widget_get_visible(GTK_WIDGET(tab->searchBar)))
+ browser_search_bar_open(tab->searchBar);
+}
+
+void browser_tab_stop_search(BrowserTab *tab)
+{
+ g_return_if_fail(BROWSER_IS_TAB(tab));
+
+ if (gtk_widget_get_visible(GTK_WIDGET(tab->searchBar)))
+ browser_search_bar_close(tab->searchBar);
+}
+
+void browser_tab_add_accelerators(BrowserTab *tab, GtkAccelGroup *accelGroup)
+{
+ g_return_if_fail(BROWSER_IS_TAB(tab));
+ g_return_if_fail(GTK_IS_ACCEL_GROUP(accelGroup));
+
+ browser_search_bar_add_accelerators(tab->searchBar, accelGroup);
+}
+
+static gboolean fullScreenMessageTimeoutCallback(BrowserTab *tab)
+{
+ gtk_widget_hide(tab->fullScreenMessageLabel);
+ tab->fullScreenMessageLabelId = 0;
+ return FALSE;
+}
+
+void browser_tab_enter_fullscreen(BrowserTab *tab)
+{
+ g_return_if_fail(BROWSER_IS_TAB(tab));
+
+ const gchar *titleOrURI = webkit_web_view_get_title(tab->webView);
+ if (!titleOrURI || !titleOrURI[0])
+ titleOrURI = webkit_web_view_get_uri(tab->webView);
+
+ gchar *message = g_strdup_printf("%s is now full screen. Press ESC or f to exit.", titleOrURI);
+ gtk_label_set_text(GTK_LABEL(tab->fullScreenMessageLabel), message);
+ g_free(message);
+
+ gtk_widget_show(tab->fullScreenMessageLabel);
+
+ tab->fullScreenMessageLabelId = g_timeout_add_seconds(2, (GSourceFunc)fullScreenMessageTimeoutCallback, tab);
+ g_source_set_name_by_id(tab->fullScreenMessageLabelId, "[WebKit] fullScreenMessageTimeoutCallback");
+
+ tab->wasSearchingWhenEnteredFullscreen = gtk_widget_get_visible(GTK_WIDGET(tab->searchBar));
+ browser_tab_stop_search(tab);
+}
+
+void browser_tab_leave_fullscreen(BrowserTab *tab)
+{
+ g_return_if_fail(BROWSER_IS_TAB(tab));
+
+ if (tab->fullScreenMessageLabelId) {
+ g_source_remove(tab->fullScreenMessageLabelId);
+ tab->fullScreenMessageLabelId = 0;
+ }
+
+ gtk_widget_hide(tab->fullScreenMessageLabel);
+
+ if (tab->wasSearchingWhenEnteredFullscreen) {
+ /* Opening the search bar steals the focus. Usually, we want
+ * this but not when coming back from fullscreen.
+ */
+ GtkWindow *window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(tab)));
+ GtkWidget *focusWidget = gtk_window_get_focus(window);
+ browser_tab_start_search(tab);
+ gtk_window_set_focus(window, focusWidget);
+ }
+}
diff --git a/Tools/MiniBrowser/gtk/BrowserTab.h b/Tools/MiniBrowser/gtk/BrowserTab.h
new file mode 100644
index 000000000..9d5727591
--- /dev/null
+++ b/Tools/MiniBrowser/gtk/BrowserTab.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BrowserTab_h
+#define BrowserTab_h
+
+#include <gtk/gtk.h>
+#include <webkit2/webkit2.h>
+
+G_BEGIN_DECLS
+
+#define BROWSER_TYPE_TAB (browser_tab_get_type())
+#define BROWSER_TAB(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), BROWSER_TYPE_TAB, BrowserTab))
+#define BROWSER_TAB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), BROWSER_TYPE_TAB, BrowserTabClass))
+#define BROWSER_IS_TAB(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), BROWSER_TYPE_TAB))
+#define BROWSER_IS_TAB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), BROWSER_TYPE_TAB))
+#define BROWSER_TAB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), BROWSER_TYPE_TAB, BrowserTabClass))
+
+typedef struct _BrowserTab BrowserTab;
+typedef struct _BrowserTabClass BrowserTabClass;
+
+GType browser_tab_get_type(void);
+
+GtkWidget* browser_tab_new(WebKitWebView*);
+WebKitWebView* browser_tab_get_web_view(BrowserTab*);
+void browser_tab_load_uri(BrowserTab*, const char* uri);
+GtkWidget *browser_tab_get_title_widget(BrowserTab*);
+void browser_tab_set_status_text(BrowserTab*, const char* text);
+void browser_tab_toggle_inspector(BrowserTab*);
+void browser_tab_start_search(BrowserTab*);
+void browser_tab_stop_search(BrowserTab*);
+void browser_tab_add_accelerators(BrowserTab*, GtkAccelGroup*);
+void browser_tab_enter_fullscreen(BrowserTab*);
+void browser_tab_leave_fullscreen(BrowserTab*);
+
+G_END_DECLS
+
+#endif
diff --git a/Tools/MiniBrowser/gtk/BrowserWindow.c b/Tools/MiniBrowser/gtk/BrowserWindow.c
index b8a0d056c..b80157fa2 100644
--- a/Tools/MiniBrowser/gtk/BrowserWindow.c
+++ b/Tools/MiniBrowser/gtk/BrowserWindow.c
@@ -25,23 +25,23 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
+#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H && defined(BUILDING_WITH_CMAKE)
+#include "cmakeconfig.h"
+#endif
#include "BrowserWindow.h"
#include "BrowserDownloadsBar.h"
#include "BrowserSearchBar.h"
#include "BrowserSettingsDialog.h"
+#include "BrowserTab.h"
#include <gdk/gdkkeysyms.h>
#include <string.h>
-enum {
- PROP_0,
-
- PROP_VIEW
-};
-
struct _BrowserWindow {
GtkWindow parent;
+ WebKitWebContext *webContext;
+
GtkAccelGroup *accelGroup;
GtkWidget *mainBox;
GtkWidget *toolbar;
@@ -50,18 +50,21 @@ struct _BrowserWindow {
GtkWidget *forwardItem;
GtkWidget *zoomInItem;
GtkWidget *zoomOutItem;
- GtkWidget *statusLabel;
+ GtkWidget *boldItem;
+ GtkWidget *italicItem;
+ GtkWidget *underlineItem;
+ GtkWidget *strikethroughItem;
GtkWidget *settingsDialog;
- WebKitWebView *webView;
+ GtkWidget *notebook;
+ BrowserTab *activeTab;
GtkWidget *downloadsBar;
- BrowserSearchBar *searchBar;
gboolean searchBarVisible;
+ gboolean fullScreenIsEnabled;
GdkPixbuf *favicon;
GtkWidget *reloadOrStopButton;
- GtkWidget *fullScreenMessageLabel;
GtkWindow *parentWindow;
- guint fullScreenMessageLabelId;
guint resetEntryProgressTimeoutId;
+ gchar *sessionFile;
};
struct _BrowserWindowClass {
@@ -69,36 +72,26 @@ struct _BrowserWindowClass {
};
static const char *defaultWindowTitle = "WebKitGTK+ MiniBrowser";
-static const char *miniBrowserAboutScheme = "minibrowser-about";
static const gdouble minimumZoomLevel = 0.5;
static const gdouble maximumZoomLevel = 3;
+static const gdouble defaultZoomLevel = 1;
static const gdouble zoomStep = 1.2;
static gint windowCount = 0;
G_DEFINE_TYPE(BrowserWindow, browser_window, GTK_TYPE_WINDOW)
-static char *getInternalURI(const char *uri)
-{
- // Internally we use minibrowser-about: as about: prefix is ignored by WebKit.
- if (g_str_has_prefix(uri, "about:") && !g_str_equal(uri, "about:blank"))
- return g_strconcat(miniBrowserAboutScheme, uri + strlen ("about"), NULL);
-
- return g_strdup(uri);
-}
-
static char *getExternalURI(const char *uri)
{
- // From the user point of view we support about: prefix.
- if (g_str_has_prefix(uri, miniBrowserAboutScheme))
- return g_strconcat("about", uri + strlen(miniBrowserAboutScheme), NULL);
+ /* From the user point of view we support about: prefix. */
+ if (uri && g_str_has_prefix(uri, BROWSER_ABOUT_SCHEME))
+ return g_strconcat("about", uri + strlen(BROWSER_ABOUT_SCHEME), NULL);
return g_strdup(uri);
}
static void browserWindowSetStatusText(BrowserWindow *window, const char *text)
{
- gtk_label_set_text(GTK_LABEL(window->statusLabel), text);
- gtk_widget_set_visible(window->statusLabel, !!text);
+ browser_tab_set_status_text(window->activeTab, text);
}
static void resetStatusText(GtkWidget *widget, BrowserWindow *window)
@@ -113,20 +106,23 @@ static void activateUriEntryCallback(BrowserWindow *window)
static void reloadOrStopCallback(BrowserWindow *window)
{
- if (webkit_web_view_is_loading(window->webView))
- webkit_web_view_stop_loading(window->webView);
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ if (webkit_web_view_is_loading(webView))
+ webkit_web_view_stop_loading(webView);
else
- webkit_web_view_reload(window->webView);
+ webkit_web_view_reload(webView);
}
static void goBackCallback(BrowserWindow *window)
{
- webkit_web_view_go_back(window->webView);
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ webkit_web_view_go_back(webView);
}
static void goForwardCallback(BrowserWindow *window)
{
- webkit_web_view_go_forward(window->webView);
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ webkit_web_view_go_forward(webView);
}
static void settingsCallback(BrowserWindow *window)
@@ -136,7 +132,8 @@ static void settingsCallback(BrowserWindow *window)
return;
}
- window->settingsDialog = browser_settings_dialog_new(webkit_web_view_get_settings(window->webView));
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ window->settingsDialog = browser_settings_dialog_new(webkit_web_view_get_settings(webView));
gtk_window_set_transient_for(GTK_WINDOW(window->settingsDialog), GTK_WINDOW(window));
g_object_add_weak_pointer(G_OBJECT(window->settingsDialog), (gpointer *)&window->settingsDialog);
gtk_widget_show(window->settingsDialog);
@@ -145,14 +142,23 @@ static void settingsCallback(BrowserWindow *window)
static void webViewURIChanged(WebKitWebView *webView, GParamSpec *pspec, BrowserWindow *window)
{
char *externalURI = getExternalURI(webkit_web_view_get_uri(webView));
- gtk_entry_set_text(GTK_ENTRY(window->uriEntry), externalURI);
- g_free(externalURI);
+ if (externalURI) {
+ gtk_entry_set_text(GTK_ENTRY(window->uriEntry), externalURI);
+ g_free(externalURI);
+ } else
+ gtk_entry_set_text(GTK_ENTRY(window->uriEntry), "");
}
static void webViewTitleChanged(WebKitWebView *webView, GParamSpec *pspec, BrowserWindow *window)
{
const char *title = webkit_web_view_get_title(webView);
- gtk_window_set_title(GTK_WINDOW(window), title ? title : defaultWindowTitle);
+ if (!title)
+ title = defaultWindowTitle;
+ char *privateTitle = NULL;
+ if (webkit_web_view_is_ephemeral(webView))
+ privateTitle = g_strdup_printf("[Private] %s", title);
+ gtk_window_set_title(GTK_WINDOW(window), privateTitle ? privateTitle : title);
+ g_free(privateTitle);
}
static gboolean resetEntryProgress(BrowserWindow *window)
@@ -196,7 +202,8 @@ static void browserWindowHistoryItemActivated(BrowserWindow *window, GtkAction *
if (!item)
return;
- webkit_web_view_go_to_back_forward_list_item(window->webView, item);
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ webkit_web_view_go_to_back_forward_list_item(webView, item);
}
static GtkWidget *browserWindowCreateBackForwardMenu(BrowserWindow *window, GList *list)
@@ -230,8 +237,9 @@ static GtkWidget *browserWindowCreateBackForwardMenu(BrowserWindow *window, GLis
static void browserWindowUpdateNavigationActions(BrowserWindow *window, WebKitBackForwardList *backForwadlist)
{
- gtk_widget_set_sensitive(window->backItem, webkit_web_view_can_go_back(window->webView));
- gtk_widget_set_sensitive(window->forwardItem, webkit_web_view_can_go_forward(window->webView));
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ gtk_widget_set_sensitive(window->backItem, webkit_web_view_can_go_back(webView));
+ gtk_widget_set_sensitive(window->forwardItem, webkit_web_view_can_go_forward(webView));
GList *list = g_list_reverse(webkit_back_forward_list_get_back_list_with_limit(backForwadlist, 10));
gtk_menu_tool_button_set_menu(GTK_MENU_TOOL_BUTTON(window->backItem),
@@ -249,24 +257,22 @@ static void backForwadlistChanged(WebKitBackForwardList *backForwadlist, WebKitB
browserWindowUpdateNavigationActions(window, backForwadlist);
}
-static void geolocationRequestDialogCallback(GtkDialog *dialog, gint response, WebKitPermissionRequest *request)
+static void webViewClose(WebKitWebView *webView, BrowserWindow *window)
{
- switch (response) {
- case GTK_RESPONSE_YES:
- webkit_permission_request_allow(request);
- break;
- default:
- webkit_permission_request_deny(request);
- break;
+ int tabsCount = gtk_notebook_get_n_pages(GTK_NOTEBOOK(window->notebook));
+ if (tabsCount == 1) {
+ gtk_widget_destroy(GTK_WIDGET(window));
+ return;
}
- gtk_widget_destroy(GTK_WIDGET(dialog));
- g_object_unref(request);
-}
-
-static void webViewClose(WebKitWebView *webView, BrowserWindow *window)
-{
- gtk_widget_destroy(GTK_WIDGET(window));
+ int i;
+ for (i = 0; i < tabsCount; ++i) {
+ BrowserTab *tab = (BrowserTab *)gtk_notebook_get_nth_page(GTK_NOTEBOOK(window->notebook), i);
+ if (browser_tab_get_web_view(tab) == webView) {
+ gtk_widget_destroy(GTK_WIDGET(tab));
+ return;
+ }
+ }
}
static void webViewRunAsModal(WebKitWebView *webView, BrowserWindow *window)
@@ -297,65 +303,33 @@ static void webViewReadyToShow(WebKitWebView *webView, BrowserWindow *window)
gtk_widget_show(GTK_WIDGET(window));
}
-static gboolean fullScreenMessageTimeoutCallback(BrowserWindow *window)
+static GtkWidget *webViewCreate(WebKitWebView *webView, WebKitNavigationAction *navigation, BrowserWindow *window)
{
- gtk_widget_hide(window->fullScreenMessageLabel);
- window->fullScreenMessageLabelId = 0;
- return FALSE;
+ WebKitWebView *newWebView = WEBKIT_WEB_VIEW(webkit_web_view_new_with_related_view(webView));
+ webkit_web_view_set_settings(newWebView, webkit_web_view_get_settings(webView));
+
+ GtkWidget *newWindow = browser_window_new(GTK_WINDOW(window), window->webContext);
+ browser_window_append_view(BROWSER_WINDOW(newWindow), newWebView);
+ g_signal_connect(newWebView, "ready-to-show", G_CALLBACK(webViewReadyToShow), newWindow);
+ g_signal_connect(newWebView, "run-as-modal", G_CALLBACK(webViewRunAsModal), newWindow);
+ g_signal_connect(newWebView, "close", G_CALLBACK(webViewClose), newWindow);
+ return GTK_WIDGET(newWebView);
}
static gboolean webViewEnterFullScreen(WebKitWebView *webView, BrowserWindow *window)
{
- gchar *titleOrURI = g_strdup(webkit_web_view_get_title(window->webView));
- if (!titleOrURI)
- titleOrURI = getExternalURI(webkit_web_view_get_uri(window->webView));
- gchar *message = g_strdup_printf("%s is now full screen. Press ESC or f to exit.", titleOrURI);
- gtk_label_set_text(GTK_LABEL(window->fullScreenMessageLabel), message);
- g_free(titleOrURI);
- g_free(message);
-
- gtk_widget_show(window->fullScreenMessageLabel);
-
- window->fullScreenMessageLabelId = g_timeout_add_seconds(2, (GSourceFunc)fullScreenMessageTimeoutCallback, window);
- g_source_set_name_by_id(window->fullScreenMessageLabelId, "[WebKit] fullScreenMessageTimeoutCallback");
gtk_widget_hide(window->toolbar);
- window->searchBarVisible = gtk_widget_get_visible(GTK_WIDGET(window->searchBar));
- browser_search_bar_close(window->searchBar);
-
+ browser_tab_enter_fullscreen(window->activeTab);
return FALSE;
}
static gboolean webViewLeaveFullScreen(WebKitWebView *webView, BrowserWindow *window)
{
- if (window->fullScreenMessageLabelId) {
- g_source_remove(window->fullScreenMessageLabelId);
- window->fullScreenMessageLabelId = 0;
- }
- gtk_widget_hide(window->fullScreenMessageLabel);
+ browser_tab_leave_fullscreen(window->activeTab);
gtk_widget_show(window->toolbar);
- if (window->searchBarVisible) {
- // Opening the search bar steals the focus. Usually, we want
- // this but not when coming back from fullscreen.
- GtkWidget *focusWidget = gtk_window_get_focus(GTK_WINDOW(window));
- browser_search_bar_open(window->searchBar);
- gtk_window_set_focus(GTK_WINDOW(window), focusWidget);
- }
-
return FALSE;
}
-static GtkWidget *webViewCreate(WebKitWebView *webView, BrowserWindow *window)
-{
- WebKitWebView *newWebView = WEBKIT_WEB_VIEW(webkit_web_view_new_with_related_view(webView));
- webkit_web_view_set_settings(newWebView, webkit_web_view_get_settings(webView));
-
- GtkWidget *newWindow = browser_window_new(newWebView, GTK_WINDOW(window));
- g_signal_connect(newWebView, "ready-to-show", G_CALLBACK(webViewReadyToShow), newWindow);
- g_signal_connect(newWebView, "run-as-modal", G_CALLBACK(webViewRunAsModal), newWindow);
- g_signal_connect(newWebView, "close", G_CALLBACK(webViewClose), newWindow);
- return GTK_WIDGET(newWebView);
-}
-
static gboolean webViewLoadFailed(WebKitWebView *webView, WebKitLoadEvent loadEvent, const char *failingURI, GError *error, BrowserWindow *window)
{
gtk_entry_set_progress_fraction(GTK_ENTRY(window->uriEntry), 0.);
@@ -364,57 +338,28 @@ static gboolean webViewLoadFailed(WebKitWebView *webView, WebKitLoadEvent loadEv
static gboolean webViewDecidePolicy(WebKitWebView *webView, WebKitPolicyDecision *decision, WebKitPolicyDecisionType decisionType, BrowserWindow *window)
{
- switch (decisionType) {
- case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION: {
- WebKitNavigationPolicyDecision *navigationDecision = WEBKIT_NAVIGATION_POLICY_DECISION(decision);
- if (webkit_navigation_policy_decision_get_navigation_type(navigationDecision) != WEBKIT_NAVIGATION_TYPE_LINK_CLICKED
- || webkit_navigation_policy_decision_get_mouse_button(navigationDecision) != GDK_BUTTON_MIDDLE)
- return FALSE;
-
- // Opening a new window if link clicked with the middle button.
- WebKitWebView *newWebView = WEBKIT_WEB_VIEW(webkit_web_view_new_with_context(webkit_web_view_get_context(webView)));
- GtkWidget *newWindow = browser_window_new(newWebView, GTK_WINDOW(window));
- webkit_web_view_load_request(newWebView, webkit_navigation_policy_decision_get_request(navigationDecision));
- gtk_widget_show(newWindow);
-
- webkit_policy_decision_ignore(decision);
- return TRUE;
- }
- case WEBKIT_POLICY_DECISION_TYPE_RESPONSE: {
- WebKitResponsePolicyDecision *responseDecision = WEBKIT_RESPONSE_POLICY_DECISION(decision);
- if (webkit_response_policy_decision_is_mime_type_supported(responseDecision))
- return FALSE;
-
- WebKitWebResource *mainResource = webkit_web_view_get_main_resource(webView);
- WebKitURIRequest *request = webkit_response_policy_decision_get_request(responseDecision);
- const char *requestURI = webkit_uri_request_get_uri(request);
- if (g_strcmp0(webkit_web_resource_get_uri(mainResource), requestURI))
- return FALSE;
-
- webkit_policy_decision_download(decision);
- return TRUE;
- }
- case WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION:
- default:
+ if (decisionType != WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION)
return FALSE;
- }
-}
-static gboolean webViewDecidePermissionRequest(WebKitWebView *webView, WebKitPermissionRequest *request, BrowserWindow *window)
-{
- if (!WEBKIT_IS_GEOLOCATION_PERMISSION_REQUEST(request))
+ WebKitNavigationAction *navigationAction = webkit_navigation_policy_decision_get_navigation_action(WEBKIT_NAVIGATION_POLICY_DECISION(decision));
+ if (webkit_navigation_action_get_navigation_type(navigationAction) != WEBKIT_NAVIGATION_TYPE_LINK_CLICKED
+ || webkit_navigation_action_get_mouse_button(navigationAction) != GDK_BUTTON_MIDDLE)
return FALSE;
- GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window),
- GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_QUESTION,
- GTK_BUTTONS_YES_NO,
- "Geolocation request");
+ /* Multiple tabs are not allowed in editor mode. */
+ if (webkit_web_view_is_editable(webView))
+ return FALSE;
- gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "Allow geolocation request?");
- g_signal_connect(dialog, "response", G_CALLBACK(geolocationRequestDialogCallback), g_object_ref(request));
- gtk_widget_show(dialog);
+ /* Opening a new tab if link clicked with the middle button. */
+ WebKitWebView *newWebView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW,
+ "web-context", webkit_web_view_get_context(webView),
+ "settings", webkit_web_view_get_settings(webView),
+ "user-content-manager", webkit_web_view_get_user_content_manager(webView),
+ NULL));
+ browser_window_append_view(window, newWebView);
+ webkit_web_view_load_request(newWebView, webkit_navigation_action_get_request(navigationAction));
+ webkit_policy_decision_ignore(decision);
return TRUE;
}
@@ -429,16 +374,53 @@ static void webViewMouseTargetChanged(WebKitWebView *webView, WebKitHitTestResul
static gboolean browserWindowCanZoomIn(BrowserWindow *window)
{
- gdouble zoomLevel = webkit_web_view_get_zoom_level(window->webView) * zoomStep;
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ gdouble zoomLevel = webkit_web_view_get_zoom_level(webView) * zoomStep;
return zoomLevel < maximumZoomLevel;
}
static gboolean browserWindowCanZoomOut(BrowserWindow *window)
{
- gdouble zoomLevel = webkit_web_view_get_zoom_level(window->webView) / zoomStep;
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ gdouble zoomLevel = webkit_web_view_get_zoom_level(webView) / zoomStep;
return zoomLevel > minimumZoomLevel;
}
+static gboolean browserWindowZoomIn(BrowserWindow *window)
+{
+ if (browserWindowCanZoomIn(window)) {
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ gdouble zoomLevel = webkit_web_view_get_zoom_level(webView) * zoomStep;
+ webkit_web_view_set_zoom_level(webView, zoomLevel);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean browserWindowZoomOut(BrowserWindow *window)
+{
+ if (browserWindowCanZoomOut(window)) {
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ gdouble zoomLevel = webkit_web_view_get_zoom_level(webView) / zoomStep;
+ webkit_web_view_set_zoom_level(webView, zoomLevel);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean scrollEventCallback(WebKitWebView *webView, const GdkEventScroll *event, BrowserWindow *window)
+{
+ GdkModifierType mod = gtk_accelerator_get_default_mod_mask();
+
+ if ((event->state & mod) != GDK_CONTROL_MASK)
+ return FALSE;
+
+ if (event->delta_y < 0)
+ return browserWindowZoomIn(window);
+
+ return browserWindowZoomOut(window);
+}
+
static void browserWindowUpdateZoomActions(BrowserWindow *window)
{
gtk_widget_set_sensitive(window->zoomInItem, browserWindowCanZoomIn(window));
@@ -459,10 +441,10 @@ static void updateUriEntryIcon(BrowserWindow *window)
gtk_entry_set_icon_from_stock(entry, GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_NEW);
}
-static void faviconChanged(GObject *object, GParamSpec *paramSpec, BrowserWindow *window)
+static void faviconChanged(WebKitWebView *webView, GParamSpec *paramSpec, BrowserWindow *window)
{
GdkPixbuf *favicon = NULL;
- cairo_surface_t *surface = webkit_web_view_get_favicon(window->webView);
+ cairo_surface_t *surface = webkit_web_view_get_favicon(webView);
if (surface) {
int width = cairo_image_surface_get_width(surface);
@@ -477,32 +459,194 @@ static void faviconChanged(GObject *object, GParamSpec *paramSpec, BrowserWindow
updateUriEntryIcon(window);
}
-static void webViewIsLoadingChanged(GObject *object, GParamSpec *paramSpec, BrowserWindow *window)
+static void webViewIsLoadingChanged(WebKitWebView *webView, GParamSpec *paramSpec, BrowserWindow *window)
{
- gboolean isLoading = webkit_web_view_is_loading(window->webView);
+ gboolean isLoading = webkit_web_view_is_loading(webView);
gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(window->reloadOrStopButton), isLoading ? GTK_STOCK_STOP : GTK_STOCK_REFRESH);
}
static void zoomInCallback(BrowserWindow *window)
{
- gdouble zoomLevel = webkit_web_view_get_zoom_level(window->webView) * zoomStep;
- webkit_web_view_set_zoom_level(window->webView, zoomLevel);
+ browserWindowZoomIn(window);
}
static void zoomOutCallback(BrowserWindow *window)
{
- gdouble zoomLevel = webkit_web_view_get_zoom_level(window->webView) / zoomStep;
- webkit_web_view_set_zoom_level(window->webView, zoomLevel);
+ browserWindowZoomOut(window);
+}
+
+static void defaultZoomCallback(BrowserWindow *window)
+{
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ webkit_web_view_set_zoom_level(webView, defaultZoomLevel);
}
static void searchCallback(BrowserWindow *window)
{
- browser_search_bar_open(window->searchBar);
+ browser_tab_start_search(window->activeTab);
+}
+
+static void newTabCallback(BrowserWindow *window)
+{
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ if (webkit_web_view_is_editable(webView))
+ return;
+
+ browser_window_append_view(window, WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW,
+ "web-context", webkit_web_view_get_context(webView),
+ "settings", webkit_web_view_get_settings(webView),
+ "user-content-manager", webkit_web_view_get_user_content_manager(webView),
+ NULL)));
+ gtk_notebook_set_current_page(GTK_NOTEBOOK(window->notebook), -1);
+}
+
+static void toggleWebInspector(BrowserWindow *window)
+{
+ browser_tab_toggle_inspector(window->activeTab);
+}
+
+static void openPrivateWindow(BrowserWindow *window)
+{
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ WebKitWebView *newWebView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW,
+ "web-context", webkit_web_view_get_context(webView),
+ "settings", webkit_web_view_get_settings(webView),
+ "user-content-manager", webkit_web_view_get_user_content_manager(webView),
+ "is-ephemeral", TRUE,
+ NULL));
+ GtkWidget *newWindow = browser_window_new(GTK_WINDOW(window), window->webContext);
+ browser_window_append_view(BROWSER_WINDOW(newWindow), newWebView);
+ gtk_widget_show(GTK_WIDGET(newWindow));
+}
+
+static void reloadPage(BrowserWindow *window)
+{
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ webkit_web_view_reload(webView);
+}
+
+static void reloadPageIgnoringCache(BrowserWindow *window)
+{
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ webkit_web_view_reload_bypass_cache(webView);
+}
+
+static void stopPageLoad(BrowserWindow *window)
+{
+ browser_tab_stop_search(window->activeTab);
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ if (webkit_web_view_is_loading(webView))
+ webkit_web_view_stop_loading(webView);
+}
+
+static void loadHomePage(BrowserWindow *window)
+{
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ webkit_web_view_load_uri(webView, BROWSER_DEFAULT_URL);
+}
+
+static gboolean toggleFullScreen(BrowserWindow *window, gpointer user_data)
+{
+ if (!window->fullScreenIsEnabled) {
+ gtk_window_fullscreen(GTK_WINDOW(window));
+ gtk_widget_hide(window->toolbar);
+ window->fullScreenIsEnabled = TRUE;
+ } else {
+ gtk_window_unfullscreen(GTK_WINDOW(window));
+ gtk_widget_show(window->toolbar);
+ window->fullScreenIsEnabled = FALSE;
+ }
+ return TRUE;
+}
+
+static void webKitPrintOperationFailedCallback(WebKitPrintOperation *printOperation, GError *error)
+{
+ g_warning("Print failed: '%s'", error->message);
+}
+
+static gboolean printPage(BrowserWindow *window, gpointer user_data)
+{
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ WebKitPrintOperation *printOperation = webkit_print_operation_new(webView);
+
+ g_signal_connect(printOperation, "failed", G_CALLBACK(webKitPrintOperationFailedCallback), NULL);
+ webkit_print_operation_run_dialog(printOperation, GTK_WINDOW(window));
+ g_object_unref(printOperation);
+
+ return TRUE;
+}
+
+static void editingCommandCallback(GtkWidget *widget, BrowserWindow *window)
+{
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ webkit_web_view_execute_editing_command(webView, gtk_widget_get_name(widget));
+}
+
+static void insertImageCommandCallback(GtkWidget *widget, BrowserWindow *window)
+{
+ GtkWidget *fileChooser = gtk_file_chooser_dialog_new("Insert Image", GTK_WINDOW(window), GTK_FILE_CHOOSER_ACTION_OPEN,
+ "Cancel", GTK_RESPONSE_CANCEL, "Open", GTK_RESPONSE_ACCEPT, NULL);
+
+ GtkFileFilter *filter = gtk_file_filter_new();
+ gtk_file_filter_set_name(filter, "Images");
+ gtk_file_filter_add_pixbuf_formats(filter);
+ gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(fileChooser), filter);
+
+ if (gtk_dialog_run(GTK_DIALOG(fileChooser)) == GTK_RESPONSE_ACCEPT) {
+ char *uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(fileChooser));
+ if (uri) {
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ webkit_web_view_execute_editing_command_with_argument(webView, WEBKIT_EDITING_COMMAND_INSERT_IMAGE, uri);
+ g_free(uri);
+ }
+ }
+
+ gtk_widget_destroy(fileChooser);
+}
+
+static void insertLinkCommandCallback(GtkWidget *widget, BrowserWindow *window)
+{
+ GtkWidget *dialog = gtk_dialog_new_with_buttons("Insert Link", GTK_WINDOW(window), GTK_DIALOG_MODAL, "Insert", GTK_RESPONSE_ACCEPT, NULL);
+ gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
+ GtkWidget *entry = gtk_entry_new();
+ gtk_entry_set_placeholder_text(GTK_ENTRY(entry), "URL");
+ gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
+ gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), entry);
+ gtk_widget_show(entry);
+
+ if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
+ const char *url = gtk_entry_get_text(GTK_ENTRY(entry));
+ if (url && *url) {
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ webkit_web_view_execute_editing_command_with_argument(webView, WEBKIT_EDITING_COMMAND_CREATE_LINK, url);
+ }
+ }
+
+ gtk_widget_destroy(dialog);
+}
+
+static void browserWindowEditingCommandToggleButtonSetActive(BrowserWindow *window, GtkWidget *button, gboolean active)
+{
+ g_signal_handlers_block_by_func(button, G_CALLBACK(editingCommandCallback), window);
+ gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(button), active);
+ g_signal_handlers_unblock_by_func(button, G_CALLBACK(editingCommandCallback), window);
+}
+
+static void typingAttributesChanged(WebKitEditorState *editorState, GParamSpec *spec, BrowserWindow *window)
+{
+ unsigned typingAttributes = webkit_editor_state_get_typing_attributes(editorState);
+ browserWindowEditingCommandToggleButtonSetActive(window, window->boldItem, typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_BOLD);
+ browserWindowEditingCommandToggleButtonSetActive(window, window->italicItem, typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_ITALIC);
+ browserWindowEditingCommandToggleButtonSetActive(window, window->underlineItem, typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_UNDERLINE);
+ browserWindowEditingCommandToggleButtonSetActive(window, window->strikethroughItem, typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_STRIKETHROUGH);
}
static void browserWindowFinalize(GObject *gObject)
{
BrowserWindow *window = BROWSER_WINDOW(gObject);
+
+ g_signal_handlers_disconnect_matched(window->webContext, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, window);
+
if (window->favicon) {
g_object_unref(window->favicon);
window->favicon = NULL;
@@ -513,42 +657,207 @@ static void browserWindowFinalize(GObject *gObject)
window->accelGroup = NULL;
}
- if (window->fullScreenMessageLabelId)
- g_source_remove(window->fullScreenMessageLabelId);
-
if (window->resetEntryProgressTimeoutId)
g_source_remove(window->resetEntryProgressTimeoutId);
+ g_free(window->sessionFile);
+
G_OBJECT_CLASS(browser_window_parent_class)->finalize(gObject);
if (g_atomic_int_dec_and_test(&windowCount))
gtk_main_quit();
}
-static void browserWindowGetProperty(GObject *object, guint propId, GValue *value, GParamSpec *pspec)
+static void browserWindowSetupEditorToolbar(BrowserWindow *window)
{
- BrowserWindow *window = BROWSER_WINDOW(object);
+ GtkWidget *toolbar = gtk_toolbar_new();
+ gtk_orientable_set_orientation(GTK_ORIENTABLE(toolbar), GTK_ORIENTATION_HORIZONTAL);
+ gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_BOTH_HORIZ);
- switch (propId) {
- case PROP_VIEW:
- g_value_set_object(value, browser_window_get_view(window));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
- }
+ GtkToolItem *item = gtk_toggle_tool_button_new_from_stock(GTK_STOCK_BOLD);
+ window->boldItem = GTK_WIDGET(item);
+ gtk_widget_set_name(GTK_WIDGET(item), "Bold");
+ g_signal_connect(G_OBJECT(item), "toggled", G_CALLBACK(editingCommandCallback), window);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+ gtk_widget_show(GTK_WIDGET(item));
+
+ item = gtk_toggle_tool_button_new_from_stock(GTK_STOCK_ITALIC);
+ window->italicItem = GTK_WIDGET(item);
+ gtk_widget_set_name(GTK_WIDGET(item), "Italic");
+ g_signal_connect(G_OBJECT(item), "toggled", G_CALLBACK(editingCommandCallback), window);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+ gtk_widget_show(GTK_WIDGET(item));
+
+ item = gtk_toggle_tool_button_new_from_stock(GTK_STOCK_UNDERLINE);
+ window->underlineItem = GTK_WIDGET(item);
+ gtk_widget_set_name(GTK_WIDGET(item), "Underline");
+ g_signal_connect(G_OBJECT(item), "toggled", G_CALLBACK(editingCommandCallback), window);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+ gtk_widget_show(GTK_WIDGET(item));
+
+ item = gtk_toggle_tool_button_new_from_stock(GTK_STOCK_STRIKETHROUGH);
+ gtk_widget_set_name(GTK_WIDGET(item), "Strikethrough");
+ window->strikethroughItem = GTK_WIDGET(item);
+ g_signal_connect(G_OBJECT(item), "toggled", G_CALLBACK(editingCommandCallback), window);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+ gtk_widget_show(GTK_WIDGET(item));
+
+ item = gtk_separator_tool_item_new();
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+ gtk_widget_show(GTK_WIDGET(item));
+
+ item = gtk_tool_button_new_from_stock(GTK_STOCK_CUT);
+ gtk_widget_set_name(GTK_WIDGET(item), WEBKIT_EDITING_COMMAND_CUT);
+ g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(editingCommandCallback), window);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+ gtk_widget_show(GTK_WIDGET(item));
+
+ item = gtk_tool_button_new_from_stock(GTK_STOCK_COPY);
+ gtk_widget_set_name(GTK_WIDGET(item), WEBKIT_EDITING_COMMAND_COPY);
+ g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(editingCommandCallback), window);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+ gtk_widget_show(GTK_WIDGET(item));
+
+ item = gtk_tool_button_new_from_stock(GTK_STOCK_PASTE);
+ gtk_widget_set_name(GTK_WIDGET(item), WEBKIT_EDITING_COMMAND_PASTE);
+ g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(editingCommandCallback), window);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+ gtk_widget_show(GTK_WIDGET(item));
+
+ item = gtk_separator_tool_item_new();
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+ gtk_widget_show(GTK_WIDGET(item));
+
+ item = gtk_tool_button_new_from_stock(GTK_STOCK_UNDO);
+ gtk_widget_set_name(GTK_WIDGET(item), WEBKIT_EDITING_COMMAND_UNDO);
+ g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(editingCommandCallback), window);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+ gtk_widget_show(GTK_WIDGET(item));
+
+ item = gtk_tool_button_new_from_stock(GTK_STOCK_REDO);
+ gtk_widget_set_name(GTK_WIDGET(item), WEBKIT_EDITING_COMMAND_REDO);
+ g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(editingCommandCallback), window);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+ gtk_widget_show(GTK_WIDGET(item));
+
+ item = gtk_separator_tool_item_new();
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+ gtk_widget_show(GTK_WIDGET(item));
+
+ item = gtk_radio_tool_button_new_from_stock(NULL, GTK_STOCK_JUSTIFY_LEFT);
+ GSList *justifyRadioGroup = gtk_radio_tool_button_get_group(GTK_RADIO_TOOL_BUTTON(item));
+ gtk_widget_set_name(GTK_WIDGET(item), "JustifyLeft");
+ g_signal_connect(G_OBJECT(item), "toggled", G_CALLBACK(editingCommandCallback), window);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+ gtk_widget_show(GTK_WIDGET(item));
+
+ item = gtk_radio_tool_button_new_from_stock(justifyRadioGroup, GTK_STOCK_JUSTIFY_CENTER);
+ justifyRadioGroup = gtk_radio_tool_button_get_group(GTK_RADIO_TOOL_BUTTON(item));
+ gtk_widget_set_name(GTK_WIDGET(item), "JustifyCenter");
+ g_signal_connect(G_OBJECT(item), "toggled", G_CALLBACK(editingCommandCallback), window);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+ gtk_widget_show(GTK_WIDGET(item));
+
+ item = gtk_radio_tool_button_new_from_stock(justifyRadioGroup, GTK_STOCK_JUSTIFY_RIGHT);
+ gtk_widget_set_name(GTK_WIDGET(item), "JustifyRight");
+ g_signal_connect(G_OBJECT(item), "toggled", G_CALLBACK(editingCommandCallback), window);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+ gtk_widget_show(GTK_WIDGET(item));
+
+ item = gtk_separator_tool_item_new();
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+ gtk_widget_show(GTK_WIDGET(item));
+
+ item = gtk_tool_button_new_from_stock(GTK_STOCK_INDENT);
+ gtk_widget_set_name(GTK_WIDGET(item), "Indent");
+ g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(editingCommandCallback), window);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+ gtk_widget_show(GTK_WIDGET(item));
+
+ item = gtk_tool_button_new_from_stock(GTK_STOCK_UNINDENT);
+ gtk_widget_set_name(GTK_WIDGET(item), "Outdent");
+ g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(editingCommandCallback), window);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+ gtk_widget_show(GTK_WIDGET(item));
+
+ item = gtk_separator_tool_item_new();
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+ gtk_widget_show(GTK_WIDGET(item));
+
+ item = gtk_tool_button_new(NULL, NULL);
+ gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), "insert-image");
+ g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(insertImageCommandCallback), window);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+ gtk_widget_show(GTK_WIDGET(item));
+
+ item = gtk_tool_button_new(NULL, NULL);
+ gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), "insert-link");
+ g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(insertLinkCommandCallback), window);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+ gtk_widget_show(GTK_WIDGET(item));
+
+ gtk_box_pack_start(GTK_BOX(window->mainBox), toolbar, FALSE, FALSE, 0);
+ gtk_box_reorder_child(GTK_BOX(window->mainBox), toolbar, 1);
+ gtk_widget_show(toolbar);
}
-static void browserWindowSetProperty(GObject *object, guint propId, const GValue *value, GParamSpec *pspec)
+static void browserWindowSwitchTab(GtkNotebook *notebook, BrowserTab *tab, guint tabIndex, BrowserWindow *window)
{
- BrowserWindow* window = BROWSER_WINDOW(object);
+ if (window->activeTab == tab)
+ return;
- switch (propId) {
- case PROP_VIEW:
- window->webView = g_value_get_object(value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
+ if (window->activeTab) {
+ browser_tab_set_status_text(window->activeTab, NULL);
+ g_clear_object(&window->favicon);
+
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ g_signal_handlers_disconnect_by_data(webView, window);
+
+ /* We always want close to be connected even for not active tabs */
+ g_signal_connect(webView, "close", G_CALLBACK(webViewClose), window);
+
+ WebKitBackForwardList *backForwadlist = webkit_web_view_get_back_forward_list(webView);
+ g_signal_handlers_disconnect_by_data(backForwadlist, window);
+ }
+
+ window->activeTab = tab;
+
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ if (webkit_web_view_is_editable(webView)) {
+ browserWindowSetupEditorToolbar(window);
+ g_signal_connect(webkit_web_view_get_editor_state(webView), "notify::typing-attributes", G_CALLBACK(typingAttributesChanged), window);
}
+ webViewURIChanged(webView, NULL, window);
+ webViewTitleChanged(webView, NULL, window);
+ webViewIsLoadingChanged(webView, NULL, window);
+ faviconChanged(webView, NULL, window);
+ browserWindowUpdateZoomActions(window);
+ if (webkit_web_view_is_loading(webView))
+ webViewLoadProgressChanged(webView, NULL, window);
+
+ g_signal_connect(webView, "notify::uri", G_CALLBACK(webViewURIChanged), window);
+ g_signal_connect(webView, "notify::estimated-load-progress", G_CALLBACK(webViewLoadProgressChanged), window);
+ g_signal_connect(webView, "notify::title", G_CALLBACK(webViewTitleChanged), window);
+ g_signal_connect(webView, "notify::is-loading", G_CALLBACK(webViewIsLoadingChanged), window);
+ g_signal_connect(webView, "create", G_CALLBACK(webViewCreate), window);
+ g_signal_connect(webView, "close", G_CALLBACK(webViewClose), window);
+ g_signal_connect(webView, "load-failed", G_CALLBACK(webViewLoadFailed), window);
+ g_signal_connect(webView, "decide-policy", G_CALLBACK(webViewDecidePolicy), window);
+ g_signal_connect(webView, "mouse-target-changed", G_CALLBACK(webViewMouseTargetChanged), window);
+ g_signal_connect(webView, "notify::zoom-level", G_CALLBACK(webViewZoomLevelChanged), window);
+ g_signal_connect(webView, "notify::favicon", G_CALLBACK(faviconChanged), window);
+ g_signal_connect(webView, "enter-fullscreen", G_CALLBACK(webViewEnterFullScreen), window);
+ g_signal_connect(webView, "leave-fullscreen", G_CALLBACK(webViewLeaveFullScreen), window);
+ g_signal_connect(webView, "scroll-event", G_CALLBACK(scrollEventCallback), window);
+
+ WebKitBackForwardList *backForwadlist = webkit_web_view_get_back_forward_list(webView);
+ browserWindowUpdateNavigationActions(window, backForwadlist);
+ g_signal_connect(backForwadlist, "changed", G_CALLBACK(backForwadlistChanged), window);
+}
+
+static void browserWindowTabAddedOrRemoved(GtkNotebook *notebook, BrowserTab *tab, guint tabIndex, BrowserWindow *window)
+{
+ gtk_notebook_set_show_tabs(GTK_NOTEBOOK(window->notebook), gtk_notebook_get_n_pages(notebook) > 1);
}
static void browser_window_init(BrowserWindow *window)
@@ -567,6 +876,64 @@ static void browser_window_init(BrowserWindow *window)
window->accelGroup = gtk_accel_group_new();
gtk_window_add_accel_group(GTK_WINDOW(window), window->accelGroup);
+ /* Global accelerators */
+ gtk_accel_group_connect(window->accelGroup, GDK_KEY_I, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_ACCEL_VISIBLE,
+ g_cclosure_new_swap(G_CALLBACK(toggleWebInspector), window, NULL));
+ gtk_accel_group_connect(window->accelGroup, GDK_KEY_F12, 0, GTK_ACCEL_VISIBLE,
+ g_cclosure_new_swap(G_CALLBACK(toggleWebInspector), window, NULL));
+ gtk_accel_group_connect(window->accelGroup, GDK_KEY_P, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_ACCEL_VISIBLE,
+ g_cclosure_new_swap(G_CALLBACK(openPrivateWindow), window, NULL));
+
+ /* Reload page */
+ gtk_accel_group_connect(window->accelGroup, GDK_KEY_F5, 0, GTK_ACCEL_VISIBLE,
+ g_cclosure_new_swap(G_CALLBACK(reloadPage), window, NULL));
+ gtk_accel_group_connect(window->accelGroup, GDK_KEY_R, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
+ g_cclosure_new_swap(G_CALLBACK(reloadPage), window, NULL));
+
+ /* Reload page ignoring cache */
+ gtk_accel_group_connect(window->accelGroup, GDK_KEY_F5, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
+ g_cclosure_new_swap(G_CALLBACK(reloadPageIgnoringCache), window, NULL));
+ gtk_accel_group_connect(window->accelGroup, GDK_KEY_R, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_ACCEL_VISIBLE,
+ g_cclosure_new_swap(G_CALLBACK(reloadPageIgnoringCache), window, NULL));
+
+ /* Stop page load */
+ gtk_accel_group_connect(window->accelGroup, GDK_KEY_F6, 0, GTK_ACCEL_VISIBLE,
+ g_cclosure_new_swap(G_CALLBACK(stopPageLoad), window, NULL));
+ gtk_accel_group_connect(window->accelGroup, GDK_KEY_Escape, 0, GTK_ACCEL_VISIBLE,
+ g_cclosure_new_swap(G_CALLBACK(stopPageLoad), window, NULL));
+
+ /* Load home page */
+ gtk_accel_group_connect(window->accelGroup, GDK_KEY_Home, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE,
+ g_cclosure_new_swap(G_CALLBACK(loadHomePage), window, NULL));
+
+ /* Zoom in, zoom out and default zoom*/
+ gtk_accel_group_connect(window->accelGroup, GDK_KEY_equal, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
+ g_cclosure_new_swap(G_CALLBACK(zoomInCallback), window, NULL));
+ gtk_accel_group_connect(window->accelGroup, GDK_KEY_KP_Add, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
+ g_cclosure_new_swap(G_CALLBACK(zoomInCallback), window, NULL));
+ gtk_accel_group_connect(window->accelGroup, GDK_KEY_minus, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
+ g_cclosure_new_swap(G_CALLBACK(zoomOutCallback), window, NULL));
+ gtk_accel_group_connect(window->accelGroup, GDK_KEY_KP_Subtract, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
+ g_cclosure_new_swap(G_CALLBACK(zoomOutCallback), window, NULL));
+ gtk_accel_group_connect(window->accelGroup, GDK_KEY_0, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
+ g_cclosure_new_swap(G_CALLBACK(defaultZoomCallback), window, NULL));
+ gtk_accel_group_connect(window->accelGroup, GDK_KEY_KP_0, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
+ g_cclosure_new_swap(G_CALLBACK(defaultZoomCallback), window, NULL));
+
+ /* Toggle fullscreen */
+ gtk_accel_group_connect(window->accelGroup, GDK_KEY_F11, 0, GTK_ACCEL_VISIBLE,
+ g_cclosure_new_swap(G_CALLBACK(toggleFullScreen), window, NULL));
+
+ /* Quit */
+ gtk_accel_group_connect(window->accelGroup, GDK_KEY_Q, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
+ g_cclosure_new_swap(G_CALLBACK(gtk_widget_destroy), window, NULL));
+ gtk_accel_group_connect(window->accelGroup, GDK_KEY_W, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
+ g_cclosure_new_swap(G_CALLBACK(gtk_widget_destroy), window, NULL));
+
+ /* Print */
+ gtk_accel_group_connect(window->accelGroup, GDK_KEY_P, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
+ g_cclosure_new_swap(G_CALLBACK(printPage), window, NULL));
+
GtkWidget *toolbar = gtk_toolbar_new();
window->toolbar = toolbar;
gtk_orientable_set_orientation(GTK_ORIENTABLE(toolbar), GTK_ORIENTATION_HORIZONTAL);
@@ -609,6 +976,18 @@ static void browser_window_init(BrowserWindow *window)
gtk_widget_add_accelerator(GTK_WIDGET(item), "clicked", window->accelGroup, GDK_KEY_F, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
gtk_widget_show(GTK_WIDGET(item));
+ item = gtk_tool_button_new_from_stock(GTK_STOCK_HOME);
+ g_signal_connect_swapped(item, "clicked", G_CALLBACK(loadHomePage), window);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+ gtk_widget_add_accelerator(GTK_WIDGET(item), "clicked", window->accelGroup, GDK_KEY_Home, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE);
+ gtk_widget_show(GTK_WIDGET(item));
+
+ item = gtk_tool_button_new(gtk_image_new_from_icon_name("tab-new", GTK_ICON_SIZE_SMALL_TOOLBAR), NULL);
+ g_signal_connect_swapped(item, "clicked", G_CALLBACK(newTabCallback), window);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+ gtk_widget_add_accelerator(GTK_WIDGET(item), "clicked", window->accelGroup, GDK_KEY_T, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
+ gtk_widget_show_all(GTK_WIDGET(item));
+
item = gtk_tool_item_new();
gtk_tool_item_set_expand(item, TRUE);
gtk_container_add(GTK_CONTAINER(item), window->uriEntry);
@@ -628,60 +1007,44 @@ static void browser_window_init(BrowserWindow *window)
gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
gtk_widget_show(toolbar);
+ window->notebook = gtk_notebook_new();
+ g_signal_connect(window->notebook, "switch-page", G_CALLBACK(browserWindowSwitchTab), window);
+ g_signal_connect(window->notebook, "page-added", G_CALLBACK(browserWindowTabAddedOrRemoved), window);
+ g_signal_connect(window->notebook, "page-removed", G_CALLBACK(browserWindowTabAddedOrRemoved), window);
+ gtk_notebook_set_show_tabs(GTK_NOTEBOOK(window->notebook), FALSE);
+ gtk_notebook_set_show_border(GTK_NOTEBOOK(window->notebook), FALSE);
+ gtk_box_pack_start(GTK_BOX(window->mainBox), window->notebook, TRUE, TRUE, 0);
+ gtk_widget_show(window->notebook);
+
gtk_container_add(GTK_CONTAINER(window), vbox);
gtk_widget_show(vbox);
}
static void browserWindowConstructed(GObject *gObject)
{
- BrowserWindow *window = BROWSER_WINDOW(gObject);
-
- browserWindowUpdateZoomActions(window);
-
- g_signal_connect(window->webView, "notify::uri", G_CALLBACK(webViewURIChanged), window);
- g_signal_connect(window->webView, "notify::estimated-load-progress", G_CALLBACK(webViewLoadProgressChanged), window);
- g_signal_connect(window->webView, "notify::title", G_CALLBACK(webViewTitleChanged), window);
- g_signal_connect(window->webView, "create", G_CALLBACK(webViewCreate), window);
- g_signal_connect(window->webView, "load-failed", G_CALLBACK(webViewLoadFailed), window);
- g_signal_connect(window->webView, "decide-policy", G_CALLBACK(webViewDecidePolicy), window);
- g_signal_connect(window->webView, "permission-request", G_CALLBACK(webViewDecidePermissionRequest), window);
- g_signal_connect(window->webView, "mouse-target-changed", G_CALLBACK(webViewMouseTargetChanged), window);
- g_signal_connect(window->webView, "notify::zoom-level", G_CALLBACK(webViewZoomLevelChanged), window);
- g_signal_connect(window->webView, "notify::favicon", G_CALLBACK(faviconChanged), window);
- g_signal_connect(window->webView, "enter-fullscreen", G_CALLBACK(webViewEnterFullScreen), window);
- g_signal_connect(window->webView, "leave-fullscreen", G_CALLBACK(webViewLeaveFullScreen), window);
- g_signal_connect(window->webView, "notify::is-loading", G_CALLBACK(webViewIsLoadingChanged), window);
-
- g_signal_connect(webkit_web_view_get_context(window->webView), "download-started", G_CALLBACK(downloadStarted), window);
-
- window->searchBar = BROWSER_SEARCH_BAR(browser_search_bar_new(window->webView));
- browser_search_bar_add_accelerators(window->searchBar, window->accelGroup);
- gtk_box_pack_start(GTK_BOX(window->mainBox), GTK_WIDGET(window->searchBar), FALSE, FALSE, 0);
-
- WebKitBackForwardList *backForwadlist = webkit_web_view_get_back_forward_list(window->webView);
- g_signal_connect(backForwadlist, "changed", G_CALLBACK(backForwadlistChanged), window);
-
- GtkWidget *overlay = gtk_overlay_new();
- gtk_box_pack_start(GTK_BOX(window->mainBox), overlay, TRUE, TRUE, 0);
- gtk_widget_show(overlay);
+ G_OBJECT_CLASS(browser_window_parent_class)->constructed(gObject);
+}
- window->statusLabel = gtk_label_new(NULL);
- gtk_widget_set_halign(window->statusLabel, GTK_ALIGN_START);
- gtk_widget_set_valign(window->statusLabel, GTK_ALIGN_END);
- gtk_widget_set_margin_left(window->statusLabel, 1);
- gtk_widget_set_margin_right(window->statusLabel, 1);
- gtk_widget_set_margin_top(window->statusLabel, 1);
- gtk_widget_set_margin_bottom(window->statusLabel, 1);
- gtk_overlay_add_overlay(GTK_OVERLAY(overlay), window->statusLabel);
+static void browserWindowSaveSession(BrowserWindow *window)
+{
+ if (!window->sessionFile)
+ return;
- gtk_container_add(GTK_CONTAINER(overlay), GTK_WIDGET(window->webView));
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ WebKitWebViewSessionState *state = webkit_web_view_get_session_state(webView);
+ GBytes *bytes = webkit_web_view_session_state_serialize(state);
+ webkit_web_view_session_state_unref(state);
+ g_file_set_contents(window->sessionFile, g_bytes_get_data(bytes, NULL), g_bytes_get_size(bytes), NULL);
+ g_bytes_unref(bytes);
+}
- window->fullScreenMessageLabel = gtk_label_new(NULL);
- gtk_widget_set_halign(window->fullScreenMessageLabel, GTK_ALIGN_CENTER);
- gtk_widget_set_valign(window->fullScreenMessageLabel, GTK_ALIGN_CENTER);
- gtk_widget_set_no_show_all(window->fullScreenMessageLabel, TRUE);
- gtk_overlay_add_overlay(GTK_OVERLAY(overlay), window->fullScreenMessageLabel);
- gtk_widget_show(GTK_WIDGET(window->webView));
+static gboolean browserWindowDeleteEvent(GtkWidget *widget, GdkEventAny* event)
+{
+ BrowserWindow *window = BROWSER_WINDOW(widget);
+ browserWindowSaveSession(window);
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ webkit_web_view_try_close(webView);
+ return TRUE;
}
static void browser_window_class_init(BrowserWindowClass *klass)
@@ -689,27 +1052,22 @@ static void browser_window_class_init(BrowserWindowClass *klass)
GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
gobjectClass->constructed = browserWindowConstructed;
- gobjectClass->get_property = browserWindowGetProperty;
- gobjectClass->set_property = browserWindowSetProperty;
gobjectClass->finalize = browserWindowFinalize;
- g_object_class_install_property(gobjectClass,
- PROP_VIEW,
- g_param_spec_object("view",
- "View",
- "The web view of this window",
- WEBKIT_TYPE_WEB_VIEW,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ GtkWidgetClass *widgetClass = GTK_WIDGET_CLASS(klass);
+ widgetClass->delete_event = browserWindowDeleteEvent;
}
-// Public API.
-GtkWidget *browser_window_new(WebKitWebView *view, GtkWindow *parent)
+/* Public API. */
+GtkWidget *browser_window_new(GtkWindow *parent, WebKitWebContext *webContext)
{
- g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(view), 0);
+ g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(webContext), NULL);
BrowserWindow *window = BROWSER_WINDOW(g_object_new(BROWSER_TYPE_WINDOW,
- "type", GTK_WINDOW_TOPLEVEL, "view", view, NULL));
+ "type", GTK_WINDOW_TOPLEVEL, NULL));
+ window->webContext = webContext;
+ g_signal_connect(window->webContext, "download-started", G_CALLBACK(downloadStarted), window);
if (parent) {
window->parentWindow = parent;
g_object_add_weak_pointer(G_OBJECT(parent), (gpointer *)&window->parentWindow);
@@ -718,11 +1076,28 @@ GtkWidget *browser_window_new(WebKitWebView *view, GtkWindow *parent)
return GTK_WIDGET(window);
}
-WebKitWebView *browser_window_get_view(BrowserWindow *window)
+WebKitWebContext *browser_window_get_web_context(BrowserWindow *window)
+{
+ g_return_val_if_fail(BROWSER_IS_WINDOW(window), NULL);
+
+ return window->webContext;
+}
+
+void browser_window_append_view(BrowserWindow *window, WebKitWebView *webView)
{
- g_return_val_if_fail(BROWSER_IS_WINDOW(window), 0);
+ g_return_if_fail(BROWSER_IS_WINDOW(window));
+ g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
- return window->webView;
+ if (window->activeTab && webkit_web_view_is_editable(browser_tab_get_web_view(window->activeTab))) {
+ g_warning("Only one tab is allowed in editable mode");
+ return;
+ }
+
+ GtkWidget *tab = browser_tab_new(webView);
+ browser_tab_add_accelerators(BROWSER_TAB(tab), window->accelGroup);
+ gtk_notebook_append_page(GTK_NOTEBOOK(window->notebook), tab, browser_tab_get_title_widget(BROWSER_TAB(tab)));
+ gtk_container_child_set(GTK_CONTAINER(window->notebook), tab, "tab-expand", TRUE, NULL);
+ gtk_widget_show(tab);
}
void browser_window_load_uri(BrowserWindow *window, const char *uri)
@@ -730,12 +1105,55 @@ void browser_window_load_uri(BrowserWindow *window, const char *uri)
g_return_if_fail(BROWSER_IS_WINDOW(window));
g_return_if_fail(uri);
- if (!g_str_has_prefix(uri, "javascript:")) {
- char *internalURI = getInternalURI(uri);
- webkit_web_view_load_uri(window->webView, internalURI);
- g_free(internalURI);
- return;
+ browser_tab_load_uri(window->activeTab, uri);
+}
+
+void browser_window_load_session(BrowserWindow *window, const char *sessionFile)
+{
+ g_return_if_fail(BROWSER_IS_WINDOW(window));
+ g_return_if_fail(sessionFile);
+
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ window->sessionFile = g_strdup(sessionFile);
+ gchar *data = NULL;
+ gsize dataLength;
+ if (g_file_get_contents(sessionFile, &data, &dataLength, NULL)) {
+ GBytes *bytes = g_bytes_new_take(data, dataLength);
+ WebKitWebViewSessionState *state = webkit_web_view_session_state_new(bytes);
+ g_bytes_unref(bytes);
+
+ if (state) {
+ webkit_web_view_restore_session_state(webView, state);
+ webkit_web_view_session_state_unref(state);
+ }
}
- webkit_web_view_run_javascript(window->webView, strstr(uri, "javascript:"), NULL, NULL, NULL);
+ WebKitBackForwardList *bfList = webkit_web_view_get_back_forward_list(webView);
+ WebKitBackForwardListItem *item = webkit_back_forward_list_get_current_item(bfList);
+ if (item)
+ webkit_web_view_go_to_back_forward_list_item(webView, item);
+ else
+ webkit_web_view_load_uri(webView, BROWSER_DEFAULT_URL);
+
+}
+
+void browser_window_set_background_color(BrowserWindow *window, GdkRGBA *rgba)
+{
+ g_return_if_fail(BROWSER_IS_WINDOW(window));
+ g_return_if_fail(rgba);
+
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ GdkRGBA viewRGBA;
+ webkit_web_view_get_background_color(webView, &viewRGBA);
+ if (gdk_rgba_equal(rgba, &viewRGBA))
+ return;
+
+ GdkVisual *rgbaVisual = gdk_screen_get_rgba_visual(gtk_window_get_screen(GTK_WINDOW(window)));
+ if (!rgbaVisual)
+ return;
+
+ gtk_widget_set_visual(GTK_WIDGET(window), rgbaVisual);
+ gtk_widget_set_app_paintable(GTK_WIDGET(window), TRUE);
+
+ webkit_web_view_set_background_color(webView, rgba);
}
diff --git a/Tools/MiniBrowser/gtk/BrowserWindow.h b/Tools/MiniBrowser/gtk/BrowserWindow.h
index 66675462f..15abd0612 100644
--- a/Tools/MiniBrowser/gtk/BrowserWindow.h
+++ b/Tools/MiniBrowser/gtk/BrowserWindow.h
@@ -37,15 +37,20 @@ G_BEGIN_DECLS
#define BROWSER_IS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), BROWSER_TYPE_WINDOW))
#define BROWSER_IS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), BROWSER_TYPE_WINDOW))
#define BROWSER_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), BROWSER_TYPE_WINDOW, BrowserWindowClass))
+#define BROWSER_DEFAULT_URL "http://www.webkitgtk.org/"
+#define BROWSER_ABOUT_SCHEME "minibrowser-about"
typedef struct _BrowserWindow BrowserWindow;
typedef struct _BrowserWindowClass BrowserWindowClass;
GType browser_window_get_type(void);
-GtkWidget* browser_window_new(WebKitWebView*, GtkWindow*);
-WebKitWebView* browser_window_get_view(BrowserWindow*);
-void browser_window_load_uri(BrowserWindow *, const char *uri);
+GtkWidget* browser_window_new(GtkWindow*, WebKitWebContext*);
+WebKitWebContext* browser_window_get_web_context(BrowserWindow*);
+void browser_window_append_view(BrowserWindow*, WebKitWebView*);
+void browser_window_load_uri(BrowserWindow*, const char *uri);
+void browser_window_load_session(BrowserWindow *, const char *sessionFile);
+void browser_window_set_background_color(BrowserWindow*, GdkRGBA*);
G_END_DECLS
diff --git a/Tools/MiniBrowser/gtk/CMakeLists.txt b/Tools/MiniBrowser/gtk/CMakeLists.txt
new file mode 100644
index 000000000..e38bc6dc1
--- /dev/null
+++ b/Tools/MiniBrowser/gtk/CMakeLists.txt
@@ -0,0 +1,64 @@
+set(MINIBROWSER_DIR "${TOOLS_DIR}/MiniBrowser/gtk")
+set(DERIVED_SOURCES_MINIBROWSER_DIR "${CMAKE_BINARY_DIR}/DerivedSources/MiniBrowser")
+
+file(MAKE_DIRECTORY ${DERIVED_SOURCES_MINIBROWSER_DIR})
+
+set(MiniBrowser_SOURCES
+ ${DERIVED_SOURCES_MINIBROWSER_DIR}/BrowserMarshal.c
+ ${MINIBROWSER_DIR}/BrowserCellRendererVariant.c
+ ${MINIBROWSER_DIR}/BrowserCellRendererVariant.h
+ ${MINIBROWSER_DIR}/BrowserDownloadsBar.c
+ ${MINIBROWSER_DIR}/BrowserDownloadsBar.h
+ ${MINIBROWSER_DIR}/BrowserSearchBar.c
+ ${MINIBROWSER_DIR}/BrowserSearchBar.h
+ ${MINIBROWSER_DIR}/BrowserSettingsDialog.c
+ ${MINIBROWSER_DIR}/BrowserSettingsDialog.h
+ ${MINIBROWSER_DIR}/BrowserTab.c
+ ${MINIBROWSER_DIR}/BrowserTab.h
+ ${MINIBROWSER_DIR}/BrowserWindow.c
+ ${MINIBROWSER_DIR}/BrowserWindow.h
+ ${MINIBROWSER_DIR}/main.c
+)
+
+set(MiniBrowser_INCLUDE_DIRECTORIES
+ ${DERIVED_SOURCES_MINIBROWSER_DIR}
+ ${DERIVED_SOURCES_WEBKIT2GTK_DIR}
+ ${FORWARDING_HEADERS_WEBKIT2GTK_DIR}
+ ${FORWARDING_HEADERS_DIR}
+ ${CMAKE_SOURCE_DIR}/Source
+)
+
+set(MiniBrowser_SYSTEM_INCLUDE_DIRECTORIES
+ ${GTK3_INCLUDE_DIRS}
+ ${GLIB_INCLUDE_DIRS}
+ ${LIBSOUP_INCLUDE_DIRS}
+)
+
+set(MiniBrowser_LIBRARIES
+ ${JavaScriptCore_LIBRARY_NAME}
+ WebKit2
+ ${GTK3_LIBRARIES}
+ ${GLIB_LIBRARIES}
+ ${LIBSOUP_LIBRARIES}
+)
+
+add_custom_command(
+ OUTPUT ${DERIVED_SOURCES_MINIBROWSER_DIR}/BrowserMarshal.c
+ ${DERIVED_SOURCES_MINIBROWSER_DIR}/BrowserMarshal.h
+ MAIN_DEPENDENCY ${MINIBROWSER_DIR}/browser-marshal.list
+ COMMAND glib-genmarshal --prefix=browser_marshal ${MINIBROWSER_DIR}/browser-marshal.list --body > ${DERIVED_SOURCES_MINIBROWSER_DIR}/BrowserMarshal.c
+ COMMAND glib-genmarshal --prefix=browser_marshal ${MINIBROWSER_DIR}/browser-marshal.list --header > ${DERIVED_SOURCES_MINIBROWSER_DIR}/BrowserMarshal.h
+ VERBATIM)
+
+if (DEVELOPER_MODE)
+ add_definitions(-DWEBKIT_INJECTED_BUNDLE_PATH="${CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
+endif ()
+
+add_definitions(-DGDK_VERSION_MIN_REQUIRED=GDK_VERSION_3_6)
+
+include_directories(${MiniBrowser_INCLUDE_DIRECTORIES})
+include_directories(SYSTEM ${MiniBrowser_SYSTEM_INCLUDE_DIRECTORIES})
+add_executable(MiniBrowser ${MiniBrowser_SOURCES})
+target_link_libraries(MiniBrowser ${MiniBrowser_LIBRARIES})
+
+install(TARGETS MiniBrowser DESTINATION "${LIBEXEC_INSTALL_DIR}")
diff --git a/Tools/MiniBrowser/gtk/GNUmakefile.am b/Tools/MiniBrowser/gtk/GNUmakefile.am
deleted file mode 100644
index 8bdbdd33e..000000000
--- a/Tools/MiniBrowser/gtk/GNUmakefile.am
+++ /dev/null
@@ -1,75 +0,0 @@
-if ENABLE_WEBKIT2
-noinst_PROGRAMS += \
- Programs/MiniBrowser
-endif
-
-Programs_MiniBrowser_CPPFLAGS = \
- -I$(srcdir)/Source \
- -I$(top_builddir)/DerivedSources/WebKit2 \
- -I$(top_builddir)/DerivedSources/WebKit2/webkit2gtk \
- -I$(top_builddir)/DerivedSources/WebKit2/webkit2gtk/include \
- -DWEBKIT_EXEC_PATH=\"${shell pwd}/$(top_builddir)/Programs/\" \
- -DWEBKIT_INJECTED_BUNDLE_PATH=\"${shell pwd}/$(top_builddir)/.libs\" \
- -DGDK_VERSION_MIN_REQUIRED=GDK_VERSION_3_6 \
- $(global_cppflags) \
- $(javascriptcore_cppflags) \
- $(FREETYPE_CFLAGS) \
- $(GLIB_CFLAGS) \
- $(GTK_CFLAGS) \
- $(LIBSOUP_CFLAGS)
-
-Programs_MiniBrowser_SOURCES = \
- Tools/MiniBrowser/gtk/BrowserCellRendererVariant.h \
- Tools/MiniBrowser/gtk/BrowserCellRendererVariant.c \
- Tools/MiniBrowser/gtk/BrowserDownloadsBar.h \
- Tools/MiniBrowser/gtk/BrowserDownloadsBar.c \
- Tools/MiniBrowser/gtk/BrowserSearchBar.h \
- Tools/MiniBrowser/gtk/BrowserSearchBar.c \
- Tools/MiniBrowser/gtk/BrowserSettingsDialog.h \
- Tools/MiniBrowser/gtk/BrowserSettingsDialog.c \
- Tools/MiniBrowser/gtk/BrowserWindow.h \
- Tools/MiniBrowser/gtk/BrowserWindow.c \
- Tools/MiniBrowser/gtk/main.c
-
-minibrowser_built_sources += \
- DerivedSources/WebKit2/BrowserMarshal.h \
- DerivedSources/WebKit2/BrowserMarshal.c
-nodist_Programs_MiniBrowser_SOURCES = \
- $(minibrowser_built_sources)
-
-Programs_MiniBrowser_LDADD = \
- libwebkit2gtk-@WEBKITGTK_API_MAJOR_VERSION@.@WEBKITGTK_API_MINOR_VERSION@.la \
- $(FREETYPE_LIBS) \
- $(GLIB_LIBS) \
- $(GTK_LIBS) \
- $(LIBSOUP_LIBS)
-
-Programs_MiniBrowser_LDFLAGS = \
- -no-install
-
-CLEANFILES += \
- $(top_builddir)/Programs/MiniBrowser \
- $(minibrowser_built_sources) \
- $(top_builddir)/stamp-mini-browser-marshal.h \
- $(top_builddir)/stamp-mini-browser-marshal.c
-
-BUILT_SOURCES += $(minibrowser_built_sources)
-
-minibrowser_marshal_list = $(srcdir)/Tools/MiniBrowser/gtk/browser-marshal.list
-
-$(GENSOURCES_WEBKIT2)/BrowserMarshal.h: stamp-mini-browser-marshal.h
- @true
-$(GENSOURCES_WEBKIT2)/BrowserMarshal.c: stamp-mini-browser-marshal.c
- @true
-
-stamp-mini-browser-marshal.c: $(minibrowser_marshal_list)
- $(AM_V_GEN)$(GLIB_GENMARSHAL) --prefix=browser_marshal $(minibrowser_marshal_list) --body > $(GENSOURCES_WEBKIT2)/BrowserMarshal.c && \
- echo timestamp > $(@F)
-
-stamp-mini-browser-marshal.h: $(minibrowser_marshal_list)
- $(AM_V_GEN)$(GLIB_GENMARSHAL) --prefix=browser_marshal $(minibrowser_marshal_list) --header > $(GENSOURCES_WEBKIT2)/BrowserMarshal.h && \
- echo timestamp > $(@F)
-
-EXTRA_DIST += \
- $(srcdir)/Tools/MiniBrowser/gtk/browser-marshal.list
-
diff --git a/Tools/MiniBrowser/gtk/main.c b/Tools/MiniBrowser/gtk/main.c
index e383fda83..e5e5618cd 100644
--- a/Tools/MiniBrowser/gtk/main.c
+++ b/Tools/MiniBrowser/gtk/main.c
@@ -12,10 +12,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -25,7 +25,10 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "cmakeconfig.h"
+
#include "BrowserWindow.h"
+#include <JavaScriptCore/JavaScript.h>
#include <errno.h>
#include <gtk/gtk.h>
#include <string.h>
@@ -34,7 +37,11 @@
#define MINI_BROWSER_ERROR (miniBrowserErrorQuark())
static const gchar **uriArguments = NULL;
-static const char *miniBrowserAboutScheme = "minibrowser-about";
+static GdkRGBA *backgroundColor;
+static gboolean editorMode;
+static const char *sessionFile;
+static char *geometry;
+static gboolean privateMode;
typedef enum {
MINI_BROWSER_ERROR_INVALID_ABOUT_PATH
@@ -54,24 +61,40 @@ static gchar *argumentToURL(const char *filename)
return fileURL;
}
-static void createBrowserWindow(const gchar *uri, WebKitSettings *webkitSettings)
+static WebKitWebView *createBrowserTab(BrowserWindow *window, WebKitSettings *webkitSettings, WebKitUserContentManager *userContentManager)
{
- GtkWidget *webView = webkit_web_view_new();
- GtkWidget *mainWindow = browser_window_new(WEBKIT_WEB_VIEW(webView), NULL);
- gchar *url = argumentToURL(uri);
+ WebKitWebView *webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW,
+ "web-context", browser_window_get_web_context(window),
+ "settings", webkitSettings,
+ "user-content-manager", userContentManager,
+ NULL));
+
+ if (editorMode)
+ webkit_web_view_set_editable(webView, TRUE);
- if (webkitSettings)
- webkit_web_view_set_settings(WEBKIT_WEB_VIEW(webView), webkitSettings);
+ browser_window_append_view(window, webView);
+ return webView;
+}
- browser_window_load_uri(BROWSER_WINDOW(mainWindow), url);
- g_free(url);
+static gboolean parseBackgroundColor(const char *optionName, const char *value, gpointer data, GError **error)
+{
+ GdkRGBA rgba;
+ if (gdk_rgba_parse(&rgba, value)) {
+ backgroundColor = gdk_rgba_copy(&rgba);
+ return TRUE;
+ }
- gtk_widget_grab_focus(webView);
- gtk_widget_show(mainWindow);
+ g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "Failed to parse '%s' as RGBA color", value);
+ return FALSE;
}
static const GOptionEntry commandLineOptions[] =
{
+ { "bg-color", 0, 0, G_OPTION_ARG_CALLBACK, parseBackgroundColor, "Background color", NULL },
+ { "editor-mode", 'e', 0, G_OPTION_ARG_NONE, &editorMode, "Run in editor mode", NULL },
+ { "session-file", 's', 0, G_OPTION_ARG_FILENAME, &sessionFile, "Session file", "FILE" },
+ { "geometry", 'g', 0, G_OPTION_ARG_STRING, &geometry, "Set the size and position of the window (WIDTHxHEIGHT+X+Y)", "GEOMETRY" },
+ { "private", 'p', 0, G_OPTION_ARG_NONE, &privateMode, "Run in private browsing mode", NULL },
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &uriArguments, 0, "[URL…]" },
{ 0, 0, 0, 0, 0, 0, 0 }
};
@@ -208,8 +231,196 @@ static gboolean addSettingsGroupToContext(GOptionContext *context, WebKitSetting
return TRUE;
}
-static void
-aboutURISchemeRequestCallback(WebKitURISchemeRequest *request, gpointer userData)
+typedef struct {
+ WebKitURISchemeRequest *request;
+ GList *dataList;
+ GHashTable *dataMap;
+} AboutDataRequest;
+
+static GHashTable *aboutDataRequestMap;
+
+static void aboutDataRequestFree(AboutDataRequest *request)
+{
+ if (!request)
+ return;
+
+ g_list_free_full(request->dataList, g_object_unref);
+
+ if (request->request)
+ g_object_unref(request->request);
+ if (request->dataMap)
+ g_hash_table_destroy(request->dataMap);
+
+ g_slice_free(AboutDataRequest, request);
+}
+
+static AboutDataRequest* aboutDataRequestNew(WebKitURISchemeRequest *uriRequest)
+{
+ if (!aboutDataRequestMap)
+ aboutDataRequestMap = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)aboutDataRequestFree);
+
+ AboutDataRequest *request = g_slice_new0(AboutDataRequest);
+ request->request = g_object_ref(uriRequest);
+ g_hash_table_insert(aboutDataRequestMap, GUINT_TO_POINTER(webkit_web_view_get_page_id(webkit_uri_scheme_request_get_web_view(request->request))), request);
+
+ return request;
+}
+
+static AboutDataRequest *aboutDataRequestForView(guint64 pageID)
+{
+ return aboutDataRequestMap ? g_hash_table_lookup(aboutDataRequestMap, GUINT_TO_POINTER(pageID)) : NULL;
+}
+
+static void websiteDataRemovedCallback(WebKitWebsiteDataManager *manager, GAsyncResult *result, AboutDataRequest *dataRequest)
+{
+ if (webkit_website_data_manager_remove_finish(manager, result, NULL))
+ webkit_web_view_reload(webkit_uri_scheme_request_get_web_view(dataRequest->request));
+}
+
+static void websiteDataClearedCallback(WebKitWebsiteDataManager *manager, GAsyncResult *result, AboutDataRequest *dataRequest)
+{
+ if (webkit_website_data_manager_clear_finish(manager, result, NULL))
+ webkit_web_view_reload(webkit_uri_scheme_request_get_web_view(dataRequest->request));
+}
+
+static void aboutDataScriptMessageReceivedCallback(WebKitUserContentManager *userContentManager, WebKitJavascriptResult *message, WebKitWebContext *webContext)
+{
+ JSValueRef jsValue = webkit_javascript_result_get_value(message);
+ JSStringRef jsString = JSValueToStringCopy(webkit_javascript_result_get_global_context(message), jsValue, NULL);
+ size_t maxSize = JSStringGetMaximumUTF8CStringSize(jsString);
+ if (!maxSize) {
+ JSStringRelease(jsString);
+ return;
+ }
+ char *messageString = g_malloc(maxSize);
+ JSStringGetUTF8CString(jsString, messageString, maxSize);
+ JSStringRelease(jsString);
+
+ char **tokens = g_strsplit(messageString, ":", 3);
+ g_free(messageString);
+
+ unsigned tokenCount = g_strv_length(tokens);
+ if (!tokens || tokenCount < 2) {
+ g_strfreev(tokens);
+ return;
+ }
+
+ guint64 pageID = g_ascii_strtoull(tokens[0], NULL, 10);
+ AboutDataRequest *dataRequest = aboutDataRequestForView(pageID);
+ if (!dataRequest) {
+ g_strfreev(tokens);
+ return;
+ }
+
+ WebKitWebsiteDataManager *manager = webkit_web_context_get_website_data_manager(webContext);
+ guint64 types = g_ascii_strtoull(tokens[1], NULL, 10);
+ if (tokenCount == 2)
+ webkit_website_data_manager_clear(manager, types, 0, NULL, (GAsyncReadyCallback)websiteDataClearedCallback, dataRequest);
+ else {
+ guint64 domainID = g_ascii_strtoull(tokens[2], NULL, 10);
+ GList *dataList = g_hash_table_lookup(dataRequest->dataMap, GUINT_TO_POINTER(types));
+ WebKitWebsiteData *data = g_list_nth_data(dataList, domainID);
+ if (data) {
+ GList dataList = { data, NULL, NULL };
+ webkit_website_data_manager_remove(manager, types, &dataList, NULL, (GAsyncReadyCallback)websiteDataRemovedCallback, dataRequest);
+ }
+ }
+ g_strfreev(tokens);
+}
+
+static void domainListFree(GList *domains)
+{
+ g_list_free_full(domains, (GDestroyNotify)webkit_website_data_unref);
+}
+
+static void aboutDataFillTable(GString *result, AboutDataRequest *dataRequest, GList* dataList, const char *title, WebKitWebsiteDataTypes types, const char *dataPath, guint64 pageID)
+{
+ guint64 totalDataSize = 0;
+ GList *domains = NULL;
+ GList *l;
+ for (l = dataList; l; l = g_list_next(l)) {
+ WebKitWebsiteData *data = (WebKitWebsiteData *)l->data;
+
+ if (webkit_website_data_get_types(data) & types) {
+ domains = g_list_prepend(domains, webkit_website_data_ref(data));
+ totalDataSize += webkit_website_data_get_size(data, types);
+ }
+ }
+ if (!domains)
+ return;
+
+ if (!dataRequest->dataMap)
+ dataRequest->dataMap = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)domainListFree);
+ g_hash_table_insert(dataRequest->dataMap, GUINT_TO_POINTER(types), domains);
+
+ if (totalDataSize) {
+ char *totalDataSizeStr = g_format_size(totalDataSize);
+ g_string_append_printf(result, "<h1>%s (%s)</h1>\n<table>\n", title, totalDataSizeStr);
+ g_free(totalDataSizeStr);
+ } else
+ g_string_append_printf(result, "<h1>%s</h1>\n<table>\n", title);
+ if (dataPath)
+ g_string_append_printf(result, "<tr><td colspan=\"2\">Path: %s</td></tr>\n", dataPath);
+
+ unsigned index;
+ for (l = domains, index = 0; l; l = g_list_next(l), index++) {
+ WebKitWebsiteData *data = (WebKitWebsiteData *)l->data;
+ const char *displayName = webkit_website_data_get_name(data);
+ guint64 dataSize = webkit_website_data_get_size(data, types);
+ if (dataSize) {
+ char *dataSizeStr = g_format_size(dataSize);
+ g_string_append_printf(result, "<tr><td>%s (%s)</td>", displayName, dataSizeStr);
+ g_free(dataSizeStr);
+ } else
+ g_string_append_printf(result, "<tr><td>%s</td>", displayName);
+ g_string_append_printf(result, "<td><input type=\"button\" value=\"Remove\" onclick=\"removeData('%"G_GUINT64_FORMAT":%u:%u');\"></td></tr>\n",
+ pageID, types, index);
+ }
+ g_string_append_printf(result, "<tr><td><input type=\"button\" value=\"Clear all\" onclick=\"clearData('%"G_GUINT64_FORMAT":%u');\"></td></tr></table>\n",
+ pageID, types);
+}
+
+static void gotWebsiteDataCallback(WebKitWebsiteDataManager *manager, GAsyncResult *asyncResult, AboutDataRequest *dataRequest)
+{
+ GList *dataList = webkit_website_data_manager_fetch_finish(manager, asyncResult, NULL);
+
+ GString *result = g_string_new(
+ "<html><head>"
+ "<script>"
+ " function removeData(domain) {"
+ " window.webkit.messageHandlers.aboutData.postMessage(domain);"
+ " }"
+ " function clearData(dataType) {"
+ " window.webkit.messageHandlers.aboutData.postMessage(dataType);"
+ " }"
+ "</script></head><body>\n");
+
+ guint64 pageID = webkit_web_view_get_page_id(webkit_uri_scheme_request_get_web_view(dataRequest->request));
+ aboutDataFillTable(result, dataRequest, dataList, "Cookies", WEBKIT_WEBSITE_DATA_COOKIES, NULL, pageID);
+ aboutDataFillTable(result, dataRequest, dataList, "Memory Cache", WEBKIT_WEBSITE_DATA_MEMORY_CACHE, NULL, pageID);
+ aboutDataFillTable(result, dataRequest, dataList, "Disk Cache", WEBKIT_WEBSITE_DATA_DISK_CACHE, webkit_website_data_manager_get_disk_cache_directory(manager), pageID);
+ aboutDataFillTable(result, dataRequest, dataList, "Session Storage", WEBKIT_WEBSITE_DATA_SESSION_STORAGE, NULL, pageID);
+ aboutDataFillTable(result, dataRequest, dataList, "Local Storage", WEBKIT_WEBSITE_DATA_LOCAL_STORAGE, webkit_website_data_manager_get_local_storage_directory(manager), pageID);
+ aboutDataFillTable(result, dataRequest, dataList, "WebSQL Databases", WEBKIT_WEBSITE_DATA_WEBSQL_DATABASES, webkit_website_data_manager_get_websql_directory(manager), pageID);
+ aboutDataFillTable(result, dataRequest, dataList, "IndexedDB Databases", WEBKIT_WEBSITE_DATA_INDEXEDDB_DATABASES, webkit_website_data_manager_get_indexeddb_directory(manager), pageID);
+ aboutDataFillTable(result, dataRequest, dataList, "Plugins Data", WEBKIT_WEBSITE_DATA_PLUGIN_DATA, NULL, pageID);
+ aboutDataFillTable(result, dataRequest, dataList, "Offline Web Applications Cache", WEBKIT_WEBSITE_DATA_OFFLINE_APPLICATION_CACHE, webkit_website_data_manager_get_offline_application_cache_directory(manager), pageID);
+
+ result = g_string_append(result, "</body></html>");
+ gsize streamLength = result->len;
+ GInputStream *stream = g_memory_input_stream_new_from_data(g_string_free(result, FALSE), streamLength, g_free);
+ webkit_uri_scheme_request_finish(dataRequest->request, stream, streamLength, "text/html");
+ g_list_free_full(dataList, (GDestroyNotify)webkit_website_data_unref);
+}
+
+static void aboutDataHandleRequest(WebKitURISchemeRequest *request, WebKitWebContext *webContext)
+{
+ AboutDataRequest *dataRequest = aboutDataRequestNew(request);
+ WebKitWebsiteDataManager *manager = webkit_web_context_get_website_data_manager(webContext);
+ webkit_website_data_manager_fetch(manager, WEBKIT_WEBSITE_DATA_ALL, NULL, (GAsyncReadyCallback)gotWebsiteDataCallback, dataRequest);
+}
+
+static void aboutURISchemeRequestCallback(WebKitURISchemeRequest *request, WebKitWebContext *webContext)
{
GInputStream *stream;
gsize streamLength;
@@ -228,7 +439,9 @@ aboutURISchemeRequestCallback(WebKitURISchemeRequest *request, gpointer userData
webkit_uri_scheme_request_finish(request, stream, streamLength, "text/html");
g_object_unref(stream);
- } else {
+ } else if (!g_strcmp0(path, "data"))
+ aboutDataHandleRequest(request, webContext);
+ else {
error = g_error_new(MINI_BROWSER_ERROR, MINI_BROWSER_ERROR_INVALID_ABOUT_PATH, "Invalid about:%s page.", path);
webkit_uri_scheme_request_finish_error(request, error);
g_error_free(error);
@@ -238,12 +451,9 @@ aboutURISchemeRequestCallback(WebKitURISchemeRequest *request, gpointer userData
int main(int argc, char *argv[])
{
gtk_init(&argc, &argv);
-
- const gchar *multiprocess = g_getenv("MINIBROWSER_MULTIPROCESS");
- if (multiprocess && *multiprocess) {
- webkit_web_context_set_process_model(webkit_web_context_get_default(),
- WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES);
- }
+#if ENABLE_DEVELOPER_MODE
+ g_setenv("WEBKIT_INJECTED_BUNDLE_PATH", WEBKIT_INJECTED_BUNDLE_PATH, FALSE);
+#endif
GOptionContext *context = g_option_context_new(NULL);
g_option_context_add_main_entries(context, commandLineOptions, 0);
@@ -252,6 +462,7 @@ int main(int argc, char *argv[])
WebKitSettings *webkitSettings = webkit_settings_new();
webkit_settings_set_enable_developer_extras(webkitSettings, TRUE);
webkit_settings_set_enable_webgl(webkitSettings, TRUE);
+ webkit_settings_set_enable_media_stream(webkitSettings, TRUE);
if (!addSettingsGroupToContext(context, webkitSettings))
g_clear_object(&webkitSettings);
@@ -265,24 +476,62 @@ int main(int argc, char *argv[])
}
g_option_context_free (context);
- g_setenv("WEBKIT_INJECTED_BUNDLE_PATH", WEBKIT_INJECTED_BUNDLE_PATH, FALSE);
+ WebKitWebContext *webContext = privateMode ? webkit_web_context_new_ephemeral() : webkit_web_context_get_default();
+
+ const gchar *singleprocess = g_getenv("MINIBROWSER_SINGLEPROCESS");
+ webkit_web_context_set_process_model(webContext, (singleprocess && *singleprocess) ?
+ WEBKIT_PROCESS_MODEL_SHARED_SECONDARY_PROCESS : WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES);
// Enable the favicon database, by specifying the default directory.
- webkit_web_context_set_favicon_database_directory(webkit_web_context_get_default(), NULL);
+ webkit_web_context_set_favicon_database_directory(webContext, NULL);
+
+ webkit_web_context_register_uri_scheme(webContext, BROWSER_ABOUT_SCHEME, (WebKitURISchemeRequestCallback)aboutURISchemeRequestCallback, webContext, NULL);
+
+ WebKitUserContentManager *userContentManager = webkit_user_content_manager_new();
+ webkit_user_content_manager_register_script_message_handler(userContentManager, "aboutData");
+ g_signal_connect(userContentManager, "script-message-received::aboutData", G_CALLBACK(aboutDataScriptMessageReceivedCallback), webContext);
- webkit_web_context_register_uri_scheme(webkit_web_context_get_default(), miniBrowserAboutScheme, aboutURISchemeRequestCallback, NULL, NULL);
+ BrowserWindow *mainWindow = BROWSER_WINDOW(browser_window_new(NULL, webContext));
+ if (geometry)
+ gtk_window_parse_geometry(GTK_WINDOW(mainWindow), geometry);
+ GtkWidget *firstTab = NULL;
if (uriArguments) {
int i;
- for (i = 0; uriArguments[i]; i++)
- createBrowserWindow(uriArguments[i], webkitSettings);
- } else
- createBrowserWindow("http://www.webkitgtk.org/", webkitSettings);
+ for (i = 0; uriArguments[i]; i++) {
+ WebKitWebView *webView = createBrowserTab(mainWindow, webkitSettings, userContentManager);
+ if (!i)
+ firstTab = GTK_WIDGET(webView);
+ gchar *url = argumentToURL(uriArguments[i]);
+ webkit_web_view_load_uri(webView, url);
+ g_free(url);
+ }
+ } else {
+ WebKitWebView *webView = createBrowserTab(mainWindow, webkitSettings, userContentManager);
+ firstTab = GTK_WIDGET(webView);
+
+ if (backgroundColor)
+ browser_window_set_background_color(mainWindow, backgroundColor);
+
+ if (!editorMode) {
+ if (sessionFile)
+ browser_window_load_session(mainWindow, sessionFile);
+ else
+ webkit_web_view_load_uri(webView, BROWSER_DEFAULT_URL);
+ }
+ }
+
+ gtk_widget_grab_focus(firstTab);
+ gtk_widget_show(GTK_WIDGET(mainWindow));
g_clear_object(&webkitSettings);
+ g_clear_object(&userContentManager);
gtk_main();
+ if (privateMode)
+ g_object_unref(webContext);
+
return 0;
}
diff --git a/Tools/Scripts/VCSUtils.pm b/Tools/Scripts/VCSUtils.pm
new file mode 100644
index 000000000..c5c44c530
--- /dev/null
+++ b/Tools/Scripts/VCSUtils.pm
@@ -0,0 +1,2433 @@
+# Copyright (C) 2007-2013, 2015 Apple Inc. All rights reserved.
+# Copyright (C) 2009, 2010 Chris Jerdonek (chris.jerdonek@gmail.com)
+# Copyright (C) 2010, 2011 Research In Motion Limited. All rights reserved.
+# Copyright (C) 2012 Daniel Bates (dbates@intudata.com)
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Module to share code to work with various version control systems.
+package VCSUtils;
+
+use strict;
+use warnings;
+
+use Cwd qw(); # "qw()" prevents warnings about redefining getcwd() with "use POSIX;"
+use English; # for $POSTMATCH, etc.
+use File::Basename;
+use File::Spec;
+use POSIX;
+use Term::ANSIColor qw(colored);
+
+BEGIN {
+ use Exporter ();
+ our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+ $VERSION = 1.00;
+ @ISA = qw(Exporter);
+ @EXPORT = qw(
+ &applyGitBinaryPatchDelta
+ &callSilently
+ &canonicalizePath
+ &changeLogEmailAddress
+ &changeLogName
+ &chdirReturningRelativePath
+ &decodeGitBinaryChunk
+ &decodeGitBinaryPatch
+ &determineSVNRoot
+ &determineVCSRoot
+ &escapeSubversionPath
+ &exitStatus
+ &fixChangeLogPatch
+ &fixSVNPatchForAdditionWithHistory
+ &gitBranch
+ &gitDirectory
+ &gitTreeDirectory
+ &gitdiff2svndiff
+ &isGit
+ &isGitSVN
+ &isGitBranchBuild
+ &isGitDirectory
+ &isGitSVNDirectory
+ &isSVN
+ &isSVNDirectory
+ &isSVNVersion16OrNewer
+ &makeFilePathRelative
+ &mergeChangeLogs
+ &normalizePath
+ &parseChunkRange
+ &parseDiffStartLine
+ &parseFirstEOL
+ &parsePatch
+ &pathRelativeToSVNRepositoryRootForPath
+ &possiblyColored
+ &prepareParsedPatch
+ &removeEOL
+ &runCommand
+ &runPatchCommand
+ &scmMoveOrRenameFile
+ &scmToggleExecutableBit
+ &setChangeLogDateAndReviewer
+ &svnIdentifierForPath
+ &svnInfoForPath
+ &svnRepositoryRootForPath
+ &svnRevisionForDirectory
+ &svnStatus
+ &svnURLForPath
+ &toWindowsLineEndings
+ &gitCommitForSVNRevision
+ &listOfChangedFilesBetweenRevisions
+ &unixPath
+ );
+ %EXPORT_TAGS = ( );
+ @EXPORT_OK = ();
+}
+
+our @EXPORT_OK;
+
+my $gitBranch;
+my $gitRoot;
+my $isGit;
+my $isGitSVN;
+my $isGitBranchBuild;
+my $isSVN;
+my $svnVersion;
+
+# Project time zone for Cupertino, CA, US
+my $changeLogTimeZone = "PST8PDT";
+
+my $unifiedDiffStartRegEx = qr#^--- ([abc]\/)?([^\r\n]+)#;
+my $gitDiffStartRegEx = qr#^diff --git [^\r\n]+#;
+my $gitDiffStartWithPrefixRegEx = qr#^diff --git \w/(.+) \w/([^\r\n]+)#; # We suppose that --src-prefix and --dst-prefix don't contain a non-word character (\W) and end with '/'.
+my $gitDiffStartWithoutPrefixNoSpaceRegEx = qr#^diff --git (\S+) (\S+)$#;
+my $svnDiffStartRegEx = qr#^Index: ([^\r\n]+)#;
+my $gitDiffStartWithoutPrefixSourceDirectoryPrefixRegExp = qr#^diff --git ([^/]+/)#;
+my $svnPropertiesStartRegEx = qr#^Property changes on: ([^\r\n]+)#; # $1 is normally the same as the index path.
+my $svnPropertyStartRegEx = qr#^(Modified|Name|Added|Deleted): ([^\r\n]+)#; # $2 is the name of the property.
+my $svnPropertyValueStartRegEx = qr#^\s*(\+|-|Merged|Reverse-merged)\s*([^\r\n]+)#; # $2 is the start of the property's value (which may span multiple lines).
+my $svnPropertyValueNoNewlineRegEx = qr#\ No newline at end of property#;
+
+# This method is for portability. Return the system-appropriate exit
+# status of a child process.
+#
+# Args: pass the child error status returned by the last pipe close,
+# for example "$?".
+sub exitStatus($)
+{
+ my ($returnvalue) = @_;
+ if (isWindows()) {
+ return $returnvalue >> 8;
+ }
+ if (!WIFEXITED($returnvalue)) {
+ return 254;
+ }
+ return WEXITSTATUS($returnvalue);
+}
+
+# Call a function while suppressing STDERR, and return the return values
+# as an array.
+sub callSilently($@) {
+ my ($func, @args) = @_;
+
+ # The following pattern was taken from here:
+ # http://www.sdsc.edu/~moreland/courses/IntroPerl/docs/manual/pod/perlfunc/open.html
+ #
+ # Also see this Perl documentation (search for "open OLDERR"):
+ # http://perldoc.perl.org/functions/open.html
+ open(OLDERR, ">&STDERR");
+ close(STDERR);
+ my @returnValue = &$func(@args);
+ open(STDERR, ">&OLDERR");
+ close(OLDERR);
+
+ return @returnValue;
+}
+
+sub toWindowsLineEndings
+{
+ my ($text) = @_;
+ $text =~ s/\n/\r\n/g;
+ return $text;
+}
+
+# Note, this method will not error if the file corresponding to the $source path does not exist.
+sub scmMoveOrRenameFile
+{
+ my ($source, $destination) = @_;
+ return if ! -e $source;
+ if (isSVN()) {
+ my $escapedDestination = escapeSubversionPath($destination);
+ my $escapedSource = escapeSubversionPath($source);
+ system("svn", "move", $escapedSource, $escapedDestination);
+ } elsif (isGit()) {
+ system("git", "mv", $source, $destination);
+ }
+}
+
+# Note, this method will not error if the file corresponding to the path does not exist.
+sub scmToggleExecutableBit
+{
+ my ($path, $executableBitDelta) = @_;
+ return if ! -e $path;
+ if ($executableBitDelta == 1) {
+ scmAddExecutableBit($path);
+ } elsif ($executableBitDelta == -1) {
+ scmRemoveExecutableBit($path);
+ }
+}
+
+sub scmAddExecutableBit($)
+{
+ my ($path) = @_;
+
+ if (isSVN()) {
+ my $escapedPath = escapeSubversionPath($path);
+ system("svn", "propset", "svn:executable", "on", $escapedPath) == 0 or die "Failed to run 'svn propset svn:executable on $escapedPath'.";
+ } elsif (isGit()) {
+ chmod(0755, $path);
+ }
+}
+
+sub scmRemoveExecutableBit($)
+{
+ my ($path) = @_;
+
+ if (isSVN()) {
+ my $escapedPath = escapeSubversionPath($path);
+ system("svn", "propdel", "svn:executable", $escapedPath) == 0 or die "Failed to run 'svn propdel svn:executable $escapedPath'.";
+ } elsif (isGit()) {
+ chmod(0664, $path);
+ }
+}
+
+sub isGitDirectory($)
+{
+ my ($dir) = @_;
+ return system("cd $dir && git rev-parse > " . File::Spec->devnull() . " 2>&1") == 0;
+}
+
+sub isGit()
+{
+ return $isGit if defined $isGit;
+
+ $isGit = isGitDirectory(".");
+ return $isGit;
+}
+
+sub isGitSVNDirectory($)
+{
+ my ($directory) = @_;
+
+ my $savedWorkingDirectory = Cwd::getcwd();
+ chdir($directory);
+
+ # There doesn't seem to be an officially documented way to determine
+ # if you're in a git-svn checkout. The best suggestions seen so far
+ # all use something like the following:
+ my $output = `git config --get svn-remote.svn.fetch 2>& 1`;
+ $isGitSVN = exitStatus($?) == 0 && $output ne "";
+ chdir($savedWorkingDirectory);
+ return $isGitSVN;
+}
+
+sub isGitSVN()
+{
+ return $isGitSVN if defined $isGitSVN;
+
+ $isGitSVN = isGitSVNDirectory(".");
+ return $isGitSVN;
+}
+
+sub gitDirectory()
+{
+ chomp(my $result = `git rev-parse --git-dir`);
+ return $result;
+}
+
+sub gitTreeDirectory()
+{
+ chomp(my $result = `git rev-parse --show-toplevel`);
+ return $result;
+}
+
+sub gitBisectStartBranch()
+{
+ my $bisectStartFile = File::Spec->catfile(gitDirectory(), "BISECT_START");
+ if (!-f $bisectStartFile) {
+ return "";
+ }
+ open(BISECT_START, $bisectStartFile) or die "Failed to open $bisectStartFile: $!";
+ chomp(my $result = <BISECT_START>);
+ close(BISECT_START);
+ return $result;
+}
+
+sub gitBranch()
+{
+ unless (defined $gitBranch) {
+ chomp($gitBranch = `git symbolic-ref -q HEAD`);
+ my $hasDetachedHead = exitStatus($?);
+ if ($hasDetachedHead) {
+ # We may be in a git bisect session.
+ $gitBranch = gitBisectStartBranch();
+ }
+ $gitBranch =~ s#^refs/heads/##;
+ $gitBranch = "" if $gitBranch eq "master";
+ }
+
+ return $gitBranch;
+}
+
+sub isGitBranchBuild()
+{
+ my $branch = gitBranch();
+ chomp(my $override = `git config --bool branch.$branch.webKitBranchBuild`);
+ return 1 if $override eq "true";
+ return 0 if $override eq "false";
+
+ unless (defined $isGitBranchBuild) {
+ chomp(my $gitBranchBuild = `git config --bool core.webKitBranchBuild`);
+ $isGitBranchBuild = $gitBranchBuild eq "true";
+ }
+
+ return $isGitBranchBuild;
+}
+
+sub isSVNDirectory($)
+{
+ my ($dir) = @_;
+ return system("cd $dir && svn info > " . File::Spec->devnull() . " 2>&1") == 0;
+}
+
+sub isSVN()
+{
+ return $isSVN if defined $isSVN;
+
+ $isSVN = isSVNDirectory(".");
+ return $isSVN;
+}
+
+sub svnVersion()
+{
+ return $svnVersion if defined $svnVersion;
+
+ if (!isSVN()) {
+ $svnVersion = 0;
+ } else {
+ chomp($svnVersion = `svn --version --quiet`);
+ }
+ return $svnVersion;
+}
+
+sub isSVNVersion16OrNewer()
+{
+ my $version = svnVersion();
+ return "v$version" ge v1.6;
+}
+
+sub chdirReturningRelativePath($)
+{
+ my ($directory) = @_;
+ my $previousDirectory = Cwd::getcwd();
+ chdir $directory;
+ my $newDirectory = Cwd::getcwd();
+ return "." if $newDirectory eq $previousDirectory;
+ return File::Spec->abs2rel($previousDirectory, $newDirectory);
+}
+
+sub determineSVNRoot()
+{
+ my $last = '';
+ my $path = '.';
+ my $parent = '..';
+ my $repositoryRoot;
+ my $repositoryUUID;
+ while (1) {
+ my $thisRoot;
+ my $thisUUID;
+ my $escapedPath = escapeSubversionPath($path);
+ # Ignore error messages in case we've run past the root of the checkout.
+ open INFO, "svn info '$escapedPath' 2> " . File::Spec->devnull() . " |" or die;
+ while (<INFO>) {
+ if (/^Repository Root: (.+)/) {
+ $thisRoot = $1;
+ }
+ if (/^Repository UUID: (.+)/) {
+ $thisUUID = $1;
+ }
+ if ($thisRoot && $thisUUID) {
+ local $/ = undef;
+ <INFO>; # Consume the rest of the input.
+ }
+ }
+ close INFO;
+
+ # It's possible (e.g. for developers of some ports) to have a WebKit
+ # checkout in a subdirectory of another checkout. So abort if the
+ # repository root or the repository UUID suddenly changes.
+ last if !$thisUUID;
+ $repositoryUUID = $thisUUID if !$repositoryUUID;
+ last if $thisUUID ne $repositoryUUID;
+
+ last if !$thisRoot;
+ $repositoryRoot = $thisRoot if !$repositoryRoot;
+ last if $thisRoot ne $repositoryRoot;
+
+ $last = $path;
+ $path = File::Spec->catdir($parent, $path);
+ }
+
+ return File::Spec->rel2abs($last);
+}
+
+sub determineVCSRoot()
+{
+ if (isGit()) {
+ # This is the working tree root. If WebKit is a submodule,
+ # then the relevant metadata directory is somewhere else.
+ return gitTreeDirectory();
+ }
+
+ if (!isSVN()) {
+ # Some users have a workflow where svn-create-patch, svn-apply and
+ # svn-unapply are used outside of multiple svn working directores,
+ # so warn the user and assume Subversion is being used in this case.
+ warn "Unable to determine VCS root for '" . Cwd::getcwd() . "'; assuming Subversion";
+ $isSVN = 1;
+ }
+
+ return determineSVNRoot();
+}
+
+sub isWindows()
+{
+ return ($^O eq "MSWin32") || 0;
+}
+
+sub svnRevisionForDirectory($)
+{
+ my ($dir) = @_;
+ my $revision;
+
+ if (isSVNDirectory($dir)) {
+ my $escapedDir = escapeSubversionPath($dir);
+ my $command = "svn info $escapedDir | grep Revision:";
+ $command = "LC_ALL=C $command" if !isWindows();
+ my $svnInfo = `$command`;
+ ($revision) = ($svnInfo =~ m/Revision: (\d+).*/g);
+ } elsif (isGitDirectory($dir)) {
+ my $command = "git log --grep=\"git-svn-id: \" -n 1 | grep git-svn-id:";
+ $command = "LC_ALL=C $command" if !isWindows();
+ $command = "cd $dir && $command";
+ my $gitLog = `$command`;
+ ($revision) = ($gitLog =~ m/ +git-svn-id: .+@(\d+) /g);
+ }
+ if (!defined($revision)) {
+ $revision = "unknown";
+ warn "Unable to determine current SVN revision in $dir";
+ }
+ return $revision;
+}
+
+sub svnInfoForPath($)
+{
+ my ($file) = @_;
+ my $relativePath = File::Spec->abs2rel($file);
+
+ my $svnInfo;
+ if (isSVNDirectory($file)) {
+ my $escapedRelativePath = escapeSubversionPath($relativePath);
+ my $command = "svn info $escapedRelativePath";
+ $command = "LC_ALL=C $command" if !isWindows();
+ $svnInfo = `$command`;
+ } elsif (isGitDirectory($file)) {
+ my $command = "git svn info";
+ $command = "LC_ALL=C $command" if !isWindows();
+ $svnInfo = `cd $relativePath && $command`;
+ }
+
+ return $svnInfo;
+}
+
+sub svnURLForPath($)
+{
+ my ($file) = @_;
+ my $svnInfo = svnInfoForPath($file);
+
+ $svnInfo =~ /.*^URL: (.*?)$/m;
+ return $1;
+}
+
+sub svnRepositoryRootForPath($)
+{
+ my ($file) = @_;
+ my $svnInfo = svnInfoForPath($file);
+
+ $svnInfo =~ /.*^Repository Root: (.*?)$/m;
+ return $1;
+}
+
+sub pathRelativeToSVNRepositoryRootForPath($)
+{
+ my ($file) = @_;
+
+ my $svnURL = svnURLForPath($file);
+ my $svnRepositoryRoot = svnRepositoryRootForPath($file);
+
+ $svnURL =~ s/$svnRepositoryRoot\///;
+ return $svnURL;
+}
+
+sub svnIdentifierForPath($)
+{
+ my ($file) = @_;
+ my $path = pathRelativeToSVNRepositoryRootForPath($file);
+
+ $path =~ /^(trunk)|tags\/([\w\.\-]*)|branches\/([\w\.\-]*).*$/m;
+ return $1 || $2 || $3;
+}
+
+sub makeFilePathRelative($)
+{
+ my ($path) = @_;
+ return $path unless isGit();
+
+ unless (defined $gitRoot) {
+ chomp($gitRoot = `git rev-parse --show-cdup`);
+ }
+ return $gitRoot . $path;
+}
+
+sub normalizePath($)
+{
+ my ($path) = @_;
+ if (isWindows()) {
+ $path =~ s/\//\\/g;
+ } else {
+ $path =~ s/\\/\//g;
+ }
+ return $path;
+}
+
+sub unixPath($)
+{
+ my ($path) = @_;
+ $path =~ s/\\/\//g;
+ return $path;
+}
+
+sub possiblyColored($$)
+{
+ my ($colors, $string) = @_;
+
+ if (-t STDOUT) {
+ return colored([$colors], $string);
+ } else {
+ return $string;
+ }
+}
+
+sub adjustPathForRecentRenamings($)
+{
+ my ($fullPath) = @_;
+
+ $fullPath =~ s|WebCore/webaudio|WebCore/Modules/webaudio|g;
+ $fullPath =~ s|JavaScriptCore/wtf|WTF/wtf|g;
+ $fullPath =~ s|test_expectations.txt|TestExpectations|g;
+
+ return $fullPath;
+}
+
+sub canonicalizePath($)
+{
+ my ($file) = @_;
+
+ # Remove extra slashes and '.' directories in path
+ $file = File::Spec->canonpath($file);
+
+ # Remove '..' directories in path
+ my @dirs = ();
+ foreach my $dir (File::Spec->splitdir($file)) {
+ if ($dir eq '..' && $#dirs >= 0 && $dirs[$#dirs] ne '..') {
+ pop(@dirs);
+ } else {
+ push(@dirs, $dir);
+ }
+ }
+ return ($#dirs >= 0) ? File::Spec->catdir(@dirs) : ".";
+}
+
+sub removeEOL($)
+{
+ my ($line) = @_;
+ return "" unless $line;
+
+ $line =~ s/[\r\n]+$//g;
+ return $line;
+}
+
+sub parseFirstEOL($)
+{
+ my ($fileHandle) = @_;
+
+ # Make input record separator the new-line character to simplify regex matching below.
+ my $savedInputRecordSeparator = $INPUT_RECORD_SEPARATOR;
+ $INPUT_RECORD_SEPARATOR = "\n";
+ my $firstLine = <$fileHandle>;
+ $INPUT_RECORD_SEPARATOR = $savedInputRecordSeparator;
+
+ return unless defined($firstLine);
+
+ my $eol;
+ if ($firstLine =~ /\r\n/) {
+ $eol = "\r\n";
+ } elsif ($firstLine =~ /\r/) {
+ $eol = "\r";
+ } elsif ($firstLine =~ /\n/) {
+ $eol = "\n";
+ }
+ return $eol;
+}
+
+sub firstEOLInFile($)
+{
+ my ($file) = @_;
+ my $eol;
+ if (open(FILE, $file)) {
+ $eol = parseFirstEOL(*FILE);
+ close(FILE);
+ }
+ return $eol;
+}
+
+# Parses a chunk range line into its components.
+#
+# A chunk range line has the form: @@ -L_1,N_1 +L_2,N_2 @@, where the pairs (L_1, N_1),
+# (L_2, N_2) are ranges that represent the starting line number and line count in the
+# original file and new file, respectively.
+#
+# Note, some versions of GNU diff may omit the comma and trailing line count (e.g. N_1),
+# in which case the omitted line count defaults to 1. For example, GNU diff may output
+# @@ -1 +1 @@, which is equivalent to @@ -1,1 +1,1 @@.
+#
+# This subroutine returns undef if given an invalid or malformed chunk range.
+#
+# Args:
+# $line: the line to parse.
+# $chunkSentinel: the sentinel that surrounds the chunk range information (defaults to "@@").
+#
+# Returns $chunkRangeHashRef
+# $chunkRangeHashRef: a hash reference representing the parts of a chunk range, as follows--
+# startingLine: the starting line in the original file.
+# lineCount: the line count in the original file.
+# newStartingLine: the new starting line in the new file.
+# newLineCount: the new line count in the new file.
+sub parseChunkRange($;$)
+{
+ my ($line, $chunkSentinel) = @_;
+ $chunkSentinel = "@@" if !$chunkSentinel;
+ my $chunkRangeRegEx = qr#^\Q$chunkSentinel\E -(\d+)(,(\d+))? \+(\d+)(,(\d+))? \Q$chunkSentinel\E#;
+ if ($line !~ /$chunkRangeRegEx/) {
+ return;
+ }
+ my %chunkRange;
+ $chunkRange{startingLine} = $1;
+ $chunkRange{lineCount} = defined($2) ? $3 : 1;
+ $chunkRange{newStartingLine} = $4;
+ $chunkRange{newLineCount} = defined($5) ? $6 : 1;
+ return \%chunkRange;
+}
+
+sub svnStatus($)
+{
+ my ($fullPath) = @_;
+ my $escapedFullPath = escapeSubversionPath($fullPath);
+ my $svnStatus;
+ open SVN, "svn status --non-interactive --non-recursive '$escapedFullPath' |" or die;
+ if (-d $fullPath) {
+ # When running "svn stat" on a directory, we can't assume that only one
+ # status will be returned (since any files with a status below the
+ # directory will be returned), and we can't assume that the directory will
+ # be first (since any files with unknown status will be listed first).
+ my $normalizedFullPath = File::Spec->catdir(File::Spec->splitdir($fullPath));
+ while (<SVN>) {
+ # Input may use a different EOL sequence than $/, so avoid chomp.
+ $_ = removeEOL($_);
+ my $normalizedStatPath = File::Spec->catdir(File::Spec->splitdir(substr($_, 7)));
+ if ($normalizedFullPath eq $normalizedStatPath) {
+ $svnStatus = "$_\n";
+ last;
+ }
+ }
+ # Read the rest of the svn command output to avoid a broken pipe warning.
+ local $/ = undef;
+ <SVN>;
+ }
+ else {
+ # Files will have only one status returned.
+ $svnStatus = removeEOL(<SVN>) . "\n";
+ }
+ close SVN;
+ return $svnStatus;
+}
+
+# Return whether the given file mode is executable in the source control
+# sense. We make this determination based on whether the executable bit
+# is set for "others" rather than the stronger condition that it be set
+# for the user, group, and others. This is sufficient for distinguishing
+# the default behavior in Git and SVN.
+#
+# Args:
+# $fileMode: A number or string representing a file mode in octal notation.
+sub isExecutable($)
+{
+ my $fileMode = shift;
+
+ return $fileMode % 2;
+}
+
+# Parses an SVN or Git diff header start line.
+#
+# Args:
+# $line: "Index: " line or "diff --git" line
+#
+# Returns the path of the target file or undef if the $line is unrecognized.
+sub parseDiffStartLine($)
+{
+ my ($line) = @_;
+ return $1 if $line =~ /$svnDiffStartRegEx/;
+ return parseGitDiffStartLine($line) if $line =~ /$gitDiffStartRegEx/;
+}
+
+# Parse the Git diff header start line.
+#
+# Args:
+# $line: "diff --git" line.
+#
+# Returns the path of the target file.
+sub parseGitDiffStartLine($)
+{
+ my $line = shift;
+ $_ = $line;
+ if (/$gitDiffStartWithPrefixRegEx/ || /$gitDiffStartWithoutPrefixNoSpaceRegEx/) {
+ return $2;
+ }
+ # Assume the diff was generated with --no-prefix (e.g. git diff --no-prefix).
+ if (!/$gitDiffStartWithoutPrefixSourceDirectoryPrefixRegExp/) {
+ # FIXME: Moving top directory file is not supported (e.g diff --git A.txt B.txt).
+ die("Could not find '/' in \"diff --git\" line: \"$line\"; only non-prefixed git diffs (i.e. not generated with --no-prefix) that move a top-level directory file are supported.");
+ }
+ my $pathPrefix = $1;
+ if (!/^diff --git \Q$pathPrefix\E.+ (\Q$pathPrefix\E.+)$/) {
+ # FIXME: Moving a file through sub directories of top directory is not supported (e.g diff --git A/B.txt C/B.txt).
+ die("Could not find '/' in \"diff --git\" line: \"$line\"; only non-prefixed git diffs (i.e. not generated with --no-prefix) that move a file between top-level directories are supported.");
+ }
+ return $1;
+}
+
+# Parse the next Git diff header from the given file handle, and advance
+# the handle so the last line read is the first line after the header.
+#
+# This subroutine dies if given leading junk.
+#
+# Args:
+# $fileHandle: advanced so the last line read from the handle is the first
+# line of the header to parse. This should be a line
+# beginning with "diff --git".
+# $line: the line last read from $fileHandle
+#
+# Returns ($headerHashRef, $lastReadLine):
+# $headerHashRef: a hash reference representing a diff header, as follows--
+# copiedFromPath: the path from which the file was copied or moved if
+# the diff is a copy or move.
+# executableBitDelta: the value 1 or -1 if the executable bit was added or
+# removed, respectively. New and deleted files have
+# this value only if the file is executable, in which
+# case the value is 1 and -1, respectively.
+# indexPath: the path of the target file.
+# isBinary: the value 1 if the diff is for a binary file.
+# isDeletion: the value 1 if the diff is a file deletion.
+# isCopyWithChanges: the value 1 if the file was copied or moved and
+# the target file was changed in some way after being
+# copied or moved (e.g. if its contents or executable
+# bit were changed).
+# isNew: the value 1 if the diff is for a new file.
+# shouldDeleteSource: the value 1 if the file was copied or moved and
+# the source file was deleted -- i.e. if the copy
+# was actually a move.
+# svnConvertedText: the header text with some lines converted to SVN
+# format. Git-specific lines are preserved.
+# $lastReadLine: the line last read from $fileHandle.
+sub parseGitDiffHeader($$)
+{
+ my ($fileHandle, $line) = @_;
+
+ $_ = $line;
+
+ my $indexPath;
+ if (/$gitDiffStartRegEx/) {
+ # Use $POSTMATCH to preserve the end-of-line character.
+ my $eol = $POSTMATCH;
+
+ # The first and second paths can differ in the case of copies
+ # and renames. We use the second file path because it is the
+ # destination path.
+ $indexPath = adjustPathForRecentRenamings(parseGitDiffStartLine($_));
+
+ $_ = "Index: $indexPath$eol"; # Convert to SVN format.
+ } else {
+ die("Could not parse leading \"diff --git\" line: \"$line\".");
+ }
+
+ my $copiedFromPath;
+ my $foundHeaderEnding;
+ my $isBinary;
+ my $isDeletion;
+ my $isNew;
+ my $newExecutableBit = 0;
+ my $oldExecutableBit = 0;
+ my $shouldDeleteSource = 0;
+ my $similarityIndex = 0;
+ my $svnConvertedText;
+ while (1) {
+ # Temporarily strip off any end-of-line characters to simplify
+ # regex matching below.
+ s/([\n\r]+)$//;
+ my $eol = $1;
+
+ if (/^(deleted file|old) mode (\d+)/) {
+ $oldExecutableBit = (isExecutable($2) ? 1 : 0);
+ $isDeletion = 1 if $1 eq "deleted file";
+ } elsif (/^new( file)? mode (\d+)/) {
+ $newExecutableBit = (isExecutable($2) ? 1 : 0);
+ $isNew = 1 if $1;
+ } elsif (/^similarity index (\d+)%/) {
+ $similarityIndex = $1;
+ } elsif (/^copy from ([^\t\r\n]+)/) {
+ $copiedFromPath = $1;
+ } elsif (/^rename from ([^\t\r\n]+)/) {
+ # FIXME: Record this as a move rather than as a copy-and-delete.
+ # This will simplify adding rename support to svn-unapply.
+ # Otherwise, the hash for a deletion would have to know
+ # everything about the file being deleted in order to
+ # support undoing itself. Recording as a move will also
+ # permit us to use "svn move" and "git move".
+ $copiedFromPath = $1;
+ $shouldDeleteSource = 1;
+ } elsif (/^--- \S+/) {
+ # Convert to SVN format.
+ # We emit the suffix "\t(revision 0)" to handle $indexPath which contains a space character.
+ # The patch(1) command thinks a file path is characters before a tab.
+ # This suffix make our diff more closely match the SVN diff format.
+ $_ = "--- $indexPath\t(revision 0)";
+ } elsif (/^\+\+\+ \S+/) {
+ # Convert to SVN format.
+ # We emit the suffix "\t(working copy)" to handle $indexPath which contains a space character.
+ # The patch(1) command thinks a file path is characters before a tab.
+ # This suffix make our diff more closely match the SVN diff format.
+ $_ = "+++ $indexPath\t(working copy)";
+ $foundHeaderEnding = 1;
+ } elsif (/^GIT binary patch$/ ) {
+ $isBinary = 1;
+ $foundHeaderEnding = 1;
+ # The "git diff" command includes a line of the form "Binary files
+ # <path1> and <path2> differ" if the --binary flag is not used.
+ } elsif (/^Binary files / ) {
+ die("Error: the Git diff contains a binary file without the binary data in ".
+ "line: \"$_\". Be sure to use the --binary flag when invoking \"git diff\" ".
+ "with diffs containing binary files.");
+ }
+
+ $svnConvertedText .= "$_$eol"; # Also restore end-of-line characters.
+
+ $_ = <$fileHandle>; # Not defined if end-of-file reached.
+
+ last if (!defined($_) || /$gitDiffStartRegEx/ || $foundHeaderEnding);
+ }
+
+ my $executableBitDelta = $newExecutableBit - $oldExecutableBit;
+
+ my %header;
+
+ $header{copiedFromPath} = $copiedFromPath if $copiedFromPath;
+ $header{executableBitDelta} = $executableBitDelta if $executableBitDelta;
+ $header{indexPath} = $indexPath;
+ $header{isBinary} = $isBinary if $isBinary;
+ $header{isCopyWithChanges} = 1 if ($copiedFromPath && ($similarityIndex != 100 || $executableBitDelta));
+ $header{isDeletion} = $isDeletion if $isDeletion;
+ $header{isNew} = $isNew if $isNew;
+ $header{shouldDeleteSource} = $shouldDeleteSource if $shouldDeleteSource;
+ $header{svnConvertedText} = $svnConvertedText;
+
+ return (\%header, $_);
+}
+
+# Parse the next SVN diff header from the given file handle, and advance
+# the handle so the last line read is the first line after the header.
+#
+# This subroutine dies if given leading junk or if it could not detect
+# the end of the header block.
+#
+# Args:
+# $fileHandle: advanced so the last line read from the handle is the first
+# line of the header to parse. This should be a line
+# beginning with "Index:".
+# $line: the line last read from $fileHandle
+#
+# Returns ($headerHashRef, $lastReadLine):
+# $headerHashRef: a hash reference representing a diff header, as follows--
+# copiedFromPath: the path from which the file was copied if the diff
+# is a copy.
+# indexPath: the path of the target file, which is the path found in
+# the "Index:" line.
+# isBinary: the value 1 if the diff is for a binary file.
+# isNew: the value 1 if the diff is for a new file.
+# sourceRevision: the revision number of the source, if it exists. This
+# is the same as the revision number the file was copied
+# from, in the case of a file copy.
+# svnConvertedText: the header text converted to a header with the paths
+# in some lines corrected.
+# $lastReadLine: the line last read from $fileHandle.
+sub parseSvnDiffHeader($$)
+{
+ my ($fileHandle, $line) = @_;
+
+ $_ = $line;
+
+ my $indexPath;
+ if (/$svnDiffStartRegEx/) {
+ $indexPath = adjustPathForRecentRenamings($1);
+ } else {
+ die("First line of SVN diff does not begin with \"Index \": \"$_\"");
+ }
+
+ my $copiedFromPath;
+ my $foundHeaderEnding;
+ my $isBinary;
+ my $isNew;
+ my $sourceRevision;
+ my $svnConvertedText;
+ while (1) {
+ # Temporarily strip off any end-of-line characters to simplify
+ # regex matching below.
+ s/([\n\r]+)$//;
+ my $eol = $1;
+
+ # Fix paths on "---" and "+++" lines to match the leading
+ # index line.
+ if (s/^--- [^\t\n\r]+/--- $indexPath/) {
+ # ---
+ if (/^--- .+\(revision (\d+)\)/) {
+ $sourceRevision = $1;
+ $isNew = 1 if !$sourceRevision; # if revision 0.
+ if (/\(from (\S+):(\d+)\)$/) {
+ # The "from" clause is created by svn-create-patch, in
+ # which case there is always also a "revision" clause.
+ $copiedFromPath = $1;
+ die("Revision number \"$2\" in \"from\" clause does not match " .
+ "source revision number \"$sourceRevision\".") if ($2 != $sourceRevision);
+ }
+ }
+ } elsif (s/^\+\+\+ [^\t\n\r]+/+++ $indexPath/ || $isBinary && /^$/) {
+ $foundHeaderEnding = 1;
+ } elsif (/^Cannot display: file marked as a binary type.$/) {
+ $isBinary = 1;
+ # SVN 1.7 has an unusual display format for a binary diff. It repeats the first
+ # two lines of the diff header. For example:
+ # Index: test_file.swf
+ # ===================================================================
+ # Cannot display: file marked as a binary type.
+ # svn:mime-type = application/octet-stream
+ # Index: test_file.swf
+ # ===================================================================
+ # --- test_file.swf
+ # +++ test_file.swf
+ #
+ # ...
+ # Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+ # Therefore, we continue reading the diff header until we either encounter a line
+ # that begins with "+++" (SVN 1.7 or greater) or an empty line (SVN version less
+ # than 1.7).
+ }
+
+ $svnConvertedText .= "$_$eol"; # Also restore end-of-line characters.
+
+ $_ = <$fileHandle>; # Not defined if end-of-file reached.
+
+ last if (!defined($_) || !$isBinary && /$svnDiffStartRegEx/ || $foundHeaderEnding);
+ }
+
+ if (!$foundHeaderEnding) {
+ die("Did not find end of header block corresponding to index path \"$indexPath\".");
+ }
+
+ my %header;
+
+ $header{copiedFromPath} = $copiedFromPath if $copiedFromPath;
+ $header{indexPath} = $indexPath;
+ $header{isBinary} = $isBinary if $isBinary;
+ $header{isNew} = $isNew if $isNew;
+ $header{sourceRevision} = $sourceRevision if $sourceRevision;
+ $header{svnConvertedText} = $svnConvertedText;
+
+ return (\%header, $_);
+}
+
+# Parse the next Unified diff header from the given file handle, and advance
+# the handle so the last line read is the first line after the header.
+#
+# This subroutine dies if given leading junk.
+#
+# Args:
+# $fileHandle: advanced so the last line read from the handle is the first
+# line of the header to parse. This should be a line
+# beginning with "Index:".
+# $line: the line last read from $fileHandle
+#
+# Returns ($headerHashRef, $lastReadLine):
+# $headerHashRef: a hash reference representing a diff header, as follows--
+# indexPath: the path of the target file, which is the path found in
+# the "Index:" line.
+# isNew: the value 1 if the diff is for a new file.
+# isDeletion: the value 1 if the diff is a file deletion.
+# svnConvertedText: the header text converted to a header with the paths
+# in some lines corrected.
+# $lastReadLine: the line last read from $fileHandle.
+sub parseUnifiedDiffHeader($$)
+{
+ my ($fileHandle, $line) = @_;
+
+ $_ = $line;
+
+ my $currentPosition = tell($fileHandle);
+ my $indexLine;
+ my $indexPath;
+ if (/$unifiedDiffStartRegEx/) {
+ # Use $POSTMATCH to preserve the end-of-line character.
+ my $eol = $POSTMATCH;
+
+ $indexPath = $2;
+
+ # In the case of an addition, we look at the next line for the index path
+ if ($indexPath eq "/dev/null") {
+ $_ = <$fileHandle>;
+ if (/^\+\+\+ ([abc]\/)?([^\t\n\r]+)/) {
+ $indexPath = $2;
+ } else {
+ die "Unrecognized unified diff format.";
+ }
+ $_ = $line;
+ }
+
+ $indexLine = "Index: $indexPath$eol"; # Convert to SVN format.
+ } else {
+ die("Could not parse leading \"---\" line: \"$line\".");
+ }
+
+ seek($fileHandle, $currentPosition, 0);
+
+ my $isDeletion;
+ my $isHeaderEnding;
+ my $isNew;
+ my $svnConvertedText = $indexLine;
+ while (1) {
+ # Temporarily strip off any end-of-line characters to simplify
+ # regex matching below.
+ s/([\n\r]+)$//;
+ my $eol = $1;
+
+ if (/^--- \/dev\/null/) {
+ $isNew = 1;
+ } elsif (/^\+\+\+ \/dev\/null/) {
+ $isDeletion = 1;
+ }
+
+ if (/^(---|\+\+\+) ([abc]\/)?([^\t\n\r]+)/) {
+ if ($1 eq "---") {
+ my $prependText = "";
+ $prependText = "new file mode 100644\n" if $isNew;
+ $_ = "${prependText}index 0000000..0000000\n$1 $3";
+ } else {
+ $_ = "$1 $3";
+ $isHeaderEnding = 1;
+ }
+ }
+
+ $svnConvertedText .= "$_$eol"; # Also restore end-of-line characters.
+
+ $currentPosition = tell($fileHandle);
+ $_ = <$fileHandle>; # Not defined if end-of-file reached.
+ last if (!defined($_) || /$unifiedDiffStartRegEx/ || $isHeaderEnding);
+ }
+
+ my %header;
+
+ $header{indexPath} = $indexPath;
+ $header{isDeletion} = $isDeletion if $isDeletion;
+ $header{isNew} = $isNew if $isNew;
+ $header{svnConvertedText} = $svnConvertedText;
+
+ return (\%header, $_);
+}
+
+# Parse the next diff header from the given file handle, and advance
+# the handle so the last line read is the first line after the header.
+#
+# This subroutine dies if given leading junk or if it could not detect
+# the end of the header block.
+#
+# Args:
+# $fileHandle: advanced so the last line read from the handle is the first
+# line of the header to parse. For SVN-formatted diffs, this
+# is a line beginning with "Index:". For Git, this is a line
+# beginning with "diff --git".
+# $line: the line last read from $fileHandle
+#
+# Returns ($headerHashRef, $lastReadLine):
+# $headerHashRef: a hash reference representing a diff header
+# copiedFromPath: the path from which the file was copied if the diff
+# is a copy.
+# executableBitDelta: the value 1 or -1 if the executable bit was added or
+# removed, respectively. New and deleted files have
+# this value only if the file is executable, in which
+# case the value is 1 and -1, respectively.
+# indexPath: the path of the target file.
+# isBinary: the value 1 if the diff is for a binary file.
+# isGit: the value 1 if the diff is Git-formatted.
+# isSvn: the value 1 if the diff is SVN-formatted.
+# sourceRevision: the revision number of the source, if it exists. This
+# is the same as the revision number the file was copied
+# from, in the case of a file copy.
+# svnConvertedText: the header text with some lines converted to SVN
+# format. Git-specific lines are preserved.
+# $lastReadLine: the line last read from $fileHandle.
+sub parseDiffHeader($$)
+{
+ my ($fileHandle, $line) = @_;
+
+ my $header; # This is a hash ref.
+ my $isGit;
+ my $isSvn;
+ my $isUnified;
+ my $lastReadLine;
+
+ if ($line =~ $svnDiffStartRegEx) {
+ $isSvn = 1;
+ ($header, $lastReadLine) = parseSvnDiffHeader($fileHandle, $line);
+ } elsif ($line =~ $gitDiffStartRegEx) {
+ $isGit = 1;
+ ($header, $lastReadLine) = parseGitDiffHeader($fileHandle, $line);
+ } elsif ($line =~ $unifiedDiffStartRegEx) {
+ $isUnified = 1;
+ ($header, $lastReadLine) = parseUnifiedDiffHeader($fileHandle, $line);
+ } else {
+ die("First line of diff does not begin with \"Index:\" or \"diff --git\": \"$line\"");
+ }
+
+ $header->{isGit} = $isGit if $isGit;
+ $header->{isSvn} = $isSvn if $isSvn;
+ $header->{isUnified} = $isUnified if $isUnified;
+
+ return ($header, $lastReadLine);
+}
+
+# FIXME: The %diffHash "object" should not have an svnConvertedText property.
+# Instead, the hash object should store its information in a
+# structured way as properties. This should be done in a way so
+# that, if necessary, the text of an SVN or Git patch can be
+# reconstructed from the information in those hash properties.
+#
+# A %diffHash is a hash representing a source control diff of a single
+# file operation (e.g. a file modification, copy, or delete).
+#
+# These hashes appear, for example, in the parseDiff(), parsePatch(),
+# and prepareParsedPatch() subroutines of this package.
+#
+# The corresponding values are--
+#
+# copiedFromPath: the path from which the file was copied if the diff
+# is a copy.
+# executableBitDelta: the value 1 or -1 if the executable bit was added or
+# removed from the target file, respectively.
+# indexPath: the path of the target file. For SVN-formatted diffs,
+# this is the same as the path in the "Index:" line.
+# isBinary: the value 1 if the diff is for a binary file.
+# isDeletion: the value 1 if the diff is known from the header to be a deletion.
+# isGit: the value 1 if the diff is Git-formatted.
+# isNew: the value 1 if the dif is known from the header to be a new file.
+# isSvn: the value 1 if the diff is SVN-formatted.
+# sourceRevision: the revision number of the source, if it exists. This
+# is the same as the revision number the file was copied
+# from, in the case of a file copy.
+# svnConvertedText: the diff with some lines converted to SVN format.
+# Git-specific lines are preserved.
+
+# Parse one diff from a patch file created by svn-create-patch, and
+# advance the file handle so the last line read is the first line
+# of the next header block.
+#
+# This subroutine preserves any leading junk encountered before the header.
+#
+# Composition of an SVN diff
+#
+# There are three parts to an SVN diff: the header, the property change, and
+# the binary contents, in that order. Either the header or the property change
+# may be ommitted, but not both. If there are binary changes, then you always
+# have all three.
+#
+# Args:
+# $fileHandle: a file handle advanced to the first line of the next
+# header block. Leading junk is okay.
+# $line: the line last read from $fileHandle.
+# $optionsHashRef: a hash reference representing optional options to use
+# when processing a diff.
+# shouldNotUseIndexPathEOL: whether to use the line endings in the diff instead
+# instead of the line endings in the target file; the
+# value of 1 if svnConvertedText should use the line
+# endings in the diff.
+#
+# Returns ($diffHashRefs, $lastReadLine):
+# $diffHashRefs: A reference to an array of references to %diffHash hashes.
+# See the %diffHash documentation above.
+# $lastReadLine: the line last read from $fileHandle
+sub parseDiff($$;$)
+{
+ # FIXME: Adjust this method so that it dies if the first line does not
+ # match the start of a diff. This will require a change to
+ # parsePatch() so that parsePatch() skips over leading junk.
+ my ($fileHandle, $line, $optionsHashRef) = @_;
+
+ my $headerStartRegEx = $svnDiffStartRegEx; # SVN-style header for the default
+
+ my $headerHashRef; # Last header found, as returned by parseDiffHeader().
+ my $svnPropertiesHashRef; # Last SVN properties diff found, as returned by parseSvnDiffProperties().
+ my $svnText;
+ my $indexPathEOL;
+ my $numTextChunks = 0;
+ while (defined($line)) {
+ if (!$headerHashRef && ($line =~ $gitDiffStartRegEx)) {
+ # Then assume all diffs in the patch are Git-formatted. This
+ # block was made to be enterable at most once since we assume
+ # all diffs in the patch are formatted the same (SVN or Git).
+ $headerStartRegEx = $gitDiffStartRegEx;
+ }
+
+ if (!$headerHashRef && ($line =~ $unifiedDiffStartRegEx)) {
+ $headerStartRegEx = $unifiedDiffStartRegEx;
+ }
+
+ if ($line =~ $svnPropertiesStartRegEx) {
+ my $propertyPath = $1;
+ if ($svnPropertiesHashRef || $headerHashRef && ($propertyPath ne $headerHashRef->{indexPath})) {
+ # This is the start of the second diff in the while loop, which happens to
+ # be a property diff. If $svnPropertiesHasRef is defined, then this is the
+ # second consecutive property diff, otherwise it's the start of a property
+ # diff for a file that only has property changes.
+ last;
+ }
+ ($svnPropertiesHashRef, $line) = parseSvnDiffProperties($fileHandle, $line);
+ next;
+ }
+ if ($line !~ $headerStartRegEx) {
+ # Then we are in the body of the diff.
+ my $isChunkRange = defined(parseChunkRange($line));
+ $numTextChunks += 1 if $isChunkRange;
+ my $nextLine = <$fileHandle>;
+ my $willAddNewLineAtEndOfFile = defined($nextLine) && $nextLine =~ /^\\ No newline at end of file$/;
+ if ($willAddNewLineAtEndOfFile) {
+ # Diff(1) always emits a LF character preceeding the line "\ No newline at end of file".
+ # We must preserve both the added LF character and the line ending of this sentinel line
+ # or patch(1) will complain.
+ $svnText .= $line . $nextLine;
+ $line = <$fileHandle>;
+ next;
+ }
+ if ($indexPathEOL && !$isChunkRange) {
+ # The chunk range is part of the body of the diff, but its line endings should't be
+ # modified or patch(1) will complain. So, we only modify non-chunk range lines.
+ $line =~ s/\r\n|\r|\n/$indexPathEOL/g;
+ }
+ $svnText .= $line;
+ $line = $nextLine;
+ next;
+ } # Otherwise, we found a diff header.
+
+ if ($svnPropertiesHashRef || $headerHashRef) {
+ # Then either we just processed an SVN property change or this
+ # is the start of the second diff header of this while loop.
+ last;
+ }
+
+ ($headerHashRef, $line) = parseDiffHeader($fileHandle, $line);
+ if (!$optionsHashRef || !$optionsHashRef->{shouldNotUseIndexPathEOL}) {
+ # FIXME: We shouldn't query the file system (via firstEOLInFile()) to determine the
+ # line endings of the file indexPath. Instead, either the caller to parseDiff()
+ # should provide this information or parseDiff() should take a delegate that it
+ # can use to query for this information.
+ $indexPathEOL = firstEOLInFile($headerHashRef->{indexPath}) if !$headerHashRef->{isNew} && !$headerHashRef->{isBinary};
+ }
+
+ $svnText .= $headerHashRef->{svnConvertedText};
+ }
+
+ my @diffHashRefs;
+
+ if ($headerHashRef->{shouldDeleteSource}) {
+ my %deletionHash;
+ $deletionHash{indexPath} = $headerHashRef->{copiedFromPath};
+ $deletionHash{isDeletion} = 1;
+ push @diffHashRefs, \%deletionHash;
+ }
+ if ($headerHashRef->{copiedFromPath}) {
+ my %copyHash;
+ $copyHash{copiedFromPath} = $headerHashRef->{copiedFromPath};
+ $copyHash{indexPath} = $headerHashRef->{indexPath};
+ $copyHash{sourceRevision} = $headerHashRef->{sourceRevision} if $headerHashRef->{sourceRevision};
+ if ($headerHashRef->{isSvn}) {
+ $copyHash{executableBitDelta} = $svnPropertiesHashRef->{executableBitDelta} if $svnPropertiesHashRef->{executableBitDelta};
+ }
+ push @diffHashRefs, \%copyHash;
+ }
+
+ # Note, the order of evaluation for the following if conditional has been explicitly chosen so that
+ # it evaluates to false when there is no headerHashRef (e.g. a property change diff for a file that
+ # only has property changes).
+ if ($headerHashRef->{isCopyWithChanges} || (%$headerHashRef && !$headerHashRef->{copiedFromPath})) {
+ # Then add the usual file modification.
+ my %diffHash;
+ # FIXME: We should expand this code to support other properties. In the future,
+ # parseSvnDiffProperties may return a hash whose keys are the properties.
+ if ($headerHashRef->{isSvn}) {
+ # SVN records the change to the executable bit in a separate property change diff
+ # that follows the contents of the diff, except for binary diffs. For binary
+ # diffs, the property change diff follows the diff header.
+ $diffHash{executableBitDelta} = $svnPropertiesHashRef->{executableBitDelta} if $svnPropertiesHashRef->{executableBitDelta};
+ } elsif ($headerHashRef->{isGit}) {
+ # Git records the change to the executable bit in the header of a diff.
+ $diffHash{executableBitDelta} = $headerHashRef->{executableBitDelta} if $headerHashRef->{executableBitDelta};
+ }
+ $diffHash{indexPath} = $headerHashRef->{indexPath};
+ $diffHash{isBinary} = $headerHashRef->{isBinary} if $headerHashRef->{isBinary};
+ $diffHash{isDeletion} = $headerHashRef->{isDeletion} if $headerHashRef->{isDeletion};
+ $diffHash{isGit} = $headerHashRef->{isGit} if $headerHashRef->{isGit};
+ $diffHash{isNew} = $headerHashRef->{isNew} if $headerHashRef->{isNew};
+ $diffHash{isSvn} = $headerHashRef->{isSvn} if $headerHashRef->{isSvn};
+ if (!$headerHashRef->{copiedFromPath}) {
+ # If the file was copied, then we have already incorporated the
+ # sourceRevision information into the change.
+ $diffHash{sourceRevision} = $headerHashRef->{sourceRevision} if $headerHashRef->{sourceRevision};
+ }
+ # FIXME: Remove the need for svnConvertedText. See the %diffHash
+ # code comments above for more information.
+ #
+ # Note, we may not always have SVN converted text since we intend
+ # to deprecate it in the future. For example, a property change
+ # diff for a file that only has property changes will not return
+ # any SVN converted text.
+ $diffHash{svnConvertedText} = $svnText if $svnText;
+ $diffHash{numTextChunks} = $numTextChunks if $svnText && !$headerHashRef->{isBinary};
+ push @diffHashRefs, \%diffHash;
+ }
+
+ if (!%$headerHashRef && $svnPropertiesHashRef) {
+ # A property change diff for a file that only has property changes.
+ my %propertyChangeHash;
+ $propertyChangeHash{executableBitDelta} = $svnPropertiesHashRef->{executableBitDelta} if $svnPropertiesHashRef->{executableBitDelta};
+ $propertyChangeHash{indexPath} = $svnPropertiesHashRef->{propertyPath};
+ $propertyChangeHash{isSvn} = 1;
+ push @diffHashRefs, \%propertyChangeHash;
+ }
+
+ return (\@diffHashRefs, $line);
+}
+
+# Parse an SVN property change diff from the given file handle, and advance
+# the handle so the last line read is the first line after this diff.
+#
+# For the case of an SVN binary diff, the binary contents will follow the
+# the property changes.
+#
+# This subroutine dies if the first line does not begin with "Property changes on"
+# or if the separator line that follows this line is missing.
+#
+# Args:
+# $fileHandle: advanced so the last line read from the handle is the first
+# line of the footer to parse. This line begins with
+# "Property changes on".
+# $line: the line last read from $fileHandle.
+#
+# Returns ($propertyHashRef, $lastReadLine):
+# $propertyHashRef: a hash reference representing an SVN diff footer.
+# propertyPath: the path of the target file.
+# executableBitDelta: the value 1 or -1 if the executable bit was added or
+# removed from the target file, respectively.
+# $lastReadLine: the line last read from $fileHandle.
+sub parseSvnDiffProperties($$)
+{
+ my ($fileHandle, $line) = @_;
+
+ $_ = $line;
+
+ my %footer;
+ if (/$svnPropertiesStartRegEx/) {
+ $footer{propertyPath} = $1;
+ } else {
+ die("Failed to find start of SVN property change, \"Property changes on \": \"$_\"");
+ }
+
+ # We advance $fileHandle two lines so that the next line that
+ # we process is $svnPropertyStartRegEx in a well-formed footer.
+ # A well-formed footer has the form:
+ # Property changes on: FileA
+ # ___________________________________________________________________
+ # Added: svn:executable
+ # + *
+ $_ = <$fileHandle>; # Not defined if end-of-file reached.
+ my $separator = "_" x 67;
+ if (defined($_) && /^$separator[\r\n]+$/) {
+ $_ = <$fileHandle>;
+ } else {
+ die("Failed to find separator line: \"$_\".");
+ }
+
+ # FIXME: We should expand this to support other SVN properties
+ # (e.g. return a hash of property key-values that represents
+ # all properties).
+ #
+ # Notice, we keep processing until we hit end-of-file or some
+ # line that does not resemble $svnPropertyStartRegEx, such as
+ # the empty line that precedes the start of the binary contents
+ # of a patch, or the start of the next diff (e.g. "Index:").
+ my $propertyHashRef;
+ while (defined($_) && /$svnPropertyStartRegEx/) {
+ ($propertyHashRef, $_) = parseSvnProperty($fileHandle, $_);
+ if ($propertyHashRef->{name} eq "svn:executable") {
+ # Notice, for SVN properties, propertyChangeDelta is always non-zero
+ # because a property can only be added or removed.
+ $footer{executableBitDelta} = $propertyHashRef->{propertyChangeDelta};
+ }
+ }
+
+ return(\%footer, $_);
+}
+
+# Parse the next SVN property from the given file handle, and advance the handle so the last
+# line read is the first line after the property.
+#
+# This subroutine dies if the first line is not a valid start of an SVN property,
+# or the property is missing a value, or the property change type (e.g. "Added")
+# does not correspond to the property value type (e.g. "+").
+#
+# Args:
+# $fileHandle: advanced so the last line read from the handle is the first
+# line of the property to parse. This should be a line
+# that matches $svnPropertyStartRegEx.
+# $line: the line last read from $fileHandle.
+#
+# Returns ($propertyHashRef, $lastReadLine):
+# $propertyHashRef: a hash reference representing a SVN property.
+# name: the name of the property.
+# value: the last property value. For instance, suppose the property is "Modified".
+# Then it has both a '-' and '+' property value in that order. Therefore,
+# the value of this key is the value of the '+' property by ordering (since
+# it is the last value).
+# propertyChangeDelta: the value 1 or -1 if the property was added or
+# removed, respectively.
+# $lastReadLine: the line last read from $fileHandle.
+sub parseSvnProperty($$)
+{
+ my ($fileHandle, $line) = @_;
+
+ $_ = $line;
+
+ my $propertyName;
+ my $propertyChangeType;
+ if (/$svnPropertyStartRegEx/) {
+ $propertyChangeType = $1;
+ $propertyName = $2;
+ } else {
+ die("Failed to find SVN property: \"$_\".");
+ }
+
+ $_ = <$fileHandle>; # Not defined if end-of-file reached.
+
+ if (defined($_) && defined(parseChunkRange($_, "##"))) {
+ # FIXME: We should validate the chunk range line that is part of an SVN 1.7
+ # property diff. For now, we ignore this line.
+ $_ = <$fileHandle>;
+ }
+
+ # The "svn diff" command neither inserts newline characters between property values
+ # nor between successive properties.
+ #
+ # As of SVN 1.7, "svn diff" may insert "\ No newline at end of property" after a
+ # property value that doesn't end in a newline.
+ #
+ # FIXME: We do not support property values that contain tailing newline characters
+ # as it is difficult to disambiguate these trailing newlines from the empty
+ # line that precedes the contents of a binary patch.
+ my $propertyValue;
+ my $propertyValueType;
+ while (defined($_) && /$svnPropertyValueStartRegEx/) {
+ # Note, a '-' property may be followed by a '+' property in the case of a "Modified"
+ # or "Name" property. We only care about the ending value (i.e. the '+' property)
+ # in such circumstances. So, we take the property value for the property to be its
+ # last parsed property value.
+ #
+ # FIXME: We may want to consider strictly enforcing a '-', '+' property ordering or
+ # add error checking to prevent '+', '+', ..., '+' and other invalid combinations.
+ $propertyValueType = $1;
+ ($propertyValue, $_) = parseSvnPropertyValue($fileHandle, $_);
+ $_ = <$fileHandle> if defined($_) && /$svnPropertyValueNoNewlineRegEx/;
+ }
+
+ if (!$propertyValue) {
+ die("Failed to find the property value for the SVN property \"$propertyName\": \"$_\".");
+ }
+
+ my $propertyChangeDelta;
+ if ($propertyValueType eq "+" || $propertyValueType eq "Merged") {
+ $propertyChangeDelta = 1;
+ } elsif ($propertyValueType eq "-" || $propertyValueType eq "Reverse-merged") {
+ $propertyChangeDelta = -1;
+ } else {
+ die("Not reached.");
+ }
+
+ # We perform a simple validation that an "Added" or "Deleted" property
+ # change type corresponds with a "+" and "-" value type, respectively.
+ my $expectedChangeDelta;
+ if ($propertyChangeType eq "Added") {
+ $expectedChangeDelta = 1;
+ } elsif ($propertyChangeType eq "Deleted") {
+ $expectedChangeDelta = -1;
+ }
+
+ if ($expectedChangeDelta && $propertyChangeDelta != $expectedChangeDelta) {
+ die("The final property value type found \"$propertyValueType\" does not " .
+ "correspond to the property change type found \"$propertyChangeType\".");
+ }
+
+ my %propertyHash;
+ $propertyHash{name} = $propertyName;
+ $propertyHash{propertyChangeDelta} = $propertyChangeDelta;
+ $propertyHash{value} = $propertyValue;
+ return (\%propertyHash, $_);
+}
+
+# Parse the value of an SVN property from the given file handle, and advance
+# the handle so the last line read is the first line after the property value.
+#
+# This subroutine dies if the first line is an invalid SVN property value line
+# (i.e. a line that does not begin with " +" or " -").
+#
+# Args:
+# $fileHandle: advanced so the last line read from the handle is the first
+# line of the property value to parse. This should be a line
+# beginning with " +" or " -".
+# $line: the line last read from $fileHandle.
+#
+# Returns ($propertyValue, $lastReadLine):
+# $propertyValue: the value of the property.
+# $lastReadLine: the line last read from $fileHandle.
+sub parseSvnPropertyValue($$)
+{
+ my ($fileHandle, $line) = @_;
+
+ $_ = $line;
+
+ my $propertyValue;
+ my $eol;
+ if (/$svnPropertyValueStartRegEx/) {
+ $propertyValue = $2; # Does not include the end-of-line character(s).
+ $eol = $POSTMATCH;
+ } else {
+ die("Failed to find property value beginning with '+', '-', 'Merged', or 'Reverse-merged': \"$_\".");
+ }
+
+ while (<$fileHandle>) {
+ if (/^[\r\n]+$/ || /$svnPropertyValueStartRegEx/ || /$svnPropertyStartRegEx/ || /$svnPropertyValueNoNewlineRegEx/ || /$svnDiffStartRegEx/) {
+ # Note, we may encounter an empty line before the contents of a binary patch.
+ # Also, we check for $svnPropertyValueStartRegEx because a '-' property may be
+ # followed by a '+' property in the case of a "Modified" or "Name" property.
+ # We check for $svnPropertyStartRegEx because it indicates the start of the
+ # next property to parse.
+ last;
+ }
+
+ # Temporarily strip off any end-of-line characters. We add the end-of-line characters
+ # from the previously processed line to the start of this line so that the last line
+ # of the property value does not end in end-of-line characters.
+ s/([\n\r]+)$//;
+ $propertyValue .= "$eol$_";
+ $eol = $1;
+ }
+
+ return ($propertyValue, $_);
+}
+
+# Parse a patch file created by svn-create-patch.
+#
+# Args:
+# $fileHandle: A file handle to the patch file that has not yet been
+# read from.
+# $optionsHashRef: a hash reference representing optional options to use
+# when processing a diff.
+# shouldNotUseIndexPathEOL: whether to use the line endings in the diff instead
+# instead of the line endings in the target file; the
+# value of 1 if svnConvertedText should use the line
+# endings in the diff.
+#
+# Returns:
+# @diffHashRefs: an array of diff hash references.
+# See the %diffHash documentation above.
+sub parsePatch($;$)
+{
+ my ($fileHandle, $optionsHashRef) = @_;
+
+ my $newDiffHashRefs;
+ my @diffHashRefs; # return value
+
+ my $line = <$fileHandle>;
+
+ while (defined($line)) { # Otherwise, at EOF.
+
+ ($newDiffHashRefs, $line) = parseDiff($fileHandle, $line, $optionsHashRef);
+
+ push @diffHashRefs, @$newDiffHashRefs;
+ }
+
+ return @diffHashRefs;
+}
+
+# Prepare the results of parsePatch() for use in svn-apply and svn-unapply.
+#
+# Args:
+# $shouldForce: Whether to continue processing if an unexpected
+# state occurs.
+# @diffHashRefs: An array of references to %diffHashes.
+# See the %diffHash documentation above.
+#
+# Returns $preparedPatchHashRef:
+# copyDiffHashRefs: A reference to an array of the $diffHashRefs in
+# @diffHashRefs that represent file copies. The original
+# ordering is preserved.
+# nonCopyDiffHashRefs: A reference to an array of the $diffHashRefs in
+# @diffHashRefs that do not represent file copies.
+# The original ordering is preserved.
+# sourceRevisionHash: A reference to a hash of source path to source
+# revision number.
+sub prepareParsedPatch($@)
+{
+ my ($shouldForce, @diffHashRefs) = @_;
+
+ my %copiedFiles;
+
+ # Return values
+ my @copyDiffHashRefs = ();
+ my @nonCopyDiffHashRefs = ();
+ my %sourceRevisionHash = ();
+ for my $diffHashRef (@diffHashRefs) {
+ my $copiedFromPath = $diffHashRef->{copiedFromPath};
+ my $indexPath = $diffHashRef->{indexPath};
+ my $sourceRevision = $diffHashRef->{sourceRevision};
+ my $sourcePath;
+
+ if (defined($copiedFromPath)) {
+ # Then the diff is a copy operation.
+ $sourcePath = $copiedFromPath;
+
+ # FIXME: Consider printing a warning or exiting if
+ # exists($copiedFiles{$indexPath}) is true -- i.e. if
+ # $indexPath appears twice as a copy target.
+ $copiedFiles{$indexPath} = $sourcePath;
+
+ push @copyDiffHashRefs, $diffHashRef;
+ } else {
+ # Then the diff is not a copy operation.
+ $sourcePath = $indexPath;
+
+ push @nonCopyDiffHashRefs, $diffHashRef;
+ }
+
+ if (defined($sourceRevision)) {
+ if (exists($sourceRevisionHash{$sourcePath}) &&
+ ($sourceRevisionHash{$sourcePath} != $sourceRevision)) {
+ if (!$shouldForce) {
+ die "Two revisions of the same file required as a source:\n".
+ " $sourcePath:$sourceRevisionHash{$sourcePath}\n".
+ " $sourcePath:$sourceRevision";
+ }
+ }
+ $sourceRevisionHash{$sourcePath} = $sourceRevision;
+ }
+ }
+
+ my %preparedPatchHash;
+
+ $preparedPatchHash{copyDiffHashRefs} = \@copyDiffHashRefs;
+ $preparedPatchHash{nonCopyDiffHashRefs} = \@nonCopyDiffHashRefs;
+ $preparedPatchHash{sourceRevisionHash} = \%sourceRevisionHash;
+
+ return \%preparedPatchHash;
+}
+
+# Return localtime() for the project's time zone, given an integer time as
+# returned by Perl's time() function.
+sub localTimeInProjectTimeZone($)
+{
+ my $epochTime = shift;
+
+ # Change the time zone temporarily for the localtime() call.
+ my $savedTimeZone = $ENV{'TZ'};
+ $ENV{'TZ'} = $changeLogTimeZone;
+ my @localTime = localtime($epochTime);
+ if (defined $savedTimeZone) {
+ $ENV{'TZ'} = $savedTimeZone;
+ } else {
+ delete $ENV{'TZ'};
+ }
+
+ return @localTime;
+}
+
+# Set the reviewer and date in a ChangeLog patch, and return the new patch.
+#
+# Args:
+# $patch: a ChangeLog patch as a string.
+# $reviewer: the name of the reviewer, or undef if the reviewer should not be set.
+# $epochTime: an integer time as returned by Perl's time() function.
+sub setChangeLogDateAndReviewer($$$)
+{
+ my ($patch, $reviewer, $epochTime) = @_;
+
+ my @localTime = localTimeInProjectTimeZone($epochTime);
+ my $newDate = strftime("%Y-%m-%d", @localTime);
+
+ my $firstChangeLogLineRegEx = qr#(\n\+)\d{4}-[^-]{2}-[^-]{2}( )#;
+ $patch =~ s/$firstChangeLogLineRegEx/$1$newDate$2/;
+
+ if (defined($reviewer)) {
+ # We include a leading plus ("+") in the regular expression to make
+ # the regular expression less likely to match text in the leading junk
+ # for the patch, if the patch has leading junk.
+ $patch =~ s/(\n\+.*)NOBODY \(OOPS!\)/$1$reviewer/;
+ }
+
+ return $patch;
+}
+
+# Removes a leading Subversion header without an associated diff if one exists.
+#
+# This subroutine dies if the specified patch does not begin with an "Index:" line.
+#
+# In SVN 1.9 or newer, "svn diff" of a moved/copied file without post changes always
+# emits a leading header without an associated diff:
+# Index: B.txt
+# ===================================================================
+# (end of file or next header)
+#
+# If the same file has a property change then the patch has the form:
+# Index: B.txt
+# ===================================================================
+# Index: B.txt
+# ===================================================================
+# --- B.txt (revision 1)
+# +++ B.txt (working copy)
+#
+# Property change on B.txt
+# ___________________________________________________________________
+# Added: svn:executable
+# ## -0,0 +1 ##
+# +*
+# \ No newline at end of property
+#
+# We need to apply this function to the ouput of "svn diff" for an addition with history
+# to remove a duplicate header so that svn-apply can apply the resulting patch.
+sub fixSVNPatchForAdditionWithHistory($)
+{
+ my ($patch) = @_;
+
+ $patch =~ /(\r?\n)/;
+ my $lineEnding = $1;
+ my @lines = split(/$lineEnding/, $patch);
+
+ if ($lines[0] !~ /$svnDiffStartRegEx/) {
+ die("First line of SVN diff does not begin with \"Index \": \"$lines[0]\"");
+ }
+ if (@lines <= 2) {
+ return "";
+ }
+ splice(@lines, 0, 2) if $lines[2] =~ /$svnDiffStartRegEx/;
+ return join($lineEnding, @lines) . "\n"; # patch(1) expects an extra trailing newline.
+}
+
+# If possible, returns a ChangeLog patch equivalent to the given one,
+# but with the newest ChangeLog entry inserted at the top of the
+# file -- i.e. no leading context and all lines starting with "+".
+#
+# If given a patch string not representable as a patch with the above
+# properties, it returns the input back unchanged.
+#
+# WARNING: This subroutine can return an inequivalent patch string if
+# both the beginning of the new ChangeLog file matches the beginning
+# of the source ChangeLog, and the source beginning was modified.
+# Otherwise, it is guaranteed to return an equivalent patch string,
+# if it returns.
+#
+# Applying this subroutine to ChangeLog patches allows svn-apply to
+# insert new ChangeLog entries at the top of the ChangeLog file.
+# svn-apply uses patch with --fuzz=3 to do this. We need to apply
+# this subroutine because the diff(1) command is greedy when matching
+# lines. A new ChangeLog entry with the same date and author as the
+# previous will match and cause the diff to have lines of starting
+# context.
+#
+# This subroutine has unit tests in VCSUtils_unittest.pl.
+#
+# Returns $changeLogHashRef:
+# $changeLogHashRef: a hash reference representing a change log patch.
+# patch: a ChangeLog patch equivalent to the given one, but with the
+# newest ChangeLog entry inserted at the top of the file, if possible.
+sub fixChangeLogPatch($)
+{
+ my $patch = shift; # $patch will only contain patch fragments for ChangeLog.
+
+ $patch =~ s|test_expectations.txt:|TestExpectations:|g;
+
+ $patch =~ /(\r?\n)/;
+ my $lineEnding = $1;
+ my @lines = split(/$lineEnding/, $patch);
+
+ my $i = 0; # We reuse the same index throughout.
+
+ # Skip to beginning of first chunk.
+ for (; $i < @lines; ++$i) {
+ if (substr($lines[$i], 0, 1) eq "@") {
+ last;
+ }
+ }
+ my $chunkStartIndex = ++$i;
+ my %changeLogHashRef;
+
+ # Optimization: do not process if new lines already begin the chunk.
+ if (substr($lines[$i], 0, 1) eq "+") {
+ $changeLogHashRef{patch} = $patch;
+ return \%changeLogHashRef;
+ }
+
+ # Skip to first line of newly added ChangeLog entry.
+ # For example, +2009-06-03 Eric Seidel <eric@webkit.org>
+ my $dateStartRegEx = '^\+(\d{4}-\d{2}-\d{2})' # leading "+" and date
+ . '\s+(.+)\s+' # name
+ . '<([^<>]+)>$'; # e-mail address
+
+ for (; $i < @lines; ++$i) {
+ my $line = $lines[$i];
+ my $firstChar = substr($line, 0, 1);
+ if ($line =~ /$dateStartRegEx/) {
+ last;
+ } elsif ($firstChar eq " " or $firstChar eq "+") {
+ next;
+ }
+ $changeLogHashRef{patch} = $patch; # Do not change if, for example, "-" or "@" found.
+ return \%changeLogHashRef;
+ }
+ if ($i >= @lines) {
+ $changeLogHashRef{patch} = $patch; # Do not change if date not found.
+ return \%changeLogHashRef;
+ }
+ my $dateStartIndex = $i;
+
+ # Rewrite overlapping lines to lead with " ".
+ my @overlappingLines = (); # These will include a leading "+".
+ for (; $i < @lines; ++$i) {
+ my $line = $lines[$i];
+ if (substr($line, 0, 1) ne "+") {
+ last;
+ }
+ push(@overlappingLines, $line);
+ $lines[$i] = " " . substr($line, 1);
+ }
+
+ # Remove excess ending context, if necessary.
+ my $shouldTrimContext = 1;
+ for (; $i < @lines; ++$i) {
+ my $firstChar = substr($lines[$i], 0, 1);
+ if ($firstChar eq " ") {
+ next;
+ } elsif ($firstChar eq "@") {
+ last;
+ }
+ $shouldTrimContext = 0; # For example, if "+" or "-" encountered.
+ last;
+ }
+ my $deletedLineCount = 0;
+ if ($shouldTrimContext) { # Also occurs if end of file reached.
+ splice(@lines, $i - @overlappingLines, @overlappingLines);
+ $deletedLineCount = @overlappingLines;
+ }
+
+ # Work backwards, shifting overlapping lines towards front
+ # while checking that patch stays equivalent.
+ for ($i = $dateStartIndex - 1; @overlappingLines && $i >= $chunkStartIndex; --$i) {
+ my $line = $lines[$i];
+ if (substr($line, 0, 1) ne " ") {
+ next;
+ }
+ my $text = substr($line, 1);
+ my $newLine = pop(@overlappingLines);
+ if ($text ne substr($newLine, 1)) {
+ $changeLogHashRef{patch} = $patch; # Unexpected difference.
+ return \%changeLogHashRef;
+ }
+ $lines[$i] = "+$text";
+ }
+
+ # If @overlappingLines > 0, this is where we make use of the
+ # assumption that the beginning of the source file was not modified.
+ splice(@lines, $chunkStartIndex, 0, @overlappingLines);
+
+ # Update the date start index as it may have changed after shifting
+ # the overlapping lines towards the front.
+ for ($i = $chunkStartIndex; $i < $dateStartIndex; ++$i) {
+ $dateStartIndex = $i if $lines[$i] =~ /$dateStartRegEx/;
+ }
+ splice(@lines, $chunkStartIndex, $dateStartIndex - $chunkStartIndex); # Remove context of later entry.
+ $deletedLineCount += $dateStartIndex - $chunkStartIndex;
+
+ # Update the initial chunk range.
+ my $chunkRangeHashRef = parseChunkRange($lines[$chunkStartIndex - 1]);
+ if (!$chunkRangeHashRef) {
+ # FIXME: Handle errors differently from ChangeLog files that
+ # are okay but should not be altered. That way we can find out
+ # if improvements to the script ever become necessary.
+ $changeLogHashRef{patch} = $patch; # Error: unexpected patch string format.
+ return \%changeLogHashRef;
+ }
+ my $oldSourceLineCount = $chunkRangeHashRef->{lineCount};
+ my $oldTargetLineCount = $chunkRangeHashRef->{newLineCount};
+
+ my $sourceLineCount = $oldSourceLineCount + @overlappingLines - $deletedLineCount;
+ my $targetLineCount = $oldTargetLineCount + @overlappingLines - $deletedLineCount;
+ $lines[$chunkStartIndex - 1] = "@@ -1,$sourceLineCount +1,$targetLineCount @@";
+
+ $changeLogHashRef{patch} = join($lineEnding, @lines) . "\n"; # patch(1) expects an extra trailing newline.
+ return \%changeLogHashRef;
+}
+
+# This is a supporting method for runPatchCommand.
+#
+# Arg: the optional $args parameter passed to runPatchCommand (can be undefined).
+#
+# Returns ($patchCommand, $isForcing).
+#
+# This subroutine has unit tests in VCSUtils_unittest.pl.
+sub generatePatchCommand($)
+{
+ my ($passedArgsHashRef) = @_;
+
+ my $argsHashRef = { # Defaults
+ ensureForce => 0,
+ shouldReverse => 0,
+ options => []
+ };
+
+ # Merges hash references. It's okay here if passed hash reference is undefined.
+ @{$argsHashRef}{keys %{$passedArgsHashRef}} = values %{$passedArgsHashRef};
+
+ my $ensureForce = $argsHashRef->{ensureForce};
+ my $shouldReverse = $argsHashRef->{shouldReverse};
+ my $options = $argsHashRef->{options};
+
+ if (! $options) {
+ $options = [];
+ } else {
+ $options = [@{$options}]; # Copy to avoid side effects.
+ }
+
+ my $isForcing = 0;
+ if (grep /^--force$/, @{$options}) {
+ $isForcing = 1;
+ } elsif ($ensureForce) {
+ push @{$options}, "--force";
+ $isForcing = 1;
+ }
+
+ if ($shouldReverse) { # No check: --reverse should never be passed explicitly.
+ push @{$options}, "--reverse";
+ }
+
+ @{$options} = sort(@{$options}); # For easier testing.
+
+ my $patchCommand = join(" ", "patch -p0", @{$options});
+
+ return ($patchCommand, $isForcing);
+}
+
+# Apply the given patch using the patch(1) command.
+#
+# On success, return the resulting exit status. Otherwise, exit with the
+# exit status. If "--force" is passed as an option, however, then never
+# exit and always return the exit status.
+#
+# Args:
+# $patch: a patch string.
+# $repositoryRootPath: an absolute path to the repository root.
+# $pathRelativeToRoot: the path of the file to be patched, relative to the
+# repository root. This should normally be the path
+# found in the patch's "Index:" line. It is passed
+# explicitly rather than reparsed from the patch
+# string for optimization purposes.
+# This is used only for error reporting. The
+# patch command gleans the actual file to patch
+# from the patch string.
+# $args: a reference to a hash of optional arguments. The possible
+# keys are --
+# ensureForce: whether to ensure --force is passed (defaults to 0).
+# shouldReverse: whether to pass --reverse (defaults to 0).
+# options: a reference to an array of options to pass to the
+# patch command. The subroutine passes the -p0 option
+# no matter what. This should not include --reverse.
+#
+# This subroutine has unit tests in VCSUtils_unittest.pl.
+sub runPatchCommand($$$;$)
+{
+ my ($patch, $repositoryRootPath, $pathRelativeToRoot, $args) = @_;
+
+ my ($patchCommand, $isForcing) = generatePatchCommand($args);
+
+ # Temporarily change the working directory since the path found
+ # in the patch's "Index:" line is relative to the repository root
+ # (i.e. the same as $pathRelativeToRoot).
+ my $cwd = Cwd::getcwd();
+ chdir $repositoryRootPath;
+
+ open PATCH, "| $patchCommand" or die "Could not call \"$patchCommand\" for file \"$pathRelativeToRoot\": $!";
+ print PATCH $patch;
+ close PATCH;
+ my $exitStatus = exitStatus($?);
+
+ chdir $cwd;
+
+ if ($exitStatus && !$isForcing) {
+ print "Calling \"$patchCommand\" for file \"$pathRelativeToRoot\" returned " .
+ "status $exitStatus. Pass --force to ignore patch failures.\n";
+ exit $exitStatus;
+ }
+
+ return $exitStatus;
+}
+
+# Merge ChangeLog patches using a three-file approach.
+#
+# This is used by resolve-ChangeLogs when it's operated as a merge driver
+# and when it's used to merge conflicts after a patch is applied or after
+# an svn update.
+#
+# It's also used for traditional rejected patches.
+#
+# Args:
+# $fileMine: The merged version of the file. Also known in git as the
+# other branch's version (%B) or "ours".
+# For traditional patch rejects, this is the *.rej file.
+# $fileOlder: The base version of the file. Also known in git as the
+# ancestor version (%O) or "base".
+# For traditional patch rejects, this is the *.orig file.
+# $fileNewer: The current version of the file. Also known in git as the
+# current version (%A) or "theirs".
+# For traditional patch rejects, this is the original-named
+# file.
+#
+# Returns 1 if merge was successful, else 0.
+sub mergeChangeLogs($$$)
+{
+ my ($fileMine, $fileOlder, $fileNewer) = @_;
+
+ my $traditionalReject = $fileMine =~ /\.rej$/ ? 1 : 0;
+
+ local $/ = undef;
+
+ my $patch;
+ if ($traditionalReject) {
+ open(DIFF, "<", $fileMine) or die $!;
+ $patch = <DIFF>;
+ close(DIFF);
+ rename($fileMine, "$fileMine.save");
+ rename($fileOlder, "$fileOlder.save");
+ } else {
+ open(DIFF, "diff -u -a --binary \"$fileOlder\" \"$fileMine\" |") or die $!;
+ $patch = <DIFF>;
+ close(DIFF);
+ }
+
+ unlink("${fileNewer}.orig");
+ unlink("${fileNewer}.rej");
+
+ open(PATCH, "| patch --force --fuzz=3 --binary \"$fileNewer\" > " . File::Spec->devnull()) or die $!;
+ if ($traditionalReject) {
+ print PATCH $patch;
+ } else {
+ my $changeLogHash = fixChangeLogPatch($patch);
+ print PATCH $changeLogHash->{patch};
+ }
+ close(PATCH);
+
+ my $result = !exitStatus($?);
+
+ # Refuse to merge the patch if it did not apply cleanly
+ if (-e "${fileNewer}.rej") {
+ unlink("${fileNewer}.rej");
+ if (-f "${fileNewer}.orig") {
+ unlink($fileNewer);
+ rename("${fileNewer}.orig", $fileNewer);
+ }
+ } else {
+ unlink("${fileNewer}.orig");
+ }
+
+ if ($traditionalReject) {
+ rename("$fileMine.save", $fileMine);
+ rename("$fileOlder.save", $fileOlder);
+ }
+
+ return $result;
+}
+
+sub gitConfig($)
+{
+ return unless isGit();
+
+ my ($config) = @_;
+
+ my $result = `git config $config`;
+ chomp $result;
+ return $result;
+}
+
+sub changeLogNameError($)
+{
+ my ($message) = @_;
+ print STDERR "$message\nEither:\n";
+ print STDERR " set CHANGE_LOG_NAME in your environment\n";
+ print STDERR " OR pass --name= on the command line\n";
+ print STDERR " OR set REAL_NAME in your environment";
+ print STDERR " OR git users can set 'git config user.name'\n";
+ exit(1);
+}
+
+sub changeLogName()
+{
+ my $name = $ENV{CHANGE_LOG_NAME} || $ENV{REAL_NAME} || gitConfig("user.name");
+ if (not $name and !isWindows()) {
+ $name = (split /\s*,\s*/, (getpwuid $<)[6])[0];
+ }
+
+ changeLogNameError("Failed to determine ChangeLog name.") unless $name;
+ # getpwuid seems to always succeed on windows, returning the username instead of the full name. This check will catch that case.
+ changeLogNameError("'$name' does not contain a space! ChangeLogs should contain your full name.") unless ($name =~ /\S\s\S/);
+
+ return $name;
+}
+
+sub changeLogEmailAddressError($)
+{
+ my ($message) = @_;
+ print STDERR "$message\nEither:\n";
+ print STDERR " set CHANGE_LOG_EMAIL_ADDRESS in your environment\n";
+ print STDERR " OR pass --email= on the command line\n";
+ print STDERR " OR set EMAIL_ADDRESS in your environment\n";
+ print STDERR " OR git users can set 'git config user.email'\n";
+ exit(1);
+}
+
+sub changeLogEmailAddress()
+{
+ my $emailAddress = $ENV{CHANGE_LOG_EMAIL_ADDRESS} || $ENV{EMAIL_ADDRESS} || gitConfig("user.email");
+
+ changeLogEmailAddressError("Failed to determine email address for ChangeLog.") unless $emailAddress;
+ changeLogEmailAddressError("Email address '$emailAddress' does not contain '\@' and is likely invalid.") unless ($emailAddress =~ /\@/);
+
+ return $emailAddress;
+}
+
+# http://tools.ietf.org/html/rfc1924
+sub decodeBase85($)
+{
+ my ($encoded) = @_;
+ my %table;
+ my @characters = ('0'..'9', 'A'..'Z', 'a'..'z', '!', '#', '$', '%', '&', '(', ')', '*', '+', '-', ';', '<', '=', '>', '?', '@', '^', '_', '`', '{', '|', '}', '~');
+ for (my $i = 0; $i < 85; $i++) {
+ $table{$characters[$i]} = $i;
+ }
+
+ my $decoded = '';
+ my @encodedChars = $encoded =~ /./g;
+
+ for (my $encodedIter = 0; defined($encodedChars[$encodedIter]);) {
+ my $digit = 0;
+ for (my $i = 0; $i < 5; $i++) {
+ $digit *= 85;
+ my $char = $encodedChars[$encodedIter];
+ $digit += $table{$char};
+ $encodedIter++;
+ }
+
+ for (my $i = 0; $i < 4; $i++) {
+ $decoded .= chr(($digit >> (3 - $i) * 8) & 255);
+ }
+ }
+
+ return $decoded;
+}
+
+sub decodeGitBinaryChunk($$)
+{
+ my ($contents, $fullPath) = @_;
+
+ # Load this module lazily in case the user don't have this module
+ # and won't handle git binary patches.
+ require Compress::Zlib;
+
+ my $encoded = "";
+ my $compressedSize = 0;
+ while ($contents =~ /^([A-Za-z])(.*)$/gm) {
+ my $line = $2;
+ next if $line eq "";
+ die "$fullPath: unexpected size of a line: $&" if length($2) % 5 != 0;
+ my $actualSize = length($2) / 5 * 4;
+ my $encodedExpectedSize = ord($1);
+ my $expectedSize = $encodedExpectedSize <= ord("Z") ? $encodedExpectedSize - ord("A") + 1 : $encodedExpectedSize - ord("a") + 27;
+
+ die "$fullPath: unexpected size of a line: $&" if int(($expectedSize + 3) / 4) * 4 != $actualSize;
+ $compressedSize += $expectedSize;
+ $encoded .= $line;
+ }
+
+ my $compressed = decodeBase85($encoded);
+ $compressed = substr($compressed, 0, $compressedSize);
+ return Compress::Zlib::uncompress($compressed);
+}
+
+sub decodeGitBinaryPatch($$)
+{
+ my ($contents, $fullPath) = @_;
+
+ # Git binary patch has two chunks. One is for the normal patching
+ # and another is for the reverse patching.
+ #
+ # Each chunk a line which starts from either "literal" or "delta",
+ # followed by a number which specifies decoded size of the chunk.
+ #
+ # Then, content of the chunk comes. To decode the content, we
+ # need decode it with base85 first, and then zlib.
+ my $gitPatchRegExp = '(literal|delta) ([0-9]+)\n([A-Za-z0-9!#$%&()*+-;<=>?@^_`{|}~\\n]*?)\n\n';
+ if ($contents !~ m"\nGIT binary patch\n$gitPatchRegExp$gitPatchRegExp(\Z|-- \n)") {
+ return ();
+ }
+
+ my $binaryChunkType = $1;
+ my $binaryChunkExpectedSize = $2;
+ my $encodedChunk = $3;
+ my $reverseBinaryChunkType = $4;
+ my $reverseBinaryChunkExpectedSize = $5;
+ my $encodedReverseChunk = $6;
+
+ my $binaryChunk = decodeGitBinaryChunk($encodedChunk, $fullPath);
+ my $binaryChunkActualSize = length($binaryChunk);
+ my $reverseBinaryChunk = decodeGitBinaryChunk($encodedReverseChunk, $fullPath);
+ my $reverseBinaryChunkActualSize = length($reverseBinaryChunk);
+
+ die "$fullPath: unexpected size of the first chunk (expected $binaryChunkExpectedSize but was $binaryChunkActualSize" if ($binaryChunkType eq "literal" and $binaryChunkExpectedSize != $binaryChunkActualSize);
+ die "$fullPath: unexpected size of the second chunk (expected $reverseBinaryChunkExpectedSize but was $reverseBinaryChunkActualSize" if ($reverseBinaryChunkType eq "literal" and $reverseBinaryChunkExpectedSize != $reverseBinaryChunkActualSize);
+
+ return ($binaryChunkType, $binaryChunk, $reverseBinaryChunkType, $reverseBinaryChunk);
+}
+
+sub readByte($$)
+{
+ my ($data, $location) = @_;
+
+ # Return the byte at $location in $data as a numeric value.
+ return ord(substr($data, $location, 1));
+}
+
+# The git binary delta format is undocumented, except in code:
+# - https://github.com/git/git/blob/master/delta.h:get_delta_hdr_size is the source
+# of the algorithm in decodeGitBinaryPatchDeltaSize.
+# - https://github.com/git/git/blob/master/patch-delta.c:patch_delta is the source
+# of the algorithm in applyGitBinaryPatchDelta.
+sub decodeGitBinaryPatchDeltaSize($)
+{
+ my ($binaryChunk) = @_;
+
+ # Source and destination buffer sizes are stored in 7-bit chunks at the
+ # start of the binary delta patch data. The highest bit in each byte
+ # except the last is set; the remaining 7 bits provide the next
+ # chunk of the size. The chunks are stored in ascending significance
+ # order.
+ my $cmd;
+ my $size = 0;
+ my $shift = 0;
+ for (my $i = 0; $i < length($binaryChunk);) {
+ $cmd = readByte($binaryChunk, $i++);
+ $size |= ($cmd & 0x7f) << $shift;
+ $shift += 7;
+ if (!($cmd & 0x80)) {
+ return ($size, $i);
+ }
+ }
+}
+
+sub applyGitBinaryPatchDelta($$)
+{
+ my ($binaryChunk, $originalContents) = @_;
+
+ # Git delta format consists of two headers indicating source buffer size
+ # and result size, then a series of commands. Each command is either
+ # a copy-from-old-version (the 0x80 bit is set) or a copy-from-delta
+ # command. Commands are applied sequentially to generate the result.
+ #
+ # A copy-from-old-version command encodes an offset and size to copy
+ # from in subsequent bits, while a copy-from-delta command consists only
+ # of the number of bytes to copy from the delta.
+
+ # We don't use these values, but we need to know how big they are so that
+ # we can skip to the diff data.
+ my ($size, $bytesUsed) = decodeGitBinaryPatchDeltaSize($binaryChunk);
+ $binaryChunk = substr($binaryChunk, $bytesUsed);
+ ($size, $bytesUsed) = decodeGitBinaryPatchDeltaSize($binaryChunk);
+ $binaryChunk = substr($binaryChunk, $bytesUsed);
+
+ my $out = "";
+ for (my $i = 0; $i < length($binaryChunk); ) {
+ my $cmd = ord(substr($binaryChunk, $i++, 1));
+ if ($cmd & 0x80) {
+ # Extract an offset and size from the delta data, then copy
+ # $size bytes from $offset in the original data into the output.
+ my $offset = 0;
+ my $size = 0;
+ if ($cmd & 0x01) { $offset = readByte($binaryChunk, $i++); }
+ if ($cmd & 0x02) { $offset |= readByte($binaryChunk, $i++) << 8; }
+ if ($cmd & 0x04) { $offset |= readByte($binaryChunk, $i++) << 16; }
+ if ($cmd & 0x08) { $offset |= readByte($binaryChunk, $i++) << 24; }
+ if ($cmd & 0x10) { $size = readByte($binaryChunk, $i++); }
+ if ($cmd & 0x20) { $size |= readByte($binaryChunk, $i++) << 8; }
+ if ($cmd & 0x40) { $size |= readByte($binaryChunk, $i++) << 16; }
+ if ($size == 0) { $size = 0x10000; }
+ $out .= substr($originalContents, $offset, $size);
+ } elsif ($cmd) {
+ # Copy $cmd bytes from the delta data into the output.
+ $out .= substr($binaryChunk, $i, $cmd);
+ $i += $cmd;
+ } else {
+ die "unexpected delta opcode 0";
+ }
+ }
+
+ return $out;
+}
+
+sub escapeSubversionPath($)
+{
+ my ($path) = @_;
+ $path .= "@" if $path =~ /@/;
+ return $path;
+}
+
+sub runCommand(@)
+{
+ my @args = @_;
+ my $pid = open(CHILD, "-|");
+ if (!defined($pid)) {
+ die "Failed to fork(): $!";
+ }
+ if ($pid) {
+ # Parent process
+ my $childStdout;
+ while (<CHILD>) {
+ $childStdout .= $_;
+ }
+ close(CHILD);
+ my %childOutput;
+ $childOutput{exitStatus} = exitStatus($?);
+ $childOutput{stdout} = $childStdout if $childStdout;
+ return \%childOutput;
+ }
+ # Child process
+ # FIXME: Consider further hardening of this function, including sanitizing the environment.
+ exec { $args[0] } @args or die "Failed to exec(): $!";
+}
+
+sub gitCommitForSVNRevision
+{
+ my ($svnRevision) = @_;
+ my $command = "git svn find-rev r" . $svnRevision;
+ $command = "LC_ALL=C $command" if !isWindows();
+ my $gitHash = `$command`;
+ if (!defined($gitHash)) {
+ $gitHash = "unknown";
+ warn "Unable to determine GIT commit from SVN revision";
+ } else {
+ chop($gitHash);
+ }
+ return $gitHash;
+}
+
+sub listOfChangedFilesBetweenRevisions
+{
+ my ($sourceDir, $firstRevision, $lastRevision) = @_;
+ my $command;
+
+ if ($firstRevision eq "unknown" or $lastRevision eq "unknown") {
+ return ();
+ }
+
+ # Some VCS functions don't work from within the build dir, so always
+ # go to the source dir first.
+ my $cwd = Cwd::getcwd();
+ chdir $sourceDir;
+
+ if (isGit()) {
+ my $firstCommit = gitCommitForSVNRevision($firstRevision);
+ my $lastCommit = gitCommitForSVNRevision($lastRevision);
+ $command = "git diff --name-status $firstCommit..$lastCommit";
+ } elsif (isSVN()) {
+ $command = "svn diff --summarize -r $firstRevision:$lastRevision";
+ }
+
+ my @result = ();
+
+ if ($command) {
+ my $diffOutput = `$command`;
+ $diffOutput =~ s/^[A-Z]\s+//gm;
+ @result = split(/[\r\n]+/, $diffOutput);
+ }
+
+ chdir $cwd;
+
+ return @result;
+}
+
+
+1;
diff --git a/Tools/Scripts/run-gtk-tests b/Tools/Scripts/run-gtk-tests
new file mode 100755
index 000000000..a3d3e6f28
--- /dev/null
+++ b/Tools/Scripts/run-gtk-tests
@@ -0,0 +1,494 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2011, 2012 Igalia S.L.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public License
+# along with this library; see the file COPYING.LIB. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
+import logging
+import subprocess
+import os
+import sys
+import optparse
+import re
+from signal import alarm, signal, SIGALRM, SIGKILL, SIGSEGV
+from gi.repository import Gio, GLib
+
+top_level_directory = os.path.normpath(os.path.join(os.path.dirname(__file__), "..", ".."))
+sys.path.append(os.path.join(top_level_directory, "Tools", "jhbuild"))
+sys.path.append(os.path.join(top_level_directory, "Tools", "gtk"))
+import common
+import jhbuildutils
+from webkitpy.common.host import Host
+
+class SkippedTest:
+ ENTIRE_SUITE = None
+
+ def __init__(self, test, test_case, reason, bug, build_type=None):
+ self.test = test
+ self.test_case = test_case
+ self.reason = reason
+ self.bug = bug
+ self.build_type = build_type
+
+ def __str__(self):
+ skipped_test_str = "%s" % self.test
+
+ if not(self.skip_entire_suite()):
+ skipped_test_str += " [%s]" % self.test_case
+
+ skipped_test_str += ": %s (https://bugs.webkit.org/show_bug.cgi?id=%d)" % (self.reason, self.bug)
+ return skipped_test_str
+
+ def skip_entire_suite(self):
+ return self.test_case == SkippedTest.ENTIRE_SUITE
+
+ def skip_for_build_type(self, build_type):
+ if self.build_type is None:
+ return True;
+
+ return self.build_type == build_type
+
+class TestTimeout(Exception):
+ pass
+
+class TestRunner:
+ TEST_DIRS = [ "WebKit2Gtk", "WebKit2", "JavaScriptCore", "WTF", "WebCore" ]
+
+ SKIPPED = [
+ SkippedTest("WebKit2Gtk/TestUIClient", "/webkit2/WebKitWebView/mouse-target", "Test times out after r150890", 117689),
+ SkippedTest("WebKit2Gtk/TestUIClient", "/webkit2/WebKitWebView/usermedia-permission-requests", "Test times out", 158257),
+ SkippedTest("WebKit2Gtk/TestUIClient", "/webkit2/WebKitWebView/audio-usermedia-permission-request", "Test times out", 158257),
+ SkippedTest("WebKit2Gtk/TestCookieManager", "/webkit2/WebKitCookieManager/persistent-storage", "Test is flaky", 134580),
+ SkippedTest("WebKit2Gtk/TestPrinting", "/webkit2/WebKitPrintOperation/custom-widget", "Test is flaky", 168196),
+ SkippedTest("WebKit2Gtk/TestWebViewEditor", "/webkit2/WebKitWebView/editable/editable", "Test hits an assertion in Debug builds", 151654, "Debug"),
+ SkippedTest("WebKit2Gtk/TestWebExtensions", "/webkit2/WebKitWebExtension/form-controls-associated-signal", "Test is flaky", 168194),
+ SkippedTest("WebKit2Gtk/TestWebExtensions", "/webkit2/WebKitWebView/install-missing-plugins-permission-request", "Test times out", 147822),
+ SkippedTest("WebKit2/TestWebKit2", "WebKit2.MouseMoveAfterCrash", "Test is flaky", 85066),
+ SkippedTest("WebKit2/TestWebKit2", "WebKit2.NewFirstVisuallyNonEmptyLayoutForImages", "Test is flaky", 85066),
+ SkippedTest("WebKit2/TestWebKit2", "WebKit2.NewFirstVisuallyNonEmptyLayoutFrames", "Test fails", 85037),
+ SkippedTest("WebKit2/TestWebKit2", "WebKit2.SpacebarScrolling", "Test fails", 84961),
+ SkippedTest("WebKit2/TestWebKit2", "WebKit2.WKConnection", "Tests fail and time out out", 84959),
+ SkippedTest("WebKit2/TestWebKit2", "WebKit2.ForceRepaint", "Test times out", 105532),
+ SkippedTest("WebKit2/TestWebKit2", "WebKit2.ReloadPageAfterCrash", "Test flakily times out", 110129),
+ SkippedTest("WebKit2/TestWebKit2", "WebKit2.DidAssociateFormControls", "Test times out", 120302),
+ SkippedTest("WebKit2/TestWebKit2", "WebKit2.InjectedBundleFrameHitTest", "Test times out", 120303),
+ SkippedTest("WebKit2/TestWebKit2", "WebKit2.TerminateTwice", "Test causes crash on the next test", 121970),
+ SkippedTest("WebKit2/TestWebKit2", "WebKit2.GeolocationTransitionToHighAccuracy", "Test causes crash on the next test", 125068),
+ SkippedTest("WebKit2/TestWebKit2", "WebKit2.GeolocationTransitionToLowAccuracy", "Test causes crash on the next test", 125068),
+ ]
+
+ SLOW = [
+ "WTF_Lock.ContendedShortSection",
+ "WTF_Lock.ContendedLongSection",
+ "WTF_WordLock.ContendedShortSection",
+ "WTF_WordLock.ContendedLongSection",
+ "WebKit2Gtk/TestInspectorServer",
+ ]
+
+ def __init__(self, options, tests=[]):
+ self._options = options
+
+ self._build_type = "Debug" if self._options.debug else "Release"
+ common.set_build_types((self._build_type,))
+ self._port = Host().port_factory.get("gtk")
+ self._driver = self._create_driver()
+
+ self._programs_path = common.binary_build_path()
+ self._tests = self._get_tests(tests)
+ self._skipped_tests = [skipped for skipped in TestRunner.SKIPPED if skipped.skip_for_build_type(self._build_type)]
+ self._disabled_tests = []
+
+ # These SPI daemons need to be active for the accessibility tests to work.
+ self._spi_registryd = None
+ self._spi_bus_launcher = None
+
+ def _test_programs_base_dir(self):
+ return os.path.join(self._programs_path, "TestWebKitAPI")
+
+ def _get_tests_from_dir(self, test_dir):
+ if not os.path.isdir(test_dir):
+ return []
+
+ tests = []
+ for test_file in os.listdir(test_dir):
+ if not test_file.lower().startswith("test"):
+ continue
+ test_path = os.path.join(test_dir, test_file)
+ if os.path.isfile(test_path) and os.access(test_path, os.X_OK):
+ tests.append(test_path)
+ return tests
+
+ def _get_tests(self, initial_tests):
+ tests = []
+ for test in initial_tests:
+ if os.path.isdir(test):
+ tests.extend(self._get_tests_from_dir(test))
+ else:
+ tests.append(test)
+ if tests:
+ return tests
+
+ tests = []
+ for test_dir in self.TEST_DIRS:
+ absolute_test_dir = os.path.join(self._test_programs_base_dir(), test_dir)
+ tests.extend(self._get_tests_from_dir(absolute_test_dir))
+ return tests
+
+ def _lookup_atspi2_binary(self, filename):
+ exec_prefix = common.pkg_config_file_variable('atspi-2', 'exec_prefix')
+ if not exec_prefix:
+ return None
+ for path in ['libexec', 'lib/at-spi2-core', 'lib32/at-spi2-core', 'lib64/at-spi2-core']:
+ filepath = os.path.join(exec_prefix, path, filename)
+ if os.path.isfile(filepath):
+ return filepath
+
+ return None
+
+ def _wait_for_accessibility_bus(self):
+ def timeout_accessibility_bus():
+ self._accessibility_bus_found = False
+ sys.stderr.write("Timeout waiting for the accesibility bus.\n")
+ sys.stderr.flush()
+ loop.quit()
+ # Backup current environment, and temporally set the test one.
+ oldenv = dict(os.environ)
+ os.environ.clear()
+ os.environ.update(self._test_env)
+ # We spin a main loop until the bus name appears on DBus.
+ self._accessibility_bus_found = True
+ loop = GLib.MainLoop()
+ Gio.bus_watch_name(Gio.BusType.SESSION, 'org.a11y.Bus', Gio.BusNameWatcherFlags.NONE,
+ lambda *args: loop.quit(), None)
+ GLib.timeout_add_seconds(5, timeout_accessibility_bus)
+ loop.run()
+ # Restore previous environment.
+ os.environ.clear()
+ os.environ.update(oldenv)
+ return self._accessibility_bus_found
+
+ def _start_accessibility_daemons(self):
+ spi_bus_launcher_path = self._lookup_atspi2_binary('at-spi-bus-launcher')
+ spi_registryd_path = self._lookup_atspi2_binary('at-spi2-registryd')
+ if not spi_bus_launcher_path or not spi_registryd_path:
+ return False
+
+ try:
+ self._spi_bus_launcher = subprocess.Popen([spi_bus_launcher_path], env=self._test_env)
+ except:
+ sys.stderr.write("Failed to launch the accessibility bus\n")
+ sys.stderr.flush()
+ return False
+
+ # We need to wait until the SPI bus is launched before trying to start the SPI registry.
+ if not self._wait_for_accessibility_bus():
+ sys.stderr.write("Failed checking the accessibility bus within D-Bus\n")
+ sys.stderr.flush()
+ return False
+
+ try:
+ self._spi_registryd = subprocess.Popen([spi_registryd_path], env=self._test_env)
+ except:
+ sys.stderr.write("Failed to launch the accessibility registry\n")
+ sys.stderr.flush()
+ return False
+
+ return True
+
+ def _create_driver(self, port_options=[]):
+ self._port._display_server = self._options.display_server
+ driver = self._port.create_driver(worker_number=0, no_timeout=True)._make_driver(pixel_tests=False)
+ if not driver.check_driver(self._port):
+ raise RuntimeError("Failed to check driver %s" %driver.__class__.__name__)
+ return driver
+
+ def _setup_testing_environment(self):
+ self._test_env = self._driver._setup_environ_for_test()
+ self._test_env["TEST_WEBKIT_API_WEBKIT2_RESOURCES_PATH"] = common.top_level_path("Tools", "TestWebKitAPI", "Tests", "WebKit2")
+ self._test_env["TEST_WEBKIT_API_WEBKIT2_INJECTED_BUNDLE_PATH"] = common.library_build_path()
+ self._test_env["WEBKIT_EXEC_PATH"] = self._programs_path
+
+ # If we cannot start the accessibility daemons, we can just skip the accessibility tests.
+ if not self._start_accessibility_daemons():
+ print "Could not start accessibility bus, so disabling TestWebKitAccessibility"
+ self._disabled_tests.append("WebKit2APITests/TestWebKitAccessibility")
+ return True
+
+ def _tear_down_testing_environment(self):
+ if self._spi_registryd:
+ self._spi_registryd.terminate()
+ if self._spi_bus_launcher:
+ self._spi_bus_launcher.terminate()
+ if self._driver:
+ self._driver.stop()
+
+ def _test_cases_to_skip(self, test_program):
+ if self._options.skipped_action != 'skip':
+ return []
+
+ test_cases = []
+ for skipped in self._skipped_tests:
+ if test_program.endswith(skipped.test) and not skipped.skip_entire_suite():
+ test_cases.append(skipped.test_case)
+ return test_cases
+
+ def _should_run_test_program(self, test_program):
+ for disabled_test in self._disabled_tests:
+ if test_program.endswith(disabled_test):
+ return False
+
+ if self._options.skipped_action != 'skip':
+ return True
+
+ for skipped in self._skipped_tests:
+ if test_program.endswith(skipped.test) and skipped.skip_entire_suite():
+ return False
+ return True
+
+ def _get_child_pid_from_test_output(self, output):
+ if not output:
+ return -1
+ match = re.search(r'\(pid=(?P<child_pid>[0-9]+)\)', output)
+ if not match:
+ return -1
+ return int(match.group('child_pid'))
+
+ def _kill_process(self, pid):
+ try:
+ os.kill(pid, SIGKILL)
+ except OSError:
+ # Process already died.
+ pass
+
+ def _run_test_command(self, command, timeout=-1):
+ def alarm_handler(signum, frame):
+ raise TestTimeout
+
+ child_pid = [-1]
+ def parse_line(line, child_pid = child_pid):
+ if child_pid[0] == -1:
+ child_pid[0] = self._get_child_pid_from_test_output(line)
+
+ sys.stdout.write(line)
+
+ def waitpid(pid):
+ while True:
+ try:
+ return os.waitpid(pid, 0)
+ except (OSError, IOError) as e:
+ if e.errno == errno.EINTR:
+ continue
+ raise
+
+ def return_code_from_exit_status(status):
+ if os.WIFSIGNALED(status):
+ return -os.WTERMSIG(status)
+ elif os.WIFEXITED(status):
+ return os.WEXITSTATUS(status)
+ else:
+ # Should never happen
+ raise RuntimeError("Unknown child exit status!")
+
+ pid, fd = os.forkpty()
+ if pid == 0:
+ os.execvpe(command[0], command, self._test_env)
+ sys.exit(0)
+
+ if timeout > 0:
+ signal(SIGALRM, alarm_handler)
+ alarm(timeout)
+
+ try:
+ common.parse_output_lines(fd, parse_line)
+ if timeout > 0:
+ alarm(0)
+ except TestTimeout:
+ self._kill_process(pid)
+ if child_pid[0] > 0:
+ self._kill_process(child_pid[0])
+ raise
+
+ try:
+ dummy, status = waitpid(pid)
+ except OSError as e:
+ if e.errno != errno.ECHILD:
+ raise
+ # This happens if SIGCLD is set to be ignored or waiting
+ # for child processes has otherwise been disabled for our
+ # process. This child is dead, we can't get the status.
+ status = 0
+
+ return return_code_from_exit_status(status)
+
+ def _run_test_glib(self, test_program):
+ tester_command = ['gtester', '-k']
+ if self._options.verbose:
+ tester_command.append('--verbose')
+ for test_case in self._test_cases_to_skip(test_program):
+ tester_command.extend(['-s', test_case])
+ tester_command.append(test_program)
+ # This timeout is supposed to be per test case, but in the case of GLib tests it affects all the tests cases of
+ # the same test program. Some test programs like TestLoaderClient, that have a lot of test cases, often time out
+ # in the bots because the timeout is not enough to run all the tests cases. So, we use a longer timeout for GLib
+ # tests (timeout * 2).
+ timeout = self._options.timeout * 2
+ test = os.path.join(os.path.basename(os.path.dirname(test_program)), os.path.basename(test_program))
+ if test in TestRunner.SLOW:
+ timeout *= 5
+
+ return self._run_test_command(tester_command, timeout)
+
+ def _get_tests_from_google_test_suite(self, test_program):
+ try:
+ output = subprocess.check_output([test_program, '--gtest_list_tests'], env=self._test_env)
+ except subprocess.CalledProcessError:
+ sys.stderr.write("ERROR: could not list available tests for binary %s.\n" % (test_program))
+ sys.stderr.flush()
+ return 1
+
+ skipped_test_cases = self._test_cases_to_skip(test_program)
+
+ tests = []
+ prefix = None
+ for line in output.split('\n'):
+ if not line.startswith(' '):
+ prefix = line
+ continue
+ else:
+ test_name = prefix + line.strip()
+ if not test_name in skipped_test_cases:
+ tests.append(test_name)
+ return tests
+
+ def _run_google_test(self, test_program, subtest):
+ test_command = [test_program, '--gtest_filter=%s' % (subtest)]
+ timeout = self._options.timeout
+ if subtest in TestRunner.SLOW:
+ timeout *= 5
+
+ status = self._run_test_command(test_command, timeout)
+ if status == -SIGSEGV:
+ sys.stdout.write("**CRASH** %s\n" % subtest)
+ sys.stdout.flush()
+ return status
+
+ def _run_google_test_suite(self, test_program):
+ retcode = 0
+ for subtest in self._get_tests_from_google_test_suite(test_program):
+ if self._run_google_test(test_program, subtest):
+ retcode = 1
+ return retcode
+
+ def _run_test(self, test_program):
+ basedir = os.path.basename(os.path.dirname(test_program))
+ if basedir in ["WebKit2Gtk", "WebKitGtk"]:
+ return self._run_test_glib(test_program)
+
+ if basedir in ["WebKit2", "JavaScriptCore", "WTF", "WebCore", "WebCoreGtk"]:
+ return self._run_google_test_suite(test_program)
+
+ return 1
+
+ def run_tests(self):
+ if not self._tests:
+ sys.stderr.write("ERROR: tests not found in %s.\n" % (self._test_programs_base_dir()))
+ sys.stderr.flush()
+ return 1
+
+ if not self._setup_testing_environment():
+ return 1
+
+ # Remove skipped tests now instead of when we find them, because
+ # some tests might be skipped while setting up the test environment.
+ self._tests = [test for test in self._tests if self._should_run_test_program(test)]
+
+ crashed_tests = []
+ failed_tests = []
+ timed_out_tests = []
+ try:
+ for test in self._tests:
+ exit_status_code = 0
+ try:
+ exit_status_code = self._run_test(test)
+ except TestTimeout:
+ sys.stdout.write("TEST: %s: TIMEOUT\n" % test)
+ sys.stdout.flush()
+ timed_out_tests.append(test)
+
+ if exit_status_code == -SIGSEGV:
+ sys.stdout.write("TEST: %s: CRASHED\n" % test)
+ sys.stdout.flush()
+ crashed_tests.append(test)
+ elif exit_status_code != 0:
+ failed_tests.append(test)
+ finally:
+ self._tear_down_testing_environment()
+
+ if failed_tests:
+ names = [test.replace(self._test_programs_base_dir(), '', 1) for test in failed_tests]
+ sys.stdout.write("Tests failed (%d): %s\n" % (len(names), ", ".join(names)))
+ sys.stdout.flush()
+
+ if crashed_tests:
+ names = [test.replace(self._test_programs_base_dir(), '', 1) for test in crashed_tests]
+ sys.stdout.write("Tests that crashed (%d): %s\n" % (len(names), ", ".join(names)))
+ sys.stdout.flush()
+
+ if timed_out_tests:
+ names = [test.replace(self._test_programs_base_dir(), '', 1) for test in timed_out_tests]
+ sys.stdout.write("Tests that timed out (%d): %s\n" % (len(names), ", ".join(names)))
+ sys.stdout.flush()
+
+ if self._skipped_tests and self._options.skipped_action == 'skip':
+ sys.stdout.write("Tests skipped (%d):\n%s\n" %
+ (len(self._skipped_tests),
+ "\n".join([str(skipped) for skipped in self._skipped_tests])))
+ sys.stdout.flush()
+
+ return len(failed_tests) + len(timed_out_tests)
+
+if __name__ == "__main__":
+ if not jhbuildutils.enter_jhbuild_environment_if_available("gtk"):
+ print "***"
+ print "*** Warning: jhbuild environment not present. Run update-webkitgtk-libs before build-webkit to ensure proper testing."
+ print "***"
+
+ option_parser = optparse.OptionParser(usage='usage: %prog [options] [test...]')
+ option_parser.add_option('-r', '--release',
+ action='store_true', dest='release',
+ help='Run in Release')
+ option_parser.add_option('-d', '--debug',
+ action='store_true', dest='debug',
+ help='Run in Debug')
+ option_parser.add_option('-v', '--verbose',
+ action='store_true', dest='verbose',
+ help='Run gtester in verbose mode')
+ option_parser.add_option('--skipped', action='store', dest='skipped_action',
+ choices=['skip', 'ignore', 'only'], default='skip',
+ metavar='skip|ignore|only',
+ help='Specifies how to treat the skipped tests')
+ option_parser.add_option('-t', '--timeout',
+ action='store', type='int', dest='timeout', default=10,
+ help='Time in seconds until a test times out')
+ option_parser.add_option('--display-server', choices=['xvfb', 'xorg', 'weston', 'wayland'], default='xvfb',
+ help='"xvfb": Use a virtualized X11 server. "xorg": Use the current X11 session. '
+ '"weston": Use a virtualized Weston server. "wayland": Use the current wayland session.'),
+ options, args = option_parser.parse_args()
+
+ logging.basicConfig(level=logging.INFO, format="%(message)s")
+
+ runner = TestRunner(options, args)
+ sys.exit(runner.run_tests())
diff --git a/Tools/Scripts/webkit-build-directory b/Tools/Scripts/webkit-build-directory
new file mode 100755
index 000000000..5bac3708a
--- /dev/null
+++ b/Tools/Scripts/webkit-build-directory
@@ -0,0 +1,84 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2010 Google Inc. All rights reserved.
+# Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# A script to expose WebKit's build directory detection logic to non-perl scripts.
+
+use FindBin;
+use Getopt::Long;
+
+use lib $FindBin::Bin;
+use webkitdirs;
+
+my $showConfigurationDirectory = 0;
+my $showExecutablePath = 0;
+my $showHelp = 0;
+my $showTopLevelDirectory = 0;
+
+
+my $programName = basename($0);
+my $usage = <<EOF;
+Usage: $programName [options]
+ --configuration Show the build directory for a specific configuration (e.g. Debug, Release. Defaults to the active configuration set by set-webkit-configuration)
+ --executablePath Show the path to the executables produced by a specific build configuration. This differs from --configuration on Windows.
+ -h|--help Show this help message
+ --top-level Show the top-level build directory
+
+ --efl Find the build directory for the EFL port
+ --gtk Find the build directory for the GTK+ port
+ --wincairo Find the build directory for using Cairo (rather than CoreGraphics) on Windows
+
+Either --configuration or --top-level is required.
+EOF
+
+setConfiguration(); # Figure out from the command line if we're --debug or --release or the default.
+
+# FIXME: Check if extra flags are valid or not.
+Getopt::Long::Configure('pass_through'); # Let --blackberry, etc... be handled by webkitdirs
+my $getOptionsResult = GetOptions(
+ 'configuration' => \$showConfigurationDirectory,
+ 'executablePath' => \$showExecutablePath,
+ 'top-level' => \$showTopLevelDirectory,
+ 'help|h' => \$showHelp,
+);
+
+if (!$getOptionsResult || $showHelp) {
+ print STDERR $usage;
+ exit 1;
+}
+
+if (!$showConfigurationDirectory && !$showTopLevelDirectory && !$showExecutablePath) {
+ print baseProductDir() . "\n";
+ print productDir() . "\n";
+} elsif ($showTopLevelDirectory) {
+ print baseProductDir() . "\n";
+} elsif ($showExecutablePath) {
+ print executableProductDir() . "\n";
+} else {
+ print productDir() . "\n";
+}
diff --git a/Tools/Scripts/webkitdirs.pm b/Tools/Scripts/webkitdirs.pm
new file mode 100755
index 000000000..030cd9ff2
--- /dev/null
+++ b/Tools/Scripts/webkitdirs.pm
@@ -0,0 +1,2613 @@
+# Copyright (C) 2005-2007, 2010-2016 Apple Inc. All rights reserved.
+# Copyright (C) 2009 Google Inc. All rights reserved.
+# Copyright (C) 2011 Research In Motion Limited. All rights reserved.
+# Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Module to share code to get to WebKit directories.
+
+use strict;
+use version;
+use warnings;
+use Config;
+use Cwd qw(realpath);
+use Digest::MD5 qw(md5_hex);
+use FindBin;
+use File::Basename;
+use File::Find;
+use File::Path qw(make_path mkpath rmtree);
+use File::Spec;
+use File::stat;
+use List::Util;
+use POSIX;
+use Time::HiRes qw(usleep);
+use VCSUtils;
+
+BEGIN {
+ use Exporter ();
+ our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+ $VERSION = 1.00;
+ @ISA = qw(Exporter);
+ @EXPORT = qw(
+ &XcodeCoverageSupportOptions
+ &XcodeOptionString
+ &XcodeOptionStringNoConfig
+ &XcodeOptions
+ &XcodeStaticAnalyzerOption
+ &appDisplayNameFromBundle
+ &appendToEnvironmentVariableList
+ &archCommandLineArgumentsForRestrictedEnvironmentVariables
+ &baseProductDir
+ &chdirWebKit
+ &checkFrameworks
+ &cmakeBasedPortArguments
+ &currentSVNRevision
+ &debugSafari
+ &executableProductDir
+ &findOrCreateSimulatorForIOSDevice
+ &iosSimulatorDeviceByName
+ &nmPath
+ &passedConfiguration
+ &prependToEnvironmentVariableList
+ &printHelpAndExitForRunAndDebugWebKitAppIfNeeded
+ &productDir
+ &quitIOSSimulator
+ &relaunchIOSSimulator
+ &restartIOSSimulatorDevice
+ &runIOSWebKitApp
+ &runMacWebKitApp
+ &safariPath
+ &iosVersion
+ &setConfiguration
+ &setupMacWebKitEnvironment
+ &sharedCommandLineOptions
+ &sharedCommandLineOptionsUsage
+ &shutDownIOSSimulatorDevice
+ &willUseIOSDeviceSDK
+ &willUseIOSSimulatorSDK
+ SIMULATOR_DEVICE_SUFFIX_FOR_WEBKIT_DEVELOPMENT
+ USE_OPEN_COMMAND
+ );
+ %EXPORT_TAGS = ( );
+ @EXPORT_OK = ();
+}
+
+# Ports
+use constant {
+ AppleWin => "AppleWin",
+ GTK => "GTK",
+ Efl => "Efl",
+ iOS => "iOS",
+ Mac => "Mac",
+ JSCOnly => "JSCOnly",
+ WinCairo => "WinCairo",
+ Unknown => "Unknown"
+};
+
+use constant USE_OPEN_COMMAND => 1; # Used in runMacWebKitApp().
+use constant SIMULATOR_DEVICE_STATE_SHUTDOWN => "1";
+use constant SIMULATOR_DEVICE_STATE_BOOTED => "3";
+use constant SIMULATOR_DEVICE_SUFFIX_FOR_WEBKIT_DEVELOPMENT => "For WebKit Development";
+
+# See table "Certificate types and names" on <https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/MaintainingCertificates/MaintainingCertificates.html#//apple_ref/doc/uid/TP40012582-CH31-SW41>.
+use constant IOS_DEVELOPMENT_CERTIFICATE_NAME_PREFIX => "iPhone Developer: ";
+
+our @EXPORT_OK;
+
+my $architecture;
+my $asanIsEnabled;
+my $numberOfCPUs;
+my $maxCPULoad;
+my $baseProductDir;
+my @baseProductDirOption;
+my $configuration;
+my $xcodeSDK;
+my $configurationForVisualStudio;
+my $configurationProductDir;
+my $sourceDir;
+my $currentSVNRevision;
+my $didLoadIPhoneSimulatorNotification;
+my $nmPath;
+my $osXVersion;
+my $iosVersion;
+my $generateDsym;
+my $isCMakeBuild;
+my $isWin64;
+my $isInspectorFrontend;
+my $portName;
+my $shouldUseGuardMalloc;
+my $shouldNotUseNinja;
+my $xcodeVersion;
+
+my $unknownPortProhibited = 0;
+
+# Variables for Win32 support
+my $programFilesPath;
+my $vcBuildPath;
+my $vsInstallDir;
+my $msBuildInstallDir;
+my $vsVersion;
+my $windowsSourceDir;
+my $winVersion;
+my $willUseVCExpressWhenBuilding = 0;
+
+# Defined in VCSUtils.
+sub exitStatus($);
+
+sub findMatchingArguments($$);
+sub hasArgument($$);
+
+sub determineSourceDir
+{
+ return if $sourceDir;
+ $sourceDir = $FindBin::Bin;
+ $sourceDir =~ s|/+$||; # Remove trailing '/' as we would die later
+
+ # walks up path checking each directory to see if it is the main WebKit project dir,
+ # defined by containing Sources, WebCore, and JavaScriptCore.
+ until ((-d File::Spec->catdir($sourceDir, "Source") && -d File::Spec->catdir($sourceDir, "Source", "WebCore") && -d File::Spec->catdir($sourceDir, "Source", "JavaScriptCore")) || (-d File::Spec->catdir($sourceDir, "Internal") && -d File::Spec->catdir($sourceDir, "OpenSource")))
+ {
+ if ($sourceDir !~ s|/[^/]+$||) {
+ die "Could not find top level webkit directory above source directory using FindBin.\n";
+ }
+ }
+
+ $sourceDir = File::Spec->catdir($sourceDir, "OpenSource") if -d File::Spec->catdir($sourceDir, "OpenSource");
+}
+
+sub currentPerlPath()
+{
+ my $thisPerl = $^X;
+ if ($^O ne 'VMS') {
+ $thisPerl .= $Config{_exe} unless $thisPerl =~ m/$Config{_exe}$/i;
+ }
+ return $thisPerl;
+}
+
+# used for scripts which are stored in a non-standard location
+sub setSourceDir($)
+{
+ ($sourceDir) = @_;
+}
+
+sub determineNinjaVersion
+{
+ chomp(my $ninjaVersion = `ninja --version`);
+ return $ninjaVersion;
+}
+
+sub determineXcodeVersion
+{
+ return if defined $xcodeVersion;
+ my $xcodebuildVersionOutput = `xcodebuild -version`;
+ $xcodeVersion = ($xcodebuildVersionOutput =~ /Xcode ([0-9](\.[0-9]+)*)/) ? $1 : "3.0";
+}
+
+sub readXcodeUserDefault($)
+{
+ my ($key) = @_;
+
+ my $devnull = File::Spec->devnull();
+
+ my $value = `defaults read com.apple.dt.Xcode ${key} 2> ${devnull}`;
+ return if $?;
+
+ chomp $value;
+ return $value;
+}
+
+sub determineBaseProductDir
+{
+ return if defined $baseProductDir;
+ determineSourceDir();
+
+ my $setSharedPrecompsDir;
+ $baseProductDir = $ENV{"WEBKIT_OUTPUTDIR"};
+
+ if (!defined($baseProductDir) and isAppleCocoaWebKit()) {
+ # Silently remove ~/Library/Preferences/xcodebuild.plist which can
+ # cause build failure. The presence of
+ # ~/Library/Preferences/xcodebuild.plist can prevent xcodebuild from
+ # respecting global settings such as a custom build products directory
+ # (<rdar://problem/5585899>).
+ my $personalPlistFile = $ENV{HOME} . "/Library/Preferences/xcodebuild.plist";
+ if (-e $personalPlistFile) {
+ unlink($personalPlistFile) || die "Could not delete $personalPlistFile: $!";
+ }
+
+ my $buildLocationStyle = join '', readXcodeUserDefault("IDEBuildLocationStyle");
+ if ($buildLocationStyle eq "Custom") {
+ my $buildLocationType = join '', readXcodeUserDefault("IDECustomBuildLocationType");
+ # FIXME: Read CustomBuildIntermediatesPath and set OBJROOT accordingly.
+ $baseProductDir = readXcodeUserDefault("IDECustomBuildProductsPath") if $buildLocationType eq "Absolute";
+ }
+
+ # DeterminedByTargets corresponds to a setting of "Legacy" in Xcode.
+ # It is the only build location style for which SHARED_PRECOMPS_DIR is not
+ # overridden when building from within Xcode.
+ $setSharedPrecompsDir = 1 if $buildLocationStyle ne "DeterminedByTargets";
+
+ if (!defined($baseProductDir)) {
+ $baseProductDir = join '', readXcodeUserDefault("IDEApplicationwideBuildSettings");
+ $baseProductDir = $1 if $baseProductDir =~ /SYMROOT\s*=\s*\"(.*?)\";/s;
+ }
+
+ undef $baseProductDir unless $baseProductDir =~ /^\//;
+ }
+
+ if (!defined($baseProductDir)) { # Port-specific checks failed, use default
+ $baseProductDir = File::Spec->catdir($sourceDir, "WebKitBuild");
+ }
+
+ if (isGit() && isGitBranchBuild()) {
+ my $branch = gitBranch();
+ $baseProductDir = "$baseProductDir/$branch";
+ }
+
+ if (isAppleCocoaWebKit()) {
+ $baseProductDir =~ s|^\Q$(SRCROOT)/..\E$|$sourceDir|;
+ $baseProductDir =~ s|^\Q$(SRCROOT)/../|$sourceDir/|;
+ $baseProductDir =~ s|^~/|$ENV{HOME}/|;
+ die "Can't handle Xcode product directory with a ~ in it.\n" if $baseProductDir =~ /~/;
+ die "Can't handle Xcode product directory with a variable in it.\n" if $baseProductDir =~ /\$/;
+ @baseProductDirOption = ("SYMROOT=$baseProductDir", "OBJROOT=$baseProductDir");
+ push(@baseProductDirOption, "SHARED_PRECOMPS_DIR=${baseProductDir}/PrecompiledHeaders") if $setSharedPrecompsDir;
+ }
+
+ if (isCygwin()) {
+ my $dosBuildPath = `cygpath --windows \"$baseProductDir\"`;
+ chomp $dosBuildPath;
+ $ENV{"WEBKIT_OUTPUTDIR"} = $dosBuildPath;
+ my $unixBuildPath = `cygpath --unix \"$baseProductDir\"`;
+ chomp $unixBuildPath;
+ $baseProductDir = $dosBuildPath;
+ }
+}
+
+sub systemVerbose {
+ print "+ @_\n";
+ return system(@_);
+}
+
+sub setBaseProductDir($)
+{
+ ($baseProductDir) = @_;
+}
+
+sub determineConfiguration
+{
+ return if defined $configuration;
+ determineBaseProductDir();
+ if (open CONFIGURATION, "$baseProductDir/Configuration") {
+ $configuration = <CONFIGURATION>;
+ close CONFIGURATION;
+ }
+ if ($configuration) {
+ chomp $configuration;
+ # compatibility for people who have old Configuration files
+ $configuration = "Release" if $configuration eq "Deployment";
+ $configuration = "Debug" if $configuration eq "Development";
+ } else {
+ $configuration = "Release";
+ }
+}
+
+sub determineArchitecture
+{
+ return if defined $architecture;
+ # make sure $architecture is defined in all cases
+ $architecture = "";
+
+ determineBaseProductDir();
+ determineXcodeSDK();
+
+ if (isAppleCocoaWebKit()) {
+ if (open ARCHITECTURE, "$baseProductDir/Architecture") {
+ $architecture = <ARCHITECTURE>;
+ close ARCHITECTURE;
+ }
+ if ($architecture) {
+ chomp $architecture;
+ } else {
+ if (not defined $xcodeSDK or $xcodeSDK =~ /^(\/$|macosx)/) {
+ my $supports64Bit = `sysctl -n hw.optional.x86_64`;
+ chomp $supports64Bit;
+ $architecture = 'x86_64' if $supports64Bit;
+ } elsif ($xcodeSDK =~ /^iphonesimulator/) {
+ $architecture = 'x86_64';
+ } elsif ($xcodeSDK =~ /^iphoneos/) {
+ $architecture = 'arm64';
+ }
+ }
+ } elsif (isCMakeBuild()) {
+ if (open my $cmake_sysinfo, "cmake --system-information |") {
+ while (<$cmake_sysinfo>) {
+ next unless index($_, 'CMAKE_SYSTEM_PROCESSOR') == 0;
+ if (/^CMAKE_SYSTEM_PROCESSOR \"([^"]+)\"/) {
+ $architecture = $1;
+ $architecture = 'x86_64' if $architecture eq 'amd64';
+ last;
+ }
+ }
+ close $cmake_sysinfo;
+ }
+ }
+
+ if (!isAnyWindows()) {
+ if (!$architecture) {
+ # Fall back to output of `arch', if it is present.
+ $architecture = `arch`;
+ chomp $architecture;
+ }
+
+ if (!$architecture) {
+ # Fall back to output of `uname -m', if it is present.
+ $architecture = `uname -m`;
+ chomp $architecture;
+ }
+ }
+
+ $architecture = 'x86_64' if ($architecture =~ /amd64/ && isBSD());
+}
+
+sub determineASanIsEnabled
+{
+ return if defined $asanIsEnabled;
+ determineBaseProductDir();
+
+ $asanIsEnabled = 0;
+ my $asanConfigurationValue;
+
+ if (open ASAN, "$baseProductDir/ASan") {
+ $asanConfigurationValue = <ASAN>;
+ close ASAN;
+ chomp $asanConfigurationValue;
+ $asanIsEnabled = 1 if $asanConfigurationValue eq "YES";
+ }
+}
+
+sub determineNumberOfCPUs
+{
+ return if defined $numberOfCPUs;
+ if (defined($ENV{NUMBER_OF_PROCESSORS})) {
+ $numberOfCPUs = $ENV{NUMBER_OF_PROCESSORS};
+ } elsif (isLinux()) {
+ # First try the nproc utility, if it exists. If we get no
+ # results fall back to just interpretting /proc directly.
+ chomp($numberOfCPUs = `nproc --all 2> /dev/null`);
+ if ($numberOfCPUs eq "") {
+ $numberOfCPUs = (grep /processor/, `cat /proc/cpuinfo`);
+ }
+ } elsif (isAnyWindows()) {
+ # Assumes cygwin
+ $numberOfCPUs = `ls /proc/registry/HKEY_LOCAL_MACHINE/HARDWARE/DESCRIPTION/System/CentralProcessor | wc -w`;
+ } elsif (isDarwin() || isBSD()) {
+ chomp($numberOfCPUs = `sysctl -n hw.ncpu`);
+ }
+}
+
+sub determineMaxCPULoad
+{
+ return if defined $maxCPULoad;
+ if (defined($ENV{MAX_CPU_LOAD})) {
+ $maxCPULoad = $ENV{MAX_CPU_LOAD};
+ }
+}
+
+sub jscPath($)
+{
+ my ($productDir) = @_;
+ my $jscName = "jsc";
+ $jscName .= "_debug" if configuration() eq "Debug_All";
+ $jscName .= ".exe" if (isAnyWindows());
+ return "$productDir/$jscName" if -e "$productDir/$jscName";
+ return "$productDir/JavaScriptCore.framework/Resources/$jscName";
+}
+
+sub argumentsForConfiguration()
+{
+ determineConfiguration();
+ determineArchitecture();
+ determineXcodeSDK();
+
+ my @args = ();
+ # FIXME: Is it necessary to pass --debug, --release, --32-bit or --64-bit?
+ # These are determined automatically from stored configuration.
+ push(@args, '--debug') if ($configuration =~ "^Debug");
+ push(@args, '--release') if ($configuration =~ "^Release");
+ push(@args, '--device') if (defined $xcodeSDK && $xcodeSDK =~ /^iphoneos/);
+ push(@args, '--ios-simulator') if (defined $xcodeSDK && $xcodeSDK =~ /^iphonesimulator/);
+ push(@args, '--32-bit') if ($architecture ne "x86_64" and !isWin64());
+ push(@args, '--64-bit') if (isWin64());
+ push(@args, '--gtk') if isGtk();
+ push(@args, '--efl') if isEfl();
+ push(@args, '--jsc-only') if isJSCOnly();
+ push(@args, '--wincairo') if isWinCairo();
+ push(@args, '--inspector-frontend') if isInspectorFrontend();
+ return @args;
+}
+
+sub determineXcodeSDK
+{
+ return if defined $xcodeSDK;
+ my $sdk;
+ if (checkForArgumentAndRemoveFromARGVGettingValue("--sdk", \$sdk)) {
+ $xcodeSDK = $sdk;
+ }
+ if (checkForArgumentAndRemoveFromARGV("--device")) {
+ my $hasInternalSDK = exitStatus(system("xcrun --sdk iphoneos.internal --show-sdk-version > /dev/null 2>&1")) == 0;
+ $xcodeSDK ||= $hasInternalSDK ? "iphoneos.internal" : "iphoneos";
+ }
+ if (checkForArgumentAndRemoveFromARGV("--ios-simulator")) {
+ $xcodeSDK ||= 'iphonesimulator';
+ }
+}
+
+sub xcodeSDK
+{
+ determineXcodeSDK();
+ return $xcodeSDK;
+}
+
+sub setXcodeSDK($)
+{
+ ($xcodeSDK) = @_;
+}
+
+
+sub xcodeSDKPlatformName()
+{
+ determineXcodeSDK();
+ return "" if !defined $xcodeSDK;
+ return "iphoneos" if $xcodeSDK =~ /iphoneos/i;
+ return "iphonesimulator" if $xcodeSDK =~ /iphonesimulator/i;
+ return "macosx" if $xcodeSDK =~ /macosx/i;
+ die "Couldn't determine platform name from Xcode SDK";
+}
+
+sub XcodeSDKPath
+{
+ determineXcodeSDK();
+
+ die "Can't find the SDK path because no Xcode SDK was specified" if not $xcodeSDK;
+
+ my $sdkPath = `xcrun --sdk $xcodeSDK --show-sdk-path` if $xcodeSDK;
+ die 'Failed to get SDK path from xcrun' if $?;
+ chomp $sdkPath;
+
+ return $sdkPath;
+}
+
+sub xcodeSDKVersion
+{
+ determineXcodeSDK();
+
+ die "Can't find the SDK version because no Xcode SDK was specified" if !$xcodeSDK;
+
+ chomp(my $sdkVersion = `xcrun --sdk $xcodeSDK --show-sdk-version`);
+ die "Failed to get SDK version from xcrun" if exitStatus($?);
+
+ return $sdkVersion;
+}
+
+sub programFilesPath
+{
+ return $programFilesPath if defined $programFilesPath;
+
+ $programFilesPath = $ENV{'PROGRAMFILES(X86)'} || $ENV{'PROGRAMFILES'} || "C:\\Program Files";
+
+ return $programFilesPath;
+}
+
+sub visualStudioInstallDir
+{
+ return $vsInstallDir if defined $vsInstallDir;
+
+ if ($ENV{'VSINSTALLDIR'}) {
+ $vsInstallDir = $ENV{'VSINSTALLDIR'};
+ $vsInstallDir =~ s|[\\/]$||;
+ } else {
+ $vsInstallDir = File::Spec->catdir(programFilesPath(), "Microsoft Visual Studio 14.0");
+ }
+ chomp($vsInstallDir = `cygpath "$vsInstallDir"`) if isCygwin();
+
+ print "Using Visual Studio: $vsInstallDir\n";
+ return $vsInstallDir;
+}
+
+sub msBuildInstallDir
+{
+ return $msBuildInstallDir if defined $msBuildInstallDir;
+
+ $msBuildInstallDir = File::Spec->catdir(programFilesPath(), "MSBuild", "14.0", "Bin");
+
+ chomp($msBuildInstallDir = `cygpath "$msBuildInstallDir"`) if isCygwin();
+
+ print "Using MSBuild: $msBuildInstallDir\n";
+ return $msBuildInstallDir;
+}
+
+sub visualStudioVersion
+{
+ return $vsVersion if defined $vsVersion;
+
+ my $installDir = visualStudioInstallDir();
+
+ $vsVersion = ($installDir =~ /Microsoft Visual Studio ([0-9]+\.[0-9]*)/) ? $1 : "14";
+
+ print "Using Visual Studio $vsVersion\n";
+ return $vsVersion;
+}
+
+sub determineConfigurationForVisualStudio
+{
+ return if defined $configurationForVisualStudio;
+ determineConfiguration();
+ # FIXME: We should detect when Debug_All or Production has been chosen.
+ $configurationForVisualStudio = "/p:Configuration=" . $configuration;
+}
+
+sub usesPerConfigurationBuildDirectory
+{
+ # [Gtk] We don't have Release/Debug configurations in straight
+ # autotool builds (non build-webkit). In this case and if
+ # WEBKIT_OUTPUTDIR exist, use that as our configuration dir. This will
+ # allows us to run run-webkit-tests without using build-webkit.
+ return ($ENV{"WEBKIT_OUTPUTDIR"} && isGtk()) || isAppleWinWebKit();
+}
+
+sub determineConfigurationProductDir
+{
+ return if defined $configurationProductDir;
+ determineBaseProductDir();
+ determineConfiguration();
+ if (isAppleWinWebKit() || isWinCairo()) {
+ $configurationProductDir = File::Spec->catdir($baseProductDir, $configuration);
+ } else {
+ if (usesPerConfigurationBuildDirectory()) {
+ $configurationProductDir = "$baseProductDir";
+ } else {
+ $configurationProductDir = "$baseProductDir/$configuration";
+ $configurationProductDir .= "-" . xcodeSDKPlatformName() if isIOSWebKit();
+ }
+ }
+}
+
+sub setConfigurationProductDir($)
+{
+ ($configurationProductDir) = @_;
+}
+
+sub determineCurrentSVNRevision
+{
+ # We always update the current SVN revision here, and leave the caching
+ # to currentSVNRevision(), so that changes to the SVN revision while the
+ # script is running can be picked up by calling this function again.
+ determineSourceDir();
+ $currentSVNRevision = svnRevisionForDirectory($sourceDir);
+ return $currentSVNRevision;
+}
+
+
+sub chdirWebKit
+{
+ determineSourceDir();
+ chdir $sourceDir or die;
+}
+
+sub baseProductDir
+{
+ determineBaseProductDir();
+ return $baseProductDir;
+}
+
+sub sourceDir
+{
+ determineSourceDir();
+ return $sourceDir;
+}
+
+sub productDir
+{
+ determineConfigurationProductDir();
+ return $configurationProductDir;
+}
+
+sub executableProductDir
+{
+ my $productDirectory = productDir();
+
+ my $binaryDirectory;
+ if (isEfl() || isGtk() || isJSCOnly()) {
+ $binaryDirectory = "bin";
+ } elsif (isAnyWindows()) {
+ $binaryDirectory = isWin64() ? "bin64" : "bin32";
+ } else {
+ return $productDirectory;
+ }
+
+ return File::Spec->catdir($productDirectory, $binaryDirectory);
+}
+
+sub jscProductDir
+{
+ return executableProductDir();
+}
+
+sub configuration()
+{
+ determineConfiguration();
+ return $configuration;
+}
+
+sub asanIsEnabled()
+{
+ determineASanIsEnabled();
+ return $asanIsEnabled;
+}
+
+sub configurationForVisualStudio()
+{
+ determineConfigurationForVisualStudio();
+ return $configurationForVisualStudio;
+}
+
+sub currentSVNRevision
+{
+ determineCurrentSVNRevision() if not defined $currentSVNRevision;
+ return $currentSVNRevision;
+}
+
+sub generateDsym()
+{
+ determineGenerateDsym();
+ return $generateDsym;
+}
+
+sub determineGenerateDsym()
+{
+ return if defined($generateDsym);
+ $generateDsym = checkForArgumentAndRemoveFromARGV("--dsym");
+}
+
+sub hasIOSDevelopmentCertificate()
+{
+ return !exitStatus(system("security find-identity -p codesigning | grep '" . IOS_DEVELOPMENT_CERTIFICATE_NAME_PREFIX . "' > /dev/null 2>&1"));
+}
+
+sub argumentsForXcode()
+{
+ my @args = ();
+ push @args, "DEBUG_INFORMATION_FORMAT=dwarf-with-dsym" if generateDsym();
+ return @args;
+}
+
+sub XcodeOptions
+{
+ determineBaseProductDir();
+ determineConfiguration();
+ determineArchitecture();
+ determineASanIsEnabled();
+ determineXcodeSDK();
+
+ my @options;
+ push @options, "-UseSanitizedBuildSystemEnvironment=YES";
+ push @options, ("-configuration", $configuration);
+ push @options, ("-xcconfig", sourceDir() . "/Tools/asan/asan.xcconfig", "ASAN_IGNORE=" . sourceDir() . "/Tools/asan/webkit-asan-ignore.txt") if $asanIsEnabled;
+ push @options, @baseProductDirOption;
+ push @options, "ARCHS=$architecture" if $architecture;
+ push @options, "SDKROOT=$xcodeSDK" if $xcodeSDK;
+ if (willUseIOSDeviceSDK()) {
+ push @options, "ENABLE_BITCODE=NO";
+ if (hasIOSDevelopmentCertificate()) {
+ # FIXME: May match more than one installed development certificate.
+ push @options, "CODE_SIGN_IDENTITY=" . IOS_DEVELOPMENT_CERTIFICATE_NAME_PREFIX;
+ } else {
+ push @options, "CODE_SIGN_IDENTITY="; # No identity
+ push @options, "CODE_SIGNING_REQUIRED=NO";
+ }
+ }
+ push @options, argumentsForXcode();
+ return @options;
+}
+
+sub XcodeOptionString
+{
+ return join " ", XcodeOptions();
+}
+
+sub XcodeOptionStringNoConfig
+{
+ return join " ", @baseProductDirOption;
+}
+
+sub XcodeCoverageSupportOptions()
+{
+ my @coverageSupportOptions = ();
+ push @coverageSupportOptions, "GCC_GENERATE_TEST_COVERAGE_FILES=YES";
+ push @coverageSupportOptions, "GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES";
+ return @coverageSupportOptions;
+}
+
+sub XcodeStaticAnalyzerOption()
+{
+ return "RUN_CLANG_STATIC_ANALYZER=YES";
+}
+
+my $passedConfiguration;
+my $searchedForPassedConfiguration;
+sub determinePassedConfiguration
+{
+ return if $searchedForPassedConfiguration;
+ $searchedForPassedConfiguration = 1;
+ $passedConfiguration = undef;
+
+ if (checkForArgumentAndRemoveFromARGV("--debug")) {
+ $passedConfiguration = "Debug";
+ } elsif(checkForArgumentAndRemoveFromARGV("--release")) {
+ $passedConfiguration = "Release";
+ } elsif (checkForArgumentAndRemoveFromARGV("--profile") || checkForArgumentAndRemoveFromARGV("--profiling")) {
+ $passedConfiguration = "Profiling";
+ }
+}
+
+sub passedConfiguration
+{
+ determinePassedConfiguration();
+ return $passedConfiguration;
+}
+
+sub setConfiguration
+{
+ setArchitecture();
+
+ if (my $config = shift @_) {
+ $configuration = $config;
+ return;
+ }
+
+ determinePassedConfiguration();
+ $configuration = $passedConfiguration if $passedConfiguration;
+}
+
+
+my $passedArchitecture;
+my $searchedForPassedArchitecture;
+sub determinePassedArchitecture
+{
+ return if $searchedForPassedArchitecture;
+ $searchedForPassedArchitecture = 1;
+
+ $passedArchitecture = undef;
+ if (checkForArgumentAndRemoveFromARGV("--32-bit")) {
+ if (isAppleCocoaWebKit()) {
+ # PLATFORM_IOS: Don't run `arch` command inside Simulator environment
+ local %ENV = %ENV;
+ delete $ENV{DYLD_ROOT_PATH};
+ delete $ENV{DYLD_FRAMEWORK_PATH};
+
+ $passedArchitecture = `arch`;
+ chomp $passedArchitecture;
+ }
+ }
+}
+
+sub passedArchitecture
+{
+ determinePassedArchitecture();
+ return $passedArchitecture;
+}
+
+sub architecture()
+{
+ determineArchitecture();
+ return $architecture;
+}
+
+sub numberOfCPUs()
+{
+ determineNumberOfCPUs();
+ return $numberOfCPUs;
+}
+
+sub maxCPULoad()
+{
+ determineMaxCPULoad();
+ return $maxCPULoad;
+}
+
+sub setArchitecture
+{
+ if (my $arch = shift @_) {
+ $architecture = $arch;
+ return;
+ }
+
+ determinePassedArchitecture();
+ $architecture = $passedArchitecture if $passedArchitecture;
+}
+
+# Locate Safari.
+sub safariPath
+{
+ die "Safari path is only relevant on Apple Mac platform\n" unless isAppleCocoaWebKit();
+
+ my $safariPath;
+
+ # Use WEBKIT_SAFARI environment variable if present.
+ my $safariBundle = $ENV{WEBKIT_SAFARI};
+ if (!$safariBundle) {
+ determineConfigurationProductDir();
+ # Use Safari.app in product directory if present (good for Safari development team).
+ if (-d "$configurationProductDir/Safari.app") {
+ $safariBundle = "$configurationProductDir/Safari.app";
+ }
+ }
+
+ if ($safariBundle) {
+ $safariPath = "$safariBundle/Contents/MacOS/Safari";
+ } else {
+ $safariPath = "/Applications/Safari.app/Contents/MacOS/SafariForWebKitDevelopment";
+ }
+
+ die "Can't find executable at $safariPath.\n" if !-x $safariPath;
+ return $safariPath;
+}
+
+sub builtDylibPathForName
+{
+ my $libraryName = shift;
+ determineConfigurationProductDir();
+
+ if (isGtk()) {
+ my $extension = isDarwin() ? ".dylib" : ".so";
+ return "$configurationProductDir/lib/libwebkit2gtk-4.0" . $extension;
+ }
+ if (isEfl()) {
+ return "$configurationProductDir/lib/libewebkit2.so";
+ }
+ if (isIOSWebKit()) {
+ return "$configurationProductDir/$libraryName.framework/$libraryName";
+ }
+ if (isAppleCocoaWebKit()) {
+ return "$configurationProductDir/$libraryName.framework/Versions/A/$libraryName";
+ }
+ if (isAppleWinWebKit()) {
+ if ($libraryName eq "JavaScriptCore") {
+ return "$baseProductDir/lib/$libraryName.lib";
+ } else {
+ return "$baseProductDir/$libraryName.intermediate/$configuration/$libraryName.intermediate/$libraryName.lib";
+ }
+ }
+
+ die "Unsupported platform, can't determine built library locations.\nTry `build-webkit --help` for more information.\n";
+}
+
+# Check to see that all the frameworks are built.
+sub checkFrameworks # FIXME: This is a poor name since only the Mac calls built WebCore a Framework.
+{
+ return if isAnyWindows();
+ my @frameworks = ("JavaScriptCore", "WebCore");
+ push(@frameworks, "WebKit") if isAppleCocoaWebKit(); # FIXME: This seems wrong, all ports should have a WebKit these days.
+ for my $framework (@frameworks) {
+ my $path = builtDylibPathForName($framework);
+ die "Can't find built framework at \"$path\".\n" unless -e $path;
+ }
+}
+
+sub isInspectorFrontend()
+{
+ determineIsInspectorFrontend();
+ return $isInspectorFrontend;
+}
+
+sub determineIsInspectorFrontend()
+{
+ return if defined($isInspectorFrontend);
+ $isInspectorFrontend = checkForArgumentAndRemoveFromARGV("--inspector-frontend");
+}
+
+sub commandExists($)
+{
+ my $command = shift;
+ my $devnull = File::Spec->devnull();
+
+ if (isAnyWindows()) {
+ return exitStatus(system("where /q $command >$devnull 2>&1")) == 0;
+ }
+ return exitStatus(system("which $command >$devnull 2>&1")) == 0;
+}
+
+sub checkForArgumentAndRemoveFromARGV($)
+{
+ my $argToCheck = shift;
+ return checkForArgumentAndRemoveFromArrayRef($argToCheck, \@ARGV);
+}
+
+sub checkForArgumentAndRemoveFromArrayRefGettingValue($$$)
+{
+ my ($argToCheck, $valueRef, $arrayRef) = @_;
+ my $argumentStartRegEx = qr#^$argToCheck(?:=\S|$)#;
+ my $i = 0;
+ for (; $i < @$arrayRef; ++$i) {
+ last if $arrayRef->[$i] =~ $argumentStartRegEx;
+ }
+ if ($i >= @$arrayRef) {
+ return $$valueRef = undef;
+ }
+ my ($key, $value) = split("=", $arrayRef->[$i]);
+ splice(@$arrayRef, $i, 1);
+ if (defined($value)) {
+ # e.g. --sdk=iphonesimulator
+ return $$valueRef = $value;
+ }
+ return $$valueRef = splice(@$arrayRef, $i, 1); # e.g. --sdk iphonesimulator
+}
+
+sub checkForArgumentAndRemoveFromARGVGettingValue($$)
+{
+ my ($argToCheck, $valueRef) = @_;
+ return checkForArgumentAndRemoveFromArrayRefGettingValue($argToCheck, $valueRef, \@ARGV);
+}
+
+sub findMatchingArguments($$)
+{
+ my ($argToCheck, $arrayRef) = @_;
+ my @matchingIndices;
+ foreach my $index (0 .. $#$arrayRef) {
+ my $opt = $$arrayRef[$index];
+ if ($opt =~ /^$argToCheck$/i ) {
+ push(@matchingIndices, $index);
+ }
+ }
+ return @matchingIndices;
+}
+
+sub hasArgument($$)
+{
+ my ($argToCheck, $arrayRef) = @_;
+ my @matchingIndices = findMatchingArguments($argToCheck, $arrayRef);
+ return scalar @matchingIndices > 0;
+}
+
+sub checkForArgumentAndRemoveFromArrayRef
+{
+ my ($argToCheck, $arrayRef) = @_;
+ my @indicesToRemove = findMatchingArguments($argToCheck, $arrayRef);
+ my $removeOffset = 0;
+ foreach my $index (@indicesToRemove) {
+ splice(@$arrayRef, $index - $removeOffset++, 1);
+ }
+ return scalar @indicesToRemove > 0;
+}
+
+sub prohibitUnknownPort()
+{
+ $unknownPortProhibited = 1;
+}
+
+sub determinePortName()
+{
+ return if defined $portName;
+
+ my %argToPortName = (
+ efl => Efl,
+ gtk => GTK,
+ 'jsc-only' => JSCOnly,
+ wincairo => WinCairo
+ );
+
+ for my $arg (sort keys %argToPortName) {
+ if (checkForArgumentAndRemoveFromARGV("--$arg")) {
+ die "Argument '--$arg' conflicts with selected port '$portName'\n"
+ if defined $portName;
+
+ $portName = $argToPortName{$arg};
+ }
+ }
+
+ return if defined $portName;
+
+ # Port was not selected via command line, use appropriate default value
+
+ if (isAnyWindows()) {
+ $portName = AppleWin;
+ } elsif (isDarwin()) {
+ determineXcodeSDK();
+ if (willUseIOSDeviceSDK() || willUseIOSSimulatorSDK()) {
+ $portName = iOS;
+ } else {
+ $portName = Mac;
+ }
+ } else {
+ if ($unknownPortProhibited) {
+ my $portsChoice = join "\n\t", qw(
+ --efl
+ --gtk
+ --jsc-only
+ );
+ die "Please specify which WebKit port to build using one of the following options:"
+ . "\n\t$portsChoice\n";
+ }
+
+ # If script is run without arguments we cannot determine port
+ # TODO: This state should be outlawed
+ $portName = Unknown;
+ }
+}
+
+sub portName()
+{
+ determinePortName();
+ return $portName;
+}
+
+sub isEfl()
+{
+ return portName() eq Efl;
+}
+
+sub isGtk()
+{
+ return portName() eq GTK;
+}
+
+sub isJSCOnly()
+{
+ return portName() eq JSCOnly;
+}
+
+# Determine if this is debian, ubuntu, linspire, or something similar.
+sub isDebianBased()
+{
+ return -e "/etc/debian_version";
+}
+
+sub isFedoraBased()
+{
+ return -e "/etc/fedora-release";
+}
+
+sub isWinCairo()
+{
+ return portName() eq WinCairo;
+}
+
+sub isWin64()
+{
+ determineIsWin64();
+ return $isWin64;
+}
+
+sub determineIsWin64()
+{
+ return if defined($isWin64);
+ $isWin64 = checkForArgumentAndRemoveFromARGV("--64-bit");
+}
+
+sub determineIsWin64FromArchitecture($)
+{
+ my $arch = shift;
+ $isWin64 = ($arch eq "x86_64");
+ return $isWin64;
+}
+
+sub isCygwin()
+{
+ return ($^O eq "cygwin") || 0;
+}
+
+sub isAnyWindows()
+{
+ return isWindows() || isCygwin();
+}
+
+sub determineWinVersion()
+{
+ return if $winVersion;
+
+ if (!isAnyWindows()) {
+ $winVersion = -1;
+ return;
+ }
+
+ my $versionString = `cmd /c ver`;
+ $versionString =~ /(\d)\.(\d)\.(\d+)/;
+
+ $winVersion = {
+ major => $1,
+ minor => $2,
+ build => $3,
+ };
+}
+
+sub winVersion()
+{
+ determineWinVersion();
+ return $winVersion;
+}
+
+sub isWindows7SP0()
+{
+ return isAnyWindows() && winVersion()->{major} == 6 && winVersion()->{minor} == 1 && winVersion()->{build} == 7600;
+}
+
+sub isWindowsVista()
+{
+ return isAnyWindows() && winVersion()->{major} == 6 && winVersion()->{minor} == 0;
+}
+
+sub isWindowsXP()
+{
+ return isAnyWindows() && winVersion()->{major} == 5 && winVersion()->{minor} == 1;
+}
+
+sub isDarwin()
+{
+ return ($^O eq "darwin") || 0;
+}
+
+sub isWindows()
+{
+ return ($^O eq "MSWin32") || 0;
+}
+
+sub isLinux()
+{
+ return ($^O eq "linux") || 0;
+}
+
+sub isBSD()
+{
+ return ($^O eq "freebsd") || ($^O eq "openbsd") || ($^O eq "netbsd") || 0;
+}
+
+sub isARM()
+{
+ return ($Config{archname} =~ /^arm[v\-]/) || ($Config{archname} =~ /^aarch64[v\-]/);
+}
+
+sub isX86_64()
+{
+ return (architecture() eq "x86_64") || 0;
+}
+
+sub isCrossCompilation()
+{
+ my $compiler = "";
+ $compiler = $ENV{'CC'} if (defined($ENV{'CC'}));
+ if ($compiler =~ /gcc/) {
+ my $compiler_options = `$compiler -v 2>&1`;
+ my @host = $compiler_options =~ m/--host=(.*?)\s/;
+ my @target = $compiler_options =~ m/--target=(.*?)\s/;
+
+ return ($host[0] ne "" && $target[0] ne "" && $host[0] ne $target[0]);
+ }
+ return 0;
+}
+
+sub isAppleWebKit()
+{
+ return isAppleCocoaWebKit() || isAppleWinWebKit();
+}
+
+sub isAppleCocoaWebKit()
+{
+ return (portName() eq Mac) || isIOSWebKit();
+}
+
+sub isAppleWinWebKit()
+{
+ return portName() eq AppleWin;
+}
+
+sub iOSSimulatorDevicesPath
+{
+ return "$ENV{HOME}/Library/Developer/CoreSimulator/Devices";
+}
+
+sub iOSSimulatorDevices
+{
+ eval "require Foundation";
+ my $devicesPath = iOSSimulatorDevicesPath();
+ opendir(DEVICES, $devicesPath);
+ my @udids = grep {
+ $_ =~ m/^[0-9A-F]{8}-([0-9A-F]{4}-){3}[0-9A-F]{12}$/;
+ } readdir(DEVICES);
+ close(DEVICES);
+
+ # FIXME: We should parse the device.plist file ourself and map the dictionary keys in it to known
+ # dictionary keys so as to decouple our representation of the plist from the actual structure
+ # of the plist, which may change.
+ my @devices = map {
+ Foundation::perlRefFromObjectRef(NSDictionary->dictionaryWithContentsOfFile_("$devicesPath/$_/device.plist"));
+ } @udids;
+
+ return @devices;
+}
+
+sub createiOSSimulatorDevice
+{
+ my $name = shift;
+ my $deviceTypeId = shift;
+ my $runtimeId = shift;
+
+ my $created = system("xcrun", "--sdk", "iphonesimulator", "simctl", "create", $name, $deviceTypeId, $runtimeId) == 0;
+ die "Couldn't create simulator device: $name $deviceTypeId $runtimeId" if not $created;
+
+ system("xcrun", "--sdk", "iphonesimulator", "simctl", "list");
+
+ print "Waiting for device to be created ...\n";
+ sleep 5;
+ for (my $tries = 0; $tries < 5; $tries++){
+ my @devices = iOSSimulatorDevices();
+ foreach my $device (@devices) {
+ return $device if $device->{name} eq $name and $device->{deviceType} eq $deviceTypeId and $device->{runtime} eq $runtimeId;
+ }
+ sleep 5;
+ }
+ die "Device $name $deviceTypeId $runtimeId wasn't found in " . iOSSimulatorDevicesPath();
+}
+
+sub willUseIOSDeviceSDK()
+{
+ return xcodeSDKPlatformName() eq "iphoneos";
+}
+
+sub willUseIOSSimulatorSDK()
+{
+ return xcodeSDKPlatformName() eq "iphonesimulator";
+}
+
+sub isIOSWebKit()
+{
+ return portName() eq iOS;
+}
+
+sub determineNmPath()
+{
+ return if $nmPath;
+
+ if (isAppleCocoaWebKit()) {
+ $nmPath = `xcrun -find nm`;
+ chomp $nmPath;
+ }
+ $nmPath = "nm" if !$nmPath;
+}
+
+sub nmPath()
+{
+ determineNmPath();
+ return $nmPath;
+}
+
+sub splitVersionString
+{
+ my $versionString = shift;
+ my @splitVersion = split(/\./, $versionString);
+ @splitVersion >= 2 or die "Invalid version $versionString";
+ $osXVersion = {
+ "major" => $splitVersion[0],
+ "minor" => $splitVersion[1],
+ "subminor" => (defined($splitVersion[2]) ? $splitVersion[2] : 0),
+ };
+}
+
+sub determineOSXVersion()
+{
+ return if $osXVersion;
+
+ if (!isDarwin()) {
+ $osXVersion = -1;
+ return;
+ }
+
+ my $versionString = `sw_vers -productVersion`;
+ $osXVersion = splitVersionString($versionString);
+}
+
+sub osXVersion()
+{
+ determineOSXVersion();
+ return $osXVersion;
+}
+
+sub determineIOSVersion()
+{
+ return if $iosVersion;
+
+ if (!isIOSWebKit()) {
+ $iosVersion = -1;
+ return;
+ }
+
+ my $versionString = xcodeSDKVersion();
+ $iosVersion = splitVersionString($versionString);
+}
+
+sub iosVersion()
+{
+ determineIOSVersion();
+ return $iosVersion;
+}
+
+sub isWindowsNT()
+{
+ return $ENV{'OS'} eq 'Windows_NT';
+}
+
+sub appendToEnvironmentVariableList($$)
+{
+ my ($name, $value) = @_;
+
+ if (defined($ENV{$name})) {
+ $ENV{$name} .= $Config{path_sep} . $value;
+ } else {
+ $ENV{$name} = $value;
+ }
+}
+
+sub prependToEnvironmentVariableList($$)
+{
+ my ($name, $value) = @_;
+
+ if (defined($ENV{$name})) {
+ $ENV{$name} = $value . $Config{path_sep} . $ENV{$name};
+ } else {
+ $ENV{$name} = $value;
+ }
+}
+
+sub sharedCommandLineOptions()
+{
+ return (
+ "g|guard-malloc" => \$shouldUseGuardMalloc,
+ );
+}
+
+sub sharedCommandLineOptionsUsage
+{
+ my %opts = @_;
+
+ my %switches = (
+ '-g|--guard-malloc' => 'Use guardmalloc when running executable',
+ );
+
+ my $indent = " " x ($opts{indent} || 2);
+ my $switchWidth = List::Util::max(int($opts{switchWidth}), List::Util::max(map { length($_) } keys %switches) + ($opts{brackets} ? 2 : 0));
+
+ my $result = "Common switches:\n";
+
+ for my $switch (keys %switches) {
+ my $switchName = $opts{brackets} ? "[" . $switch . "]" : $switch;
+ $result .= sprintf("%s%-" . $switchWidth . "s %s\n", $indent, $switchName, $switches{$switch});
+ }
+
+ return $result;
+}
+
+sub setUpGuardMallocIfNeeded
+{
+ if (!isDarwin()) {
+ return;
+ }
+
+ if (!defined($shouldUseGuardMalloc)) {
+ $shouldUseGuardMalloc = checkForArgumentAndRemoveFromARGV("-g") || checkForArgumentAndRemoveFromARGV("--guard-malloc");
+ }
+
+ if ($shouldUseGuardMalloc) {
+ appendToEnvironmentVariableList("DYLD_INSERT_LIBRARIES", "/usr/lib/libgmalloc.dylib");
+ appendToEnvironmentVariableList("__XPC_DYLD_INSERT_LIBRARIES", "/usr/lib/libgmalloc.dylib");
+ }
+}
+
+sub relativeScriptsDir()
+{
+ my $scriptDir = File::Spec->catpath("", File::Spec->abs2rel($FindBin::Bin, getcwd()), "");
+ if ($scriptDir eq "") {
+ $scriptDir = ".";
+ }
+ return $scriptDir;
+}
+
+sub launcherPath()
+{
+ my $relativeScriptsPath = relativeScriptsDir();
+ if (isGtk() || isEfl()) {
+ return "$relativeScriptsPath/run-minibrowser";
+ } elsif (isAppleWebKit()) {
+ return "$relativeScriptsPath/run-safari";
+ }
+}
+
+sub launcherName()
+{
+ if (isGtk() || isEfl()) {
+ return "MiniBrowser";
+ } elsif (isAppleCocoaWebKit()) {
+ return "Safari";
+ } elsif (isAppleWinWebKit()) {
+ return "MiniBrowser";
+ }
+}
+
+sub checkRequiredSystemConfig
+{
+ if (isDarwin()) {
+ chomp(my $productVersion = `sw_vers -productVersion`);
+ if (eval "v$productVersion" lt v10.10.5) {
+ print "*************************************************************\n";
+ print "OS X Yosemite v10.10.5 or later is required to build WebKit.\n";
+ print "You have " . $productVersion . ", thus the build will most likely fail.\n";
+ print "*************************************************************\n";
+ }
+ determineXcodeVersion();
+ if (eval "v$xcodeVersion" lt v7.0) {
+ print "*************************************************************\n";
+ print "Xcode 7.0 or later is required to build WebKit.\n";
+ print "You have an earlier version of Xcode, thus the build will\n";
+ print "most likely fail. The latest Xcode is available from the App Store.\n";
+ print "*************************************************************\n";
+ }
+ }
+}
+
+sub determineWindowsSourceDir()
+{
+ return if $windowsSourceDir;
+ $windowsSourceDir = sourceDir();
+ chomp($windowsSourceDir = `cygpath -w '$windowsSourceDir'`) if isCygwin();
+}
+
+sub windowsSourceDir()
+{
+ determineWindowsSourceDir();
+ return $windowsSourceDir;
+}
+
+sub windowsSourceSourceDir()
+{
+ return File::Spec->catdir(windowsSourceDir(), "Source");
+}
+
+sub windowsLibrariesDir()
+{
+ return File::Spec->catdir(windowsSourceDir(), "WebKitLibraries", "win");
+}
+
+sub windowsOutputDir()
+{
+ return File::Spec->catdir(windowsSourceDir(), "WebKitBuild");
+}
+
+sub fontExists($)
+{
+ my $font = shift;
+ my $cmd = "reg query \"HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts\" /v \"$font\" 2>&1";
+ my $val = `$cmd`;
+ return $? == 0;
+}
+
+sub checkInstalledTools()
+{
+ # environment variables. Avoid until this is corrected.
+ my $pythonVer = `python --version 2>&1`;
+ die "You must have Python installed to build WebKit.\n" if ($?);
+
+ # cURL 7.34.0 has a bug that prevents authentication with opensource.apple.com (and other things using SSL3).
+ my $curlVer = `curl --version 2> NUL`;
+ if (!$? and $curlVer =~ "(.*curl.*)") {
+ $curlVer = $1;
+ if ($curlVer =~ /libcurl\/7\.34\.0/) {
+ print "cURL version 7.34.0 has a bug that prevents authentication with SSL v2 or v3.\n";
+ print "cURL 7.33.0 is known to work. The cURL projects is preparing an update to\n";
+ print "correct this problem.\n\n";
+ die "Please install a working cURL and try again.\n";
+ }
+ }
+
+ # MathML requires fonts that may not ship with Windows.
+ # Warn the user if they are missing.
+ my @fonts = ('Cambria & Cambria Math (TrueType)', 'LatinModernMath-Regular (TrueType)', 'STIXMath-Regular (TrueType)');
+ my @missing = ();
+ foreach my $font (@fonts) {
+ push @missing, $font if not fontExists($font);
+ }
+
+ if (scalar @missing > 0) {
+ print "*************************************************************\n";
+ print "Mathematical fonts, such as Latin Modern Math are needed to\n";
+ print "use the MathML feature. You do not appear to have these fonts\n";
+ print "on your system.\n\n";
+ print "You can download a suitable set of fonts from the following URL:\n";
+ print "https://trac.webkit.org/wiki/MathML/Fonts\n";
+ print "*************************************************************\n";
+ }
+
+ print "Installed tools are correct for the WebKit build.\n";
+}
+
+sub setupAppleWinEnv()
+{
+ return unless isAppleWinWebKit();
+
+ checkInstalledTools();
+
+ if (isWindowsNT()) {
+ my $restartNeeded = 0;
+ my %variablesToSet = ();
+
+ # FIXME: We should remove this explicit version check for cygwin once we stop supporting Cygwin 1.7.9 or older versions.
+ # https://bugs.webkit.org/show_bug.cgi?id=85791
+ my $uname_version = (POSIX::uname())[2];
+ $uname_version =~ s/\(.*\)//; # Remove the trailing cygwin version, if any.
+ $uname_version =~ s/\-.*$//; # Remove trailing dash-version content, if any
+ if (version->parse($uname_version) < version->parse("1.7.10")) {
+ # Setting the environment variable 'CYGWIN' to 'tty' makes cygwin enable extra support (i.e., termios)
+ # for UNIX-like ttys in the Windows console
+ $variablesToSet{CYGWIN} = "tty" unless $ENV{CYGWIN};
+ }
+
+ # Those environment variables must be set to be able to build inside Visual Studio.
+ $variablesToSet{WEBKIT_LIBRARIES} = windowsLibrariesDir() unless $ENV{WEBKIT_LIBRARIES};
+ $variablesToSet{WEBKIT_OUTPUTDIR} = windowsOutputDir() unless $ENV{WEBKIT_OUTPUTDIR};
+ $variablesToSet{MSBUILDDISABLENODEREUSE} = "1" unless $ENV{MSBUILDDISABLENODEREUSE};
+ $variablesToSet{_IsNativeEnvironment} = "true" unless $ENV{_IsNativeEnvironment};
+ $variablesToSet{PreferredToolArchitecture} = "x64" unless $ENV{PreferredToolArchitecture};
+
+ foreach my $variable (keys %variablesToSet) {
+ print "Setting the Environment Variable '" . $variable . "' to '" . $variablesToSet{$variable} . "'\n\n";
+ my $ret = system "setx", $variable, $variablesToSet{$variable};
+ if ($ret != 0) {
+ system qw(regtool -s set), '\\HKEY_CURRENT_USER\\Environment\\' . $variable, $variablesToSet{$variable};
+ }
+ $restartNeeded ||= $variable eq "WEBKIT_LIBRARIES" || $variable eq "WEBKIT_OUTPUTDIR";
+ }
+
+ if ($restartNeeded) {
+ print "Please restart your computer before attempting to build inside Visual Studio.\n\n";
+ }
+ } else {
+ if (!defined $ENV{'WEBKIT_LIBRARIES'} || !$ENV{'WEBKIT_LIBRARIES'}) {
+ print "Warning: You must set the 'WebKit_Libraries' environment variable\n";
+ print " to be able build WebKit from within Visual Studio 2013 and newer.\n";
+ print " Make sure that 'WebKit_Libraries' points to the\n";
+ print " 'WebKitLibraries/win' directory, not the 'WebKitLibraries/' directory.\n\n";
+ }
+ if (!defined $ENV{'WEBKIT_OUTPUTDIR'} || !$ENV{'WEBKIT_OUTPUTDIR'}) {
+ print "Warning: You must set the 'WebKit_OutputDir' environment variable\n";
+ print " to be able build WebKit from within Visual Studio 2013 and newer.\n\n";
+ }
+ if (!defined $ENV{'MSBUILDDISABLENODEREUSE'} || !$ENV{'MSBUILDDISABLENODEREUSE'}) {
+ print "Warning: You should set the 'MSBUILDDISABLENODEREUSE' environment variable to '1'\n";
+ print " to avoid periodic locked log files when building.\n\n";
+ }
+ }
+ # FIXME (125180): Remove the following temporary 64-bit support once official support is available.
+ if (isWin64() and !$ENV{'WEBKIT_64_SUPPORT'}) {
+ print "Warning: You must set the 'WEBKIT_64_SUPPORT' environment variable\n";
+ print " to be able run WebKit or JavaScriptCore tests.\n\n";
+ }
+}
+
+sub setupCygwinEnv()
+{
+ return if !isAnyWindows();
+ return if $vcBuildPath;
+
+ my $programFilesPath = programFilesPath();
+ my $visualStudioPath = File::Spec->catfile(visualStudioInstallDir(), qw(Common7 IDE devenv.com));
+ if (-e $visualStudioPath) {
+ # Visual Studio is installed;
+ if (visualStudioVersion() eq "12") {
+ $visualStudioPath = File::Spec->catfile(visualStudioInstallDir(), qw(Common7 IDE devenv.exe));
+ }
+ } else {
+ # Visual Studio not found, try VC++ Express
+ $visualStudioPath = File::Spec->catfile(visualStudioInstallDir(), qw(Common7 IDE WDExpress.exe));
+ if (! -e $visualStudioPath) {
+ print "*************************************************************\n";
+ print "Cannot find '$visualStudioPath'\n";
+ print "Please execute the file 'vcvars32.bat' from\n";
+ print "'$programFilesPath\\Microsoft Visual Studio 14.0\\VC\\bin\\'\n";
+ print "to setup the necessary environment variables.\n";
+ print "*************************************************************\n";
+ die;
+ }
+ $willUseVCExpressWhenBuilding = 1;
+ }
+
+ print "Building results into: ", baseProductDir(), "\n";
+ print "WEBKIT_OUTPUTDIR is set to: ", $ENV{"WEBKIT_OUTPUTDIR"}, "\n";
+ print "WEBKIT_LIBRARIES is set to: ", $ENV{"WEBKIT_LIBRARIES"}, "\n";
+ # FIXME (125180): Remove the following temporary 64-bit support once official support is available.
+ print "WEBKIT_64_SUPPORT is set to: ", $ENV{"WEBKIT_64_SUPPORT"}, "\n" if isWin64();
+
+ # We will actually use MSBuild to build WebKit, but we need to find the Visual Studio install (above) to make
+ # sure we use the right options.
+ $vcBuildPath = File::Spec->catfile(msBuildInstallDir(), qw(MSBuild.exe));
+ if (! -e $vcBuildPath) {
+ print "*************************************************************\n";
+ print "Cannot find '$vcBuildPath'\n";
+ print "Please make sure execute that the Microsoft .NET Framework SDK\n";
+ print "is installed on this machine.\n";
+ print "*************************************************************\n";
+ die;
+ }
+}
+
+sub dieIfWindowsPlatformSDKNotInstalled
+{
+ my $registry32Path = "/proc/registry/";
+ my $registry64Path = "/proc/registry64/";
+ my @windowsPlatformSDKRegistryEntries = (
+ "HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SDKs/Windows/v8.0A",
+ "HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SDKs/Windows/v8.0",
+ "HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SDKs/Windows/v7.1A",
+ "HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SDKs/Windows/v7.0A",
+ "HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/MicrosoftSDK/InstalledSDKs/D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1",
+ );
+
+ # FIXME: It would be better to detect whether we are using 32- or 64-bit Windows
+ # and only check the appropriate entry. But for now we just blindly check both.
+ my $recommendedPlatformSDK = $windowsPlatformSDKRegistryEntries[0];
+
+ while (@windowsPlatformSDKRegistryEntries) {
+ my $windowsPlatformSDKRegistryEntry = shift @windowsPlatformSDKRegistryEntries;
+ return if (-e $registry32Path . $windowsPlatformSDKRegistryEntry) || (-e $registry64Path . $windowsPlatformSDKRegistryEntry);
+ }
+
+ print "*************************************************************\n";
+ print "Cannot find registry entry '$recommendedPlatformSDK'.\n";
+ print "Please download and install the Microsoft Windows SDK\n";
+ print "from <http://www.microsoft.com/en-us/download/details.aspx?id=8279>.\n\n";
+ print "Then follow step 2 in the Windows section of the \"Installing Developer\n";
+ print "Tools\" instructions at <http://www.webkit.org/building/tools.html>.\n";
+ print "*************************************************************\n";
+ die;
+}
+
+sub buildXCodeProject($$@)
+{
+ my ($project, $clean, @extraOptions) = @_;
+
+ if ($clean) {
+ push(@extraOptions, "-alltargets");
+ push(@extraOptions, "clean");
+ }
+
+ chomp($ENV{DSYMUTIL_NUM_THREADS} = `sysctl -n hw.activecpu`);
+ return system "xcodebuild", "-project", "$project.xcodeproj", @extraOptions;
+}
+
+sub usingVisualStudioExpress()
+{
+ setupCygwinEnv();
+ return $willUseVCExpressWhenBuilding;
+}
+
+sub buildVisualStudioProject
+{
+ my ($project, $clean) = @_;
+ setupCygwinEnv();
+
+ my $config = configurationForVisualStudio();
+
+ dieIfWindowsPlatformSDKNotInstalled() if $willUseVCExpressWhenBuilding;
+
+ chomp($project = `cygpath -w "$project"`) if isCygwin();
+
+ my $action = "/t:build";
+ if ($clean) {
+ $action = "/t:clean";
+ }
+
+ my $platform = "/p:Platform=" . (isWin64() ? "x64" : "Win32");
+ my $logPath = File::Spec->catdir($baseProductDir, $configuration);
+ make_path($logPath) unless -d $logPath or $logPath eq ".";
+
+ my $errorLogFile = File::Spec->catfile($logPath, "webkit_errors.log");
+ chomp($errorLogFile = `cygpath -w "$errorLogFile"`) if isCygwin();
+ my $errorLogging = "/flp:LogFile=" . $errorLogFile . ";ErrorsOnly";
+
+ my $warningLogFile = File::Spec->catfile($logPath, "webkit_warnings.log");
+ chomp($warningLogFile = `cygpath -w "$warningLogFile"`) if isCygwin();
+ my $warningLogging = "/flp1:LogFile=" . $warningLogFile . ";WarningsOnly";
+
+ my @command = ($vcBuildPath, "/verbosity:minimal", $project, $action, $config, $platform, "/fl", $errorLogging, "/fl1", $warningLogging);
+ print join(" ", @command), "\n";
+ return system @command;
+}
+
+sub getJhbuildPath()
+{
+ my @jhbuildPath = File::Spec->splitdir(baseProductDir());
+ if (isGit() && isGitBranchBuild() && gitBranch()) {
+ pop(@jhbuildPath);
+ }
+ if (isEfl()) {
+ push(@jhbuildPath, "DependenciesEFL");
+ } elsif (isGtk()) {
+ push(@jhbuildPath, "DependenciesGTK");
+ } else {
+ die "Cannot get JHBuild path for platform that isn't GTK+ or EFL.\n";
+ }
+ return File::Spec->catdir(@jhbuildPath);
+}
+
+sub isCachedArgumentfileOutOfDate($@)
+{
+ my ($filename, $currentContents) = @_;
+
+ if (! -e $filename) {
+ return 1;
+ }
+
+ open(CONTENTS_FILE, $filename);
+ chomp(my $previousContents = <CONTENTS_FILE>);
+ close(CONTENTS_FILE);
+
+ if ($previousContents ne $currentContents) {
+ print "Contents for file $filename have changed.\n";
+ print "Previous contents were: $previousContents\n\n";
+ print "New contents are: $currentContents\n";
+ return 1;
+ }
+
+ return 0;
+}
+
+sub wrapperPrefixIfNeeded()
+{
+ if (isAnyWindows() || isJSCOnly()) {
+ return ();
+ }
+ if (isAppleCocoaWebKit()) {
+ return ("xcrun");
+ }
+ if (-e getJhbuildPath()) {
+ my @prefix = (File::Spec->catfile(sourceDir(), "Tools", "jhbuild", "jhbuild-wrapper"));
+ if (isEfl()) {
+ push(@prefix, "--efl");
+ } elsif (isGtk()) {
+ push(@prefix, "--gtk");
+ }
+ push(@prefix, "run");
+
+ return @prefix;
+ }
+
+ return ();
+}
+
+sub cmakeCachePath()
+{
+ return File::Spec->catdir(baseProductDir(), configuration(), "CMakeCache.txt");
+}
+
+sub cmakeFilesPath()
+{
+ return File::Spec->catdir(baseProductDir(), configuration(), "CMakeFiles");
+}
+
+sub shouldRemoveCMakeCache(@)
+{
+ my ($cacheFilePath, @buildArgs) = @_;
+
+ # We check this first, because we always want to create this file for a fresh build.
+ my $productDir = File::Spec->catdir(baseProductDir(), configuration());
+ my $optionsCache = File::Spec->catdir($productDir, "build-webkit-options.txt");
+ my $joinedBuildArgs = join(" ", @buildArgs);
+ if (isCachedArgumentfileOutOfDate($optionsCache, $joinedBuildArgs)) {
+ File::Path::mkpath($productDir) unless -d $productDir;
+ open(CACHED_ARGUMENTS, ">", $optionsCache);
+ print CACHED_ARGUMENTS $joinedBuildArgs;
+ close(CACHED_ARGUMENTS);
+
+ return 1;
+ }
+
+ my $cmakeCache = cmakeCachePath();
+ unless (-e $cmakeCache) {
+ return 0;
+ }
+
+ my $cacheFileModifiedTime = stat($cmakeCache)->mtime;
+ my $platformConfiguration = File::Spec->catdir(sourceDir(), "Source", "cmake", "Options" . cmakeBasedPortName() . ".cmake");
+ if ($cacheFileModifiedTime < stat($platformConfiguration)->mtime) {
+ return 1;
+ }
+
+ my $globalConfiguration = File::Spec->catdir(sourceDir(), "Source", "cmake", "OptionsCommon.cmake");
+ if ($cacheFileModifiedTime < stat($globalConfiguration)->mtime) {
+ return 1;
+ }
+
+ my $inspectorUserInterfaceDircetory = File::Spec->catdir(sourceDir(), "Source", "WebInspectorUI", "UserInterface");
+ if ($cacheFileModifiedTime < stat($inspectorUserInterfaceDircetory)->mtime) {
+ return 1;
+ }
+
+ if(isAnyWindows()) {
+ my $winConfiguration = File::Spec->catdir(sourceDir(), "Source", "cmake", "OptionsWin.cmake");
+ if ($cacheFileModifiedTime < stat($winConfiguration)->mtime) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+sub removeCMakeCache(@)
+{
+ my (@buildArgs) = @_;
+ if (shouldRemoveCMakeCache(@buildArgs)) {
+ my $cmakeCache = cmakeCachePath();
+ my $cmakeFiles = cmakeFilesPath();
+ unlink($cmakeCache) if -e $cmakeCache;
+ rmtree($cmakeFiles) if -d $cmakeFiles;
+ }
+}
+
+sub canUseNinja(@)
+{
+ if (!defined($shouldNotUseNinja)) {
+ $shouldNotUseNinja = checkForArgumentAndRemoveFromARGV("--no-ninja");
+ }
+
+ if ($shouldNotUseNinja) {
+ return 0;
+ }
+
+ # Test both ninja and ninja-build. Fedora uses ninja-build and has patched CMake to also call ninja-build.
+ return commandExists("ninja") || commandExists("ninja-build");
+}
+
+sub canUseNinjaGenerator(@)
+{
+ # Check that a Ninja generator is installed
+ my $devnull = File::Spec->devnull();
+ return exitStatus(system("cmake -N -G Ninja >$devnull 2>&1")) == 0;
+}
+
+sub canUseEclipseNinjaGenerator(@)
+{
+ # Check that eclipse and eclipse Ninja generator is installed
+ my $devnull = File::Spec->devnull();
+ return commandExists("eclipse") && exitStatus(system("cmake -N -G 'Eclipse CDT4 - Ninja' >$devnull 2>&1")) == 0;
+}
+
+sub cmakeGeneratedBuildfile(@)
+{
+ my ($willUseNinja) = @_;
+ if ($willUseNinja) {
+ return File::Spec->catfile(baseProductDir(), configuration(), "build.ninja")
+ } elsif (isAnyWindows()) {
+ return File::Spec->catfile(baseProductDir(), configuration(), "WebKit.sln")
+ } else {
+ return File::Spec->catfile(baseProductDir(), configuration(), "Makefile")
+ }
+}
+
+sub generateBuildSystemFromCMakeProject
+{
+ my ($prefixPath, @cmakeArgs) = @_;
+ my $config = configuration();
+ my $port = cmakeBasedPortName();
+ my $buildPath = File::Spec->catdir(baseProductDir(), $config);
+ File::Path::mkpath($buildPath) unless -d $buildPath;
+ my $originalWorkingDirectory = getcwd();
+ chdir($buildPath) or die;
+
+ # We try to be smart about when to rerun cmake, so that we can have faster incremental builds.
+ my $willUseNinja = canUseNinja() && canUseNinjaGenerator();
+ if (-e cmakeCachePath() && -e cmakeGeneratedBuildfile($willUseNinja)) {
+ return 0;
+ }
+
+ my @args;
+ push @args, "-DPORT=\"$port\"";
+ push @args, "-DCMAKE_INSTALL_PREFIX=\"$prefixPath\"" if $prefixPath;
+ push @args, "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON";
+ if ($config =~ /release/i) {
+ push @args, "-DCMAKE_BUILD_TYPE=Release";
+ } elsif ($config =~ /debug/i) {
+ push @args, "-DCMAKE_BUILD_TYPE=Debug";
+ }
+
+ if ($willUseNinja) {
+ push @args, "-G";
+ if (canUseEclipseNinjaGenerator()) {
+ push @args, "'Eclipse CDT4 - Ninja'";
+ } else {
+ push @args, "Ninja";
+ }
+ } elsif (isAnyWindows() && isWin64()) {
+ push @args, '-G "Visual Studio 14 2015 Win64"';
+ }
+ # Do not show progress of generating bindings in interactive Ninja build not to leave noisy lines on tty
+ push @args, '-DSHOW_BINDINGS_GENERATION_PROGRESS=1' unless ($willUseNinja && -t STDOUT);
+
+ # Some ports have production mode, but build-webkit should always use developer mode.
+ push @args, "-DDEVELOPER_MODE=ON" if isEfl() || isGtk() || isJSCOnly();
+
+ # Don't warn variables which aren't used by cmake ports.
+ push @args, "--no-warn-unused-cli";
+ push @args, @cmakeArgs if @cmakeArgs;
+
+ my $cmakeSourceDir = isCygwin() ? windowsSourceDir() : sourceDir();
+ push @args, '"' . $cmakeSourceDir . '"';
+
+ # Compiler options to keep floating point values consistent
+ # between 32-bit and 64-bit architectures.
+ determineArchitecture();
+ if ($architecture eq "i686" && !isCrossCompilation() && !isAnyWindows()) {
+ $ENV{'CXXFLAGS'} = "-march=pentium4 -msse2 -mfpmath=sse " . ($ENV{'CXXFLAGS'} || "");
+ }
+
+ # We call system("cmake @args") instead of system("cmake", @args) so that @args is
+ # parsed for shell metacharacters.
+ my $wrapper = join(" ", wrapperPrefixIfNeeded()) . " ";
+ my $returnCode = systemVerbose($wrapper . "cmake @args");
+
+ chdir($originalWorkingDirectory);
+ return $returnCode;
+}
+
+sub buildCMakeGeneratedProject($)
+{
+ my ($makeArgs) = @_;
+ my $config = configuration();
+ my $buildPath = File::Spec->catdir(baseProductDir(), $config);
+ if (! -d $buildPath) {
+ die "Must call generateBuildSystemFromCMakeProject() before building CMake project.";
+ }
+
+ my $command = "cmake";
+ my @args = ("--build", $buildPath, "--config", $config);
+ push @args, ("--", $makeArgs) if $makeArgs;
+
+ # GTK and JSCOnly can use a build script to preserve colors and pretty-printing.
+ if ((isGtk() || isJSCOnly()) && -e "$buildPath/build.sh") {
+ chdir "$buildPath" or die;
+ $command = "$buildPath/build.sh";
+ @args = ($makeArgs);
+ }
+
+ if ($ENV{VERBOSE} && canUseNinja()) {
+ push @args, "-v";
+ push @args, "-d keeprsp" if (version->parse(determineNinjaVersion()) >= version->parse("1.4.0"));
+ }
+
+ # We call system("cmake @args") instead of system("cmake", @args) so that @args is
+ # parsed for shell metacharacters. In particular, $makeArgs may contain such metacharacters.
+ my $wrapper = join(" ", wrapperPrefixIfNeeded()) . " ";
+ return systemVerbose($wrapper . "$command @args");
+}
+
+sub cleanCMakeGeneratedProject()
+{
+ my $config = configuration();
+ my $buildPath = File::Spec->catdir(baseProductDir(), $config);
+ if (-d $buildPath) {
+ return systemVerbose("cmake", "--build", $buildPath, "--config", $config, "--target", "clean");
+ }
+ return 0;
+}
+
+sub buildCMakeProjectOrExit($$$@)
+{
+ my ($clean, $prefixPath, $makeArgs, @cmakeArgs) = @_;
+ my $returnCode;
+
+ exit(exitStatus(cleanCMakeGeneratedProject())) if $clean;
+
+ if (isEfl() && checkForArgumentAndRemoveFromARGV("--update-efl")) {
+ system("perl", "$sourceDir/Tools/Scripts/update-webkitefl-libs") == 0 or die $!;
+ }
+
+ if (isGtk() && checkForArgumentAndRemoveFromARGV("--update-gtk")) {
+ system("perl", "$sourceDir/Tools/Scripts/update-webkitgtk-libs") == 0 or die $!;
+ }
+
+ $returnCode = exitStatus(generateBuildSystemFromCMakeProject($prefixPath, @cmakeArgs));
+ exit($returnCode) if $returnCode;
+
+ $returnCode = exitStatus(buildCMakeGeneratedProject($makeArgs));
+ exit($returnCode) if $returnCode;
+ return 0;
+}
+
+sub cmakeBasedPortArguments()
+{
+ return ();
+}
+
+sub cmakeBasedPortName()
+{
+ return ucfirst portName();
+}
+
+sub determineIsCMakeBuild()
+{
+ return if defined($isCMakeBuild);
+ $isCMakeBuild = checkForArgumentAndRemoveFromARGV("--cmake");
+}
+
+sub isCMakeBuild()
+{
+ return 1 unless isAppleCocoaWebKit();
+ determineIsCMakeBuild();
+ return $isCMakeBuild;
+}
+
+sub promptUser
+{
+ my ($prompt, $default) = @_;
+ my $defaultValue = $default ? "[$default]" : "";
+ print "$prompt $defaultValue: ";
+ chomp(my $input = <STDIN>);
+ return $input ? $input : $default;
+}
+
+sub appleApplicationSupportPath
+{
+ open INSTALL_DIR, "</proc/registry/HKEY_LOCAL_MACHINE/SOFTWARE/Apple\ Inc./Apple\ Application\ Support/InstallDir";
+ my $path = <INSTALL_DIR>;
+ $path =~ s/[\r\n\x00].*//;
+ close INSTALL_DIR;
+
+ my $unixPath = `cygpath -u '$path'`;
+ chomp $unixPath;
+ return $unixPath;
+}
+
+sub setPathForRunningWebKitApp
+{
+ my ($env) = @_;
+
+ if (isAnyWindows()) {
+ my $productBinaryDir = executableProductDir();
+ if (isAppleWinWebKit()) {
+ $env->{PATH} = join(':', $productBinaryDir, appleApplicationSupportPath(), $env->{PATH} || "");
+ } elsif (isWinCairo()) {
+ my $winCairoBin = sourceDir() . "/WebKitLibraries/win/" . (isWin64() ? "bin64/" : "bin32/");
+ my $gstreamerBin = isWin64() ? $ENV{"GSTREAMER_1_0_ROOT_X86_64"} . "bin" : $ENV{"GSTREAMER_1_0_ROOT_X86"} . "bin";
+ $env->{PATH} = join(':', $productBinaryDir, $winCairoBin, $gstreamerBin, $env->{PATH} || "");
+ }
+ }
+}
+
+sub printHelpAndExitForRunAndDebugWebKitAppIfNeeded
+{
+ return unless checkForArgumentAndRemoveFromARGV("--help");
+
+ print STDERR <<EOF;
+Usage: @{[basename($0)]} [options] [args ...]
+ --help Show this help message
+ --no-saved-state Launch the application without state restoration
+ -g|--guard-malloc Enable Guard Malloc (OS X only)
+EOF
+
+ exit(1);
+}
+
+sub argumentsForRunAndDebugMacWebKitApp()
+{
+ my @args = ();
+ if (checkForArgumentAndRemoveFromARGV("--no-saved-state")) {
+ push @args, ("-ApplePersistenceIgnoreStateQuietly", "YES");
+ # FIXME: Don't set ApplePersistenceIgnoreState once all supported OS versions respect ApplePersistenceIgnoreStateQuietly (rdar://15032886).
+ push @args, ("-ApplePersistenceIgnoreState", "YES");
+ }
+ unshift @args, @ARGV;
+
+ return @args;
+}
+
+sub setupMacWebKitEnvironment($)
+{
+ my ($dyldFrameworkPath) = @_;
+
+ $dyldFrameworkPath = File::Spec->rel2abs($dyldFrameworkPath);
+
+ prependToEnvironmentVariableList("DYLD_FRAMEWORK_PATH", $dyldFrameworkPath);
+ prependToEnvironmentVariableList("__XPC_DYLD_FRAMEWORK_PATH", $dyldFrameworkPath);
+ $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
+
+ setUpGuardMallocIfNeeded();
+}
+
+sub setupIOSWebKitEnvironment($)
+{
+ my ($dyldFrameworkPath) = @_;
+ $dyldFrameworkPath = File::Spec->rel2abs($dyldFrameworkPath);
+
+ prependToEnvironmentVariableList("DYLD_FRAMEWORK_PATH", $dyldFrameworkPath);
+ prependToEnvironmentVariableList("DYLD_LIBRARY_PATH", $dyldFrameworkPath);
+
+ setUpGuardMallocIfNeeded();
+}
+
+sub iosSimulatorApplicationsPath()
+{
+ return File::Spec->catdir(XcodeSDKPath(), "Applications");
+}
+
+sub installedMobileSafariBundle()
+{
+ return File::Spec->catfile(iosSimulatorApplicationsPath(), "MobileSafari.app");
+}
+
+sub mobileSafariBundle()
+{
+ determineConfigurationProductDir();
+
+ # Use MobileSafari.app in product directory if present.
+ if (isAppleCocoaWebKit() && -d "$configurationProductDir/MobileSafari.app") {
+ return "$configurationProductDir/MobileSafari.app";
+ }
+ return installedMobileSafariBundle();
+}
+
+sub plistPathFromBundle($)
+{
+ my ($appBundle) = @_;
+ return "$appBundle/Info.plist" if -f "$appBundle/Info.plist"; # iOS app bundle
+ return "$appBundle/Contents/Info.plist" if -f "$appBundle/Contents/Info.plist"; # Mac app bundle
+ return "";
+}
+
+sub appIdentifierFromBundle($)
+{
+ my ($appBundle) = @_;
+ my $plistPath = File::Spec->rel2abs(plistPathFromBundle($appBundle)); # defaults(1) will complain if the specified path is not absolute.
+ chomp(my $bundleIdentifier = `defaults read '$plistPath' CFBundleIdentifier 2> /dev/null`);
+ return $bundleIdentifier;
+}
+
+sub appDisplayNameFromBundle($)
+{
+ my ($appBundle) = @_;
+ my $plistPath = File::Spec->rel2abs(plistPathFromBundle($appBundle)); # defaults(1) will complain if the specified path is not absolute.
+ chomp(my $bundleDisplayName = `defaults read '$plistPath' CFBundleDisplayName 2> /dev/null`);
+ return $bundleDisplayName;
+}
+
+sub waitUntilIOSSimulatorDeviceIsInState($$)
+{
+ my ($deviceUDID, $waitUntilState) = @_;
+ my $device = iosSimulatorDeviceByUDID($deviceUDID);
+ # FIXME: We should add a maximum time limit to wait here.
+ while ($device->{state} ne $waitUntilState) {
+ usleep(500 * 1000); # Waiting 500ms between file system polls does not make script run-safari feel sluggish.
+ $device = iosSimulatorDeviceByUDID($deviceUDID);
+ }
+}
+
+sub shutDownIOSSimulatorDevice($)
+{
+ my ($simulatorDevice) = @_;
+ system("xcrun --sdk iphonesimulator simctl shutdown $simulatorDevice->{UDID} > /dev/null 2>&1");
+}
+
+sub restartIOSSimulatorDevice($)
+{
+ my ($simulatorDevice) = @_;
+ shutDownIOSSimulatorDevice($simulatorDevice);
+
+ exitStatus(system("xcrun", "--sdk", "iphonesimulator", "simctl", "boot", $simulatorDevice->{UDID})) == 0 or die "Failed to boot simulator device $simulatorDevice->{UDID}";
+}
+
+sub relaunchIOSSimulator($)
+{
+ my ($simulatedDevice) = @_;
+ quitIOSSimulator($simulatedDevice->{UDID});
+
+ # FIXME: <rdar://problem/20916140> Switch to using CoreSimulator.framework for launching and quitting iOS Simulator
+ chomp(my $developerDirectory = $ENV{DEVELOPER_DIR} || `xcode-select --print-path`);
+ my $iosSimulatorPath = File::Spec->catfile($developerDirectory, "Applications", "Simulator.app");
+ system("open", "-a", $iosSimulatorPath, "--args", "-CurrentDeviceUDID", $simulatedDevice->{UDID}) == 0 or die "Failed to open $iosSimulatorPath: $!";
+
+ waitUntilIOSSimulatorDeviceIsInState($simulatedDevice->{UDID}, SIMULATOR_DEVICE_STATE_BOOTED);
+}
+
+sub quitIOSSimulator(;$)
+{
+ my ($waitForShutdownOfSimulatedDeviceUDID) = @_;
+ # FIXME: <rdar://problem/20916140> Switch to using CoreSimulator.framework for launching and quitting iOS Simulator
+ if (exitStatus(system {"osascript"} "osascript", "-e", 'tell application id "com.apple.iphonesimulator" to quit')) {
+ # osascript returns a non-zero exit status if Simulator.app is not registered in LaunchServices.
+ return;
+ }
+
+ if (!defined($waitForShutdownOfSimulatedDeviceUDID)) {
+ return;
+ }
+ # FIXME: We assume that $waitForShutdownOfSimulatedDeviceUDID was not booted using the simctl command line tool.
+ # Otherwise we will spin indefinitely since quiting the iOS Simulator will not shutdown this device. We
+ # should add a maximum time limit to wait for a device to shutdown and either return an error or die()
+ # on expiration of the time limit.
+ waitUntilIOSSimulatorDeviceIsInState($waitForShutdownOfSimulatedDeviceUDID, SIMULATOR_DEVICE_STATE_SHUTDOWN);
+}
+
+sub iosSimulatorDeviceByName($)
+{
+ my ($simulatorName) = @_;
+ my $simulatorRuntime = iosSimulatorRuntime();
+ my @devices = iOSSimulatorDevices();
+ for my $device (@devices) {
+ if ($device->{name} eq $simulatorName && $device->{runtime} eq $simulatorRuntime) {
+ return $device;
+ }
+ }
+ return undef;
+}
+
+sub iosSimulatorDeviceByUDID($)
+{
+ my ($simulatedDeviceUDID) = @_;
+ my $devicePlistPath = File::Spec->catfile(iOSSimulatorDevicesPath(), $simulatedDeviceUDID, "device.plist");
+ if (!-f $devicePlistPath) {
+ return;
+ }
+ # FIXME: We should parse the device.plist file ourself and map the dictionary keys in it to known
+ # dictionary keys so as to decouple our representation of the plist from the actual structure
+ # of the plist, which may change.
+ eval "require Foundation";
+ return Foundation::perlRefFromObjectRef(NSDictionary->dictionaryWithContentsOfFile_($devicePlistPath));
+}
+
+sub iosSimulatorRuntime()
+{
+ my $xcodeSDKVersion = xcodeSDKVersion();
+ $xcodeSDKVersion =~ s/\./-/;
+ return "com.apple.CoreSimulator.SimRuntime.iOS-$xcodeSDKVersion";
+}
+
+sub findOrCreateSimulatorForIOSDevice($)
+{
+ my ($simulatorNameSuffix) = @_;
+ my $simulatorName;
+ my $simulatorDeviceType;
+ if (architecture() eq "x86_64") {
+ $simulatorName = "iPhone 5s " . $simulatorNameSuffix;
+ $simulatorDeviceType = "com.apple.CoreSimulator.SimDeviceType.iPhone-5s";
+ } else {
+ $simulatorName = "iPhone 5 " . $simulatorNameSuffix;
+ $simulatorDeviceType = "com.apple.CoreSimulator.SimDeviceType.iPhone-5";
+ }
+ my $simulatedDevice = iosSimulatorDeviceByName($simulatorName);
+ return $simulatedDevice if $simulatedDevice;
+ return createiOSSimulatorDevice($simulatorName, $simulatorDeviceType, iosSimulatorRuntime());
+}
+
+sub isIOSSimulatorSystemInstalledApp($)
+{
+ my ($appBundle) = @_;
+ my $simulatorApplicationsPath = realpath(iosSimulatorApplicationsPath());
+ return substr(realpath($appBundle), 0, length($simulatorApplicationsPath)) eq $simulatorApplicationsPath;
+}
+
+sub hasUserInstalledAppInSimulatorDevice($$)
+{
+ my ($appIdentifier, $simulatedDeviceUDID) = @_;
+ my $userInstalledAppPath = File::Spec->catfile($ENV{HOME}, "Library", "Developer", "CoreSimulator", "Devices", $simulatedDeviceUDID, "data", "Containers", "Bundle", "Application");
+ if (!-d $userInstalledAppPath) {
+ return 0; # No user installed apps.
+ }
+ local @::userInstalledAppBundles;
+ my $wantedFunction = sub {
+ my $file = $_;
+
+ # Ignore hidden files and directories.
+ if ($file =~ /^\../) {
+ $File::Find::prune = 1;
+ return;
+ }
+
+ return if !-d $file || $file !~ /\.app$/;
+ push @::userInstalledAppBundles, $File::Find::name;
+ $File::Find::prune = 1; # Do not traverse contents of app bundle.
+ };
+ find($wantedFunction, $userInstalledAppPath);
+ for my $userInstalledAppBundle (@::userInstalledAppBundles) {
+ if (appIdentifierFromBundle($userInstalledAppBundle) eq $appIdentifier) {
+ return 1; # Has user installed app.
+ }
+ }
+ return 0; # Does not have user installed app.
+}
+
+sub isSimulatorDeviceBooted($)
+{
+ my ($simulatedDeviceUDID) = @_;
+ my $device = iosSimulatorDeviceByUDID($simulatedDeviceUDID);
+ return $device && $device->{state} eq SIMULATOR_DEVICE_STATE_BOOTED;
+}
+
+sub runIOSWebKitAppInSimulator($;$)
+{
+ my ($appBundle, $simulatorOptions) = @_;
+ my $productDir = productDir();
+ my $appDisplayName = appDisplayNameFromBundle($appBundle);
+ my $appIdentifier = appIdentifierFromBundle($appBundle);
+ my $simulatedDevice = findOrCreateSimulatorForIOSDevice(SIMULATOR_DEVICE_SUFFIX_FOR_WEBKIT_DEVELOPMENT);
+ my $simulatedDeviceUDID = $simulatedDevice->{UDID};
+
+ my $willUseSystemInstalledApp = isIOSSimulatorSystemInstalledApp($appBundle);
+ if ($willUseSystemInstalledApp) {
+ if (hasUserInstalledAppInSimulatorDevice($appIdentifier, $simulatedDeviceUDID)) {
+ # Restore the system-installed app in the simulator device corresponding to $appBundle as it
+ # was previously overwritten with a custom built version of the app.
+ # FIXME: Only restore the system-installed version of the app instead of erasing all contents and settings.
+ print "Quitting iOS Simulator...\n";
+ quitIOSSimulator($simulatedDeviceUDID);
+ print "Erasing contents and settings for simulator device \"$simulatedDevice->{name}\".\n";
+ exitStatus(system("xcrun", "--sdk", "iphonesimulator", "simctl", "erase", $simulatedDeviceUDID)) == 0 or die;
+ }
+ # FIXME: We assume that if $simulatedDeviceUDID is not booted then iOS Simulator is not open. However
+ # $simulatedDeviceUDID may have been booted using the simctl command line tool. If $simulatedDeviceUDID
+ # was booted using simctl then we should shutdown the device and launch iOS Simulator to boot it again.
+ if (!isSimulatorDeviceBooted($simulatedDeviceUDID)) {
+ print "Launching iOS Simulator...\n";
+ relaunchIOSSimulator($simulatedDevice);
+ }
+ } else {
+ # FIXME: We should killall(1) any running instances of $appBundle before installing it to ensure
+ # that simctl launch opens the latest installed version of the app. For now we quit and
+ # launch the iOS Simulator again to ensure there are no running instances of $appBundle.
+ print "Quitting and launching iOS Simulator...\n";
+ relaunchIOSSimulator($simulatedDevice);
+
+ print "Installing $appBundle.\n";
+ # Install custom built app, overwriting an app with the same app identifier if one exists.
+ exitStatus(system("xcrun", "--sdk", "iphonesimulator", "simctl", "install", $simulatedDeviceUDID, $appBundle)) == 0 or die;
+
+ }
+
+ $simulatorOptions = {} unless $simulatorOptions;
+
+ my %simulatorENV;
+ %simulatorENV = %{$simulatorOptions->{applicationEnvironment}} if $simulatorOptions->{applicationEnvironment};
+ {
+ local %ENV; # Shadow global-scope %ENV so that changes to it will not be seen outside of this scope.
+ setupIOSWebKitEnvironment($productDir);
+ %simulatorENV = %ENV;
+ }
+ my $applicationArguments = \@ARGV;
+ $applicationArguments = $simulatorOptions->{applicationArguments} if $simulatorOptions && $simulatorOptions->{applicationArguments};
+
+ # Prefix the environment variables with SIMCTL_CHILD_ per `xcrun simctl help launch`.
+ foreach my $key (keys %simulatorENV) {
+ $ENV{"SIMCTL_CHILD_$key"} = $simulatorENV{$key};
+ }
+
+ print "Starting $appDisplayName with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n";
+ return exitStatus(system("xcrun", "--sdk", "iphonesimulator", "simctl", "launch", $simulatedDeviceUDID, $appIdentifier, @$applicationArguments));
+}
+
+sub runIOSWebKitApp($)
+{
+ my ($appBundle) = @_;
+ if (willUseIOSDeviceSDK()) {
+ die "Only running Safari in iOS Simulator is supported now.";
+ }
+ if (willUseIOSSimulatorSDK()) {
+ return runIOSWebKitAppInSimulator($appBundle);
+ }
+ die "Not using an iOS SDK."
+}
+
+sub archCommandLineArgumentsForRestrictedEnvironmentVariables()
+{
+ my @arguments = ();
+ foreach my $key (keys(%ENV)) {
+ if ($key =~ /^DYLD_/) {
+ push @arguments, "-e", "$key=$ENV{$key}";
+ }
+ }
+ return @arguments;
+}
+
+sub runMacWebKitApp($;$)
+{
+ my ($appPath, $useOpenCommand) = @_;
+ my $productDir = productDir();
+ print "Starting @{[basename($appPath)]} with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n";
+
+ local %ENV = %ENV;
+ setupMacWebKitEnvironment($productDir);
+
+ if (defined($useOpenCommand) && $useOpenCommand == USE_OPEN_COMMAND) {
+ return system("open", "-W", "-a", $appPath, "--args", argumentsForRunAndDebugMacWebKitApp());
+ }
+ if (architecture()) {
+ return system "arch", "-" . architecture(), archCommandLineArgumentsForRestrictedEnvironmentVariables(), $appPath, argumentsForRunAndDebugMacWebKitApp();
+ }
+ return system { $appPath } $appPath, argumentsForRunAndDebugMacWebKitApp();
+}
+
+sub execMacWebKitAppForDebugging($)
+{
+ my ($appPath) = @_;
+ my $architectureSwitch = "--arch";
+ my $argumentsSeparator = "--";
+
+ my $debuggerPath = `xcrun -find lldb`;
+ chomp $debuggerPath;
+ die "Can't find the lldb executable.\n" unless -x $debuggerPath;
+
+ my $productDir = productDir();
+ setupMacWebKitEnvironment($productDir);
+
+ my @architectureFlags = ($architectureSwitch, architecture());
+ print "Starting @{[basename($appPath)]} under lldb with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n";
+ exec { $debuggerPath } $debuggerPath, @architectureFlags, $argumentsSeparator, $appPath, argumentsForRunAndDebugMacWebKitApp() or die;
+}
+
+sub debugSafari
+{
+ if (isAppleCocoaWebKit()) {
+ checkFrameworks();
+ execMacWebKitAppForDebugging(safariPath());
+ }
+
+ return 1; # Unsupported platform; can't debug Safari on this platform.
+}
+
+sub runSafari
+{
+ if (isIOSWebKit()) {
+ return runIOSWebKitApp(mobileSafariBundle());
+ }
+
+ if (isAppleCocoaWebKit()) {
+ return runMacWebKitApp(safariPath());
+ }
+
+ if (isAppleWinWebKit()) {
+ my $result;
+ my $webKitLauncherPath = File::Spec->catfile(executableProductDir(), "MiniBrowser.exe");
+ return system { $webKitLauncherPath } $webKitLauncherPath, @ARGV;
+ }
+
+ return 1; # Unsupported platform; can't run Safari on this platform.
+}
+
+sub runMiniBrowser
+{
+ if (isAppleCocoaWebKit()) {
+ return runMacWebKitApp(File::Spec->catfile(productDir(), "MiniBrowser.app", "Contents", "MacOS", "MiniBrowser"));
+ } elsif (isAppleWinWebKit()) {
+ my $result;
+ my $webKitLauncherPath = File::Spec->catfile(executableProductDir(), "MiniBrowser.exe");
+ return system { $webKitLauncherPath } $webKitLauncherPath, @ARGV;
+ }
+
+ return 1;
+}
+
+sub debugMiniBrowser
+{
+ if (isAppleCocoaWebKit()) {
+ execMacWebKitAppForDebugging(File::Spec->catfile(productDir(), "MiniBrowser.app", "Contents", "MacOS", "MiniBrowser"));
+ }
+
+ return 1;
+}
+
+sub runWebKitTestRunner
+{
+ if (isAppleCocoaWebKit()) {
+ return runMacWebKitApp(File::Spec->catfile(productDir(), "WebKitTestRunner"));
+ }
+
+ return 1;
+}
+
+sub debugWebKitTestRunner
+{
+ if (isAppleCocoaWebKit()) {
+ execMacWebKitAppForDebugging(File::Spec->catfile(productDir(), "WebKitTestRunner"));
+ }
+
+ return 1;
+}
+
+sub readRegistryString
+{
+ my ($valueName) = @_;
+ chomp(my $string = `regtool --wow32 get "$valueName"`);
+ return $string;
+}
+
+sub writeRegistryString
+{
+ my ($valueName, $string) = @_;
+
+ my $error = system "regtool", "--wow32", "set", "-s", $valueName, $string;
+
+ # On Windows Vista/7 with UAC enabled, regtool will fail to modify the registry, but will still
+ # return a successful exit code. So we double-check here that the value we tried to write to the
+ # registry was really written.
+ return !$error && readRegistryString($valueName) eq $string;
+}
+
+sub formatBuildTime($)
+{
+ my ($buildTime) = @_;
+
+ my $buildHours = int($buildTime / 3600);
+ my $buildMins = int(($buildTime - $buildHours * 3600) / 60);
+ my $buildSecs = $buildTime - $buildHours * 3600 - $buildMins * 60;
+
+ if ($buildHours) {
+ return sprintf("%dh:%02dm:%02ds", $buildHours, $buildMins, $buildSecs);
+ }
+ return sprintf("%02dm:%02ds", $buildMins, $buildSecs);
+}
+
+sub runSvnUpdateAndResolveChangeLogs(@)
+{
+ my @svnOptions = @_;
+ my $openCommand = "svn update " . join(" ", @svnOptions);
+ open my $update, "$openCommand |" or die "cannot execute command $openCommand";
+ my @conflictedChangeLogs;
+ while (my $line = <$update>) {
+ print $line;
+ $line =~ m/^C\s+(.+?)[\r\n]*$/;
+ if ($1) {
+ my $filename = normalizePath($1);
+ push @conflictedChangeLogs, $filename if basename($filename) eq "ChangeLog";
+ }
+ }
+ close $update or die;
+
+ if (@conflictedChangeLogs) {
+ print "Attempting to merge conflicted ChangeLogs.\n";
+ my $resolveChangeLogsPath = File::Spec->catfile(sourceDir(), "Tools", "Scripts", "resolve-ChangeLogs");
+ (system($resolveChangeLogsPath, "--no-warnings", @conflictedChangeLogs) == 0)
+ or die "Could not open resolve-ChangeLogs script: $!.\n";
+ }
+}
+
+sub runGitUpdate()
+{
+ # Doing a git fetch first allows setups with svn-remote.svn.fetch = trunk:refs/remotes/origin/master
+ # to perform the rebase much much faster.
+ system("git", "fetch");
+ if (isGitSVNDirectory(".")) {
+ system("git", "svn", "rebase") == 0 or die;
+ } else {
+ # This will die if branch.$BRANCHNAME.merge isn't set, which is
+ # almost certainly what we want.
+ system("git", "pull") == 0 or die;
+ }
+}
+
+1;
diff --git a/Tools/TestWebKitAPI/CMakeLists.txt b/Tools/TestWebKitAPI/CMakeLists.txt
new file mode 100644
index 000000000..de2699e37
--- /dev/null
+++ b/Tools/TestWebKitAPI/CMakeLists.txt
@@ -0,0 +1,232 @@
+set(TESTWEBKITAPI_DIR "${TOOLS_DIR}/TestWebKitAPI")
+set(test_wtf_LIBRARIES
+ WTF${DEBUG_SUFFIX}
+ gtest
+)
+
+set(test_webcore_LIBRARIES
+ WTF${DEBUG_SUFFIX}
+ WebCore${DEBUG_SUFFIX}
+ gtest
+)
+
+set(TestWebKitAPI_LIBRARIES
+ WTF${DEBUG_SUFFIX}
+)
+
+if (ENABLE_WEBKIT2)
+ set(test_webkit2_api_LIBRARIES
+ JavaScriptCore
+ TestWebKitAPIBase
+ WTF
+ WebKit2
+ gtest
+ )
+ list(APPEND TestWebKitAPI_LIBRARIES
+ WebKit2
+ )
+else ()
+ list(APPEND TestWebKitAPI_LIBRARIES
+ WebKit${DEBUG_SUFFIX}
+ )
+endif ()
+
+
+set(TestJavaScriptCore_LIBRARIES
+ JavaScriptCore
+ gtest
+)
+
+set(TestWTF_SOURCES
+ ${TESTWEBKITAPI_DIR}/Counters.cpp
+ ${TESTWEBKITAPI_DIR}/TestsController.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/AtomicString.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/BloomFilter.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/Consume.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/CrossThreadTask.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/CString.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/CheckedArithmeticOperations.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/Condition.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/DateMath.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/Deque.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/EnumTraits.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/Expected.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/HashCountedSet.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/HashMap.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/HashSet.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/IntegerToStringConversion.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/ListHashSet.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/Lock.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/MD5.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/MathExtras.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/MediaTime.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/MetaAllocator.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/NakedPtr.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/Optional.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/OptionSet.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/ParkingLot.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/RedBlackTree.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/Ref.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/RefCounter.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/RefLogger.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/RefPtr.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/SHA1.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/SaturatedArithmeticOperations.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/Scope.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/ScopedLambda.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/SetForScope.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/StringBuilder.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/StringHasher.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/StringImpl.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/StringOperators.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/StringView.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/TextBreakIterator.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/Time.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/UniqueRef.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/Variant.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/Vector.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/WTFString.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/WeakPtr.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/WorkQueue.cpp
+)
+
+# FIXME: Tests/WTF/RunLoop.cpp is missing because it doesn't work for Windows.
+# FIXME: Platform-specific sources in Tests/WTF are not included in TestWTF_SOURCES.
+
+WEBKIT_INCLUDE_CONFIG_FILES_IF_EXISTS()
+
+include_directories(
+ ${TESTWEBKITAPI_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/Source
+ ${JAVASCRIPTCORE_DIR}
+ ${THIRDPARTY_DIR}/gtest/include
+ ${WEBKIT2_DIR}/Platform/IPC
+ ${WEBKIT2_DIR}/Shared
+ ${WEBKIT2_DIR}/Shared/API
+ ${WEBKIT2_DIR}/Shared/API/c
+ ${WEBKIT2_DIR}/Shared/Plugins
+ ${WEBKIT2_DIR}/UIProcess
+ ${WEBKIT2_DIR}/UIProcess/API
+ ${WEBKIT2_DIR}/WebProcess/InjectedBundle
+ ${WEBKIT2_DIR}/WebProcess/InjectedBundle/API/c
+)
+
+if (ENABLE_WEBKIT2)
+ add_library(TestWebKitAPIInjectedBundle SHARED
+ ${bundle_harness_SOURCES}
+ ${TESTWEBKITAPI_DIR}/InjectedBundleController.cpp
+ ${TESTWEBKITAPI_DIR}/InjectedBundleMain.cpp
+ ${TESTWEBKITAPI_DIR}/PlatformUtilities.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/CanHandleRequest_Bundle.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/DidAssociateFormControls_Bundle.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/DOMWindowExtensionBasic_Bundle.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/DOMWindowExtensionNoCache_Bundle.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/DocumentStartUserScriptAlertCrash_Bundle.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/GetInjectedBundleInitializationUserDataCallback_Bundle.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/HitTestResultNodeHandle_Bundle.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/InjectedBundleBasic_Bundle.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/InjectedBundleFrameHitTest_Bundle.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/InjectedBundleInitializationUserDataCallbackWins_Bundle.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/LoadCanceledNoServerRedirectCallback_Bundle.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/MouseMoveAfterCrash_Bundle.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFails_Bundle.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutForImages_Bundle.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFrames_Bundle.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/NewFirstVisuallyNonEmptyLayout_Bundle.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/ParentFrame_Bundle.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/ProvisionalURLAfterWillSendRequestCallback_Bundle.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/ResponsivenessTimerDoesntFireEarly_Bundle.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/ShouldGoToBackForwardListItem_Bundle.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/TextFieldDidBeginAndEndEditing_Bundle.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/UserMessage_Bundle.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/WillLoad_Bundle.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/WillSendSubmitEvent_Bundle.cpp
+ )
+
+ target_link_libraries(TestWebKitAPIInjectedBundle ${TestWebKitAPI_LIBRARIES})
+ add_dependencies(TestWebKitAPIInjectedBundle WTF ${ForwardingHeadersForTestWebKitAPI_NAME})
+
+ get_property(TestWebKitAPIInjectedBundle_PATH TARGET TestWebKitAPIInjectedBundle PROPERTY LOCATION)
+endif ()
+
+if (WIN32)
+ add_definitions(-DGTEST_LINKED_AS_SHARED_LIBRARY=0)
+else ()
+ add_definitions(-DGTEST_LINKED_AS_SHARED_LIBRARY=1)
+endif ()
+
+add_definitions(-DGTEST_HAS_RTTI=0
+ -DTEST_WEBKIT2_RESOURCES_DIR=\"${TESTWEBKITAPI_DIR}/Tests/WebKit2\"
+ -DTEST_INJECTED_BUNDLE_PATH=\"${TestWebKitAPIInjectedBundle_PATH}\"
+)
+
+# FIXME: This works around compatibility problems in the old version of the third-pary
+# googletest source code checkout. It should be removed once we upgrade to a newer version.
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+ add_definitions(-DGTEST_HAS_TR1_TUPLE=0)
+endif ()
+
+add_executable(TestWTF
+ ${test_main_SOURCES}
+ ${TestWTF_SOURCES}
+)
+
+if (WIN32)
+ add_dependencies(TestWTF TestWTFLib)
+endif ()
+
+target_link_libraries(TestWTF ${test_wtf_LIBRARIES})
+add_dependencies(TestWTF WTF ${ForwardingHeadersForTestWebKitAPI_NAME} ${ForwardingNetworkHeadersForTestWebKitAPI_NAME})
+add_test(TestWTF ${TESTWEBKITAPI_RUNTIME_OUTPUT_DIRECTORY_WTF}/TestWTF)
+set_tests_properties(TestWTF PROPERTIES TIMEOUT 60)
+set_target_properties(TestWTF PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY ${TESTWEBKITAPI_RUNTIME_OUTPUT_DIRECTORY_WTF}
+)
+
+# FIXME: EFL is the only port that separates the WebCore binaries. Each port ought to do closer to the same thing.
+foreach (testName ${test_webcore_BINARIES})
+ add_executable(${testName} ${test_main_SOURCES} ${TESTWEBKITAPI_DIR}/TestsController.cpp ${TESTWEBKITAPI_DIR}/Tests/WebCore/${testName}.cpp)
+ add_test(${testName} ${TESTWEBKITAPI_RUNTIME_OUTPUT_DIRECTORY}/WebCore/${testName})
+ set_tests_properties(${testName} PROPERTIES TIMEOUT 60)
+ target_link_libraries(${testName} ${test_webcore_LIBRARIES})
+ set_target_properties(${testName} PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY ${TESTWEBKITAPI_RUNTIME_OUTPUT_DIRECTORY}/WebCore
+ )
+endforeach ()
+
+if (ENABLE_WEBKIT2)
+ add_library(TestWebKitAPIBase
+ ${test_main_SOURCES}
+ ${webkit2_api_harness_SOURCES}
+ ${TESTWEBKITAPI_DIR}/JavaScriptTest.cpp
+ ${TESTWEBKITAPI_DIR}/PlatformUtilities.cpp
+ ${TESTWEBKITAPI_DIR}/TestsController.cpp
+ )
+
+ target_link_libraries(TestWebKitAPIBase JavaScriptCore WTF WebKit2 gtest)
+
+ add_dependencies(TestWebKitAPIBase WebKit2 ${ForwardingHeadersForTestWebKitAPI_NAME} ${ForwardingNetworkHeadersForTestWebKitAPI_NAME})
+
+ foreach (testName ${test_webkit2_api_BINARIES})
+ get_filename_component(testBaseName ${testName} NAME)
+ add_executable(${testBaseName} ${TESTWEBKITAPI_DIR}/Tests/WebKit2/${testName}.cpp)
+ add_test(${testBaseName} ${TESTWEBKITAPI_RUNTIME_OUTPUT_DIRECTORY}/WebKit2/${testBaseName})
+ set_tests_properties(${testBaseName} PROPERTIES TIMEOUT 60)
+ target_link_libraries(${testBaseName} ${test_webkit2_api_LIBRARIES})
+ set_target_properties(${testBaseName} PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY ${TESTWEBKITAPI_RUNTIME_OUTPUT_DIRECTORY}/WebKit2
+ )
+ endforeach ()
+
+ # We don't run tests that are expected to fail. We could use the WILL_FAIL
+ # property, but it reports failure when the test crashes or timeouts and would
+ # make the bot red.
+ foreach (testName ${test_webkit2_api_fail_BINARIES})
+ add_executable(${testName} ${TESTWEBKITAPI_DIR}/Tests/WebKit2/${testName}.cpp)
+ target_link_libraries(${testName} ${test_webkit2_api_LIBRARIES})
+ set_target_properties(${testName} PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY ${TESTWEBKITAPI_RUNTIME_OUTPUT_DIRECTORY}/WebKit2/failure
+ )
+ endforeach ()
+endif ()
diff --git a/Tools/TestWebKitAPI/Counters.cpp b/Tools/TestWebKitAPI/Counters.cpp
new file mode 100644
index 000000000..536a434bf
--- /dev/null
+++ b/Tools/TestWebKitAPI/Counters.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2014, 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Counters.h"
+
+unsigned CopyMoveCounter::constructionCount = 0;
+unsigned CopyMoveCounter::copyCount = 0;
+unsigned CopyMoveCounter::moveCount = 0;
+
+unsigned ConstructorDestructorCounter::constructionCount = 0;
+unsigned ConstructorDestructorCounter::destructionCount = 0;
+
+template<> unsigned DeleterCounter<ConstructorDestructorCounter>::m_deleterCount = 0;
diff --git a/Tools/TestWebKitAPI/Counters.h b/Tools/TestWebKitAPI/Counters.h
new file mode 100644
index 000000000..f9ea22402
--- /dev/null
+++ b/Tools/TestWebKitAPI/Counters.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ * Copyright (C) 2014, 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Counters_h
+#define Counters_h
+
+struct CopyMoveCounter {
+ static unsigned constructionCount;
+ static unsigned copyCount;
+ static unsigned moveCount;
+
+ struct TestingScope {
+ TestingScope()
+ {
+ constructionCount = 0;
+ copyCount = 0;
+ moveCount = 0;
+ }
+ };
+
+ CopyMoveCounter() { constructionCount++; }
+ CopyMoveCounter(const CopyMoveCounter&) { copyCount++; }
+ CopyMoveCounter& operator=(const CopyMoveCounter&) { copyCount++; return *this; }
+ CopyMoveCounter(CopyMoveCounter&&) { moveCount++; }
+ CopyMoveCounter& operator=(CopyMoveCounter&&) { moveCount++; return *this; }
+};
+
+
+struct ConstructorDestructorCounter {
+ static unsigned constructionCount;
+ static unsigned destructionCount;
+
+ struct TestingScope {
+ TestingScope()
+ {
+ constructionCount = 0;
+ destructionCount = 0;
+ }
+ };
+
+ ConstructorDestructorCounter() { constructionCount++; }
+ ~ConstructorDestructorCounter() { destructionCount++; }
+};
+
+#if COMPILER(CLANG)
+#if __has_warning("-Wundefined-var-template")
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wundefined-var-template"
+#endif
+#endif
+template<typename T>
+struct DeleterCounter {
+ static unsigned m_deleterCount;
+
+ static unsigned deleterCount() { return m_deleterCount; }
+
+ struct TestingScope {
+ TestingScope()
+ {
+ m_deleterCount = 0;
+ }
+ };
+
+ void operator()(T* p) const
+ {
+ m_deleterCount++;
+ delete p;
+ }
+};
+#if COMPILER(CLANG)
+#if __has_warning("-Wundefined-var-template")
+#pragma clang diagnostic pop
+#endif
+#endif
+
+#endif // Counters_h
diff --git a/Tools/TestWebKitAPI/ForwardingHeaders/WebCore/LayoutUnit.h b/Tools/TestWebKitAPI/ForwardingHeaders/WebCore/LayoutUnit.h
new file mode 100644
index 000000000..de0a7454e
--- /dev/null
+++ b/Tools/TestWebKitAPI/ForwardingHeaders/WebCore/LayoutUnit.h
@@ -0,0 +1,4 @@
+#ifndef TestWebKitAPI_FWD_LayoutUnit_h
+#define TestWebKitAPI_FWD_LayoutUnit_h
+#include <LayoutUnit.h>
+#endif
diff --git a/Tools/TestWebKitAPI/GNUmakefile.am b/Tools/TestWebKitAPI/GNUmakefile.am
deleted file mode 100644
index 2ea61734d..000000000
--- a/Tools/TestWebKitAPI/GNUmakefile.am
+++ /dev/null
@@ -1,934 +0,0 @@
-noinst_LTLIBRARIES += \
- Libraries/libTestWebKitAPIMain.la
-
-if ENABLE_WEBKIT2
-noinst_LTLIBRARIES += \
- Libraries/libTestWebKit2GtkAPI.la
-endif
-
-Libraries_libTestWebKitAPIMain_la_SOURCES = \
- Tools/TestWebKitAPI/Test.h \
- Tools/TestWebKitAPI/TestsController.cpp \
- Tools/TestWebKitAPI/TestsController.h \
- Tools/TestWebKitAPI/gtk/main.cpp
-
-# Use -isystem gcc flag so that gcc considers gtest headers as system headers.
-# We need this to avoid a lot of compile warnings due to -Wundef.
-# See http://code.google.com/p/googletest/issues/detail?id=258
-Libraries_libTestWebKitAPIMain_la_CPPFLAGS = \
- -isystem $(srcdir)/Source/ThirdParty/gtest/include \
- -I$(srcdir)/Tools/TestWebKitAPI \
- -I$(srcdir)/Source/ThirdParty/gtest/include \
- -I$(top_builddir)/DerivedSources/WebCore/include \
- -I$(top_builddir)/DerivedSources/WebKit2/include \
- $(global_cppflags) \
- $(javascriptcore_cppflags) \
- $(GTK_CFLAGS)
-
-webkitgtk_tests_cflags = \
- -fno-strict-aliasing \
- -DTEST_PLUGIN_DIR=\"${shell pwd}/${top_builddir}/TestNetscapePlugin/.libs\" \
- -I$(srcdir)/Source/JavaScriptCore/ForwardingHeaders \
- -I$(WebKit) \
- -I$(GENSOURCES) \
- -I$(top_builddir)/Source/WebKit/gtk \
- -I$(top_srcdir)/Source/WebCore/bindings \
- -I$(top_srcdir)/Source/WebCore/bindings/gobject \
- $(global_cppflags) \
- $(global_cflags) \
- $(javascriptcore_cppflags) \
- $(FREETYPE_CFLAGS) \
- $(GLIB_CFLAGS) \
- $(GTK_CFLAGS) \
- $(LIBSOUP_CFLAGS) \
- $(XRENDER_CFLAGS) \
- $(XT_CFLAGS)
-
-webkitgtk_tests_ldadd = \
- libjavascriptcoregtk-@WEBKITGTK_API_MAJOR_VERSION@.@WEBKITGTK_API_MINOR_VERSION@.la \
- libwebkitgtk-@WEBKITGTK_API_MAJOR_VERSION@.@WEBKITGTK_API_MINOR_VERSION@.la \
- $(FREETYPE_LIBS) \
- $(GTK_LIBS) \
- $(GLIB_LIBS) \
- $(LIBSOUP_LIBS) \
- $(XRENDER_LIBS)
-
-webkitgtk_tests_ldflags = \
- -no-install
-
-
-webkit2gtk_tests_cppflags = \
- -DWEBKIT_EXEC_PATH=\"${shell pwd}/$(top_builddir)/Programs\" \
- -DWEBKIT_SRC_DIR=\"${shell pwd}/${srcdir}\" \
- -DWEBKIT_DERIVED_SRC_DIR=\"${shell pwd}/${top_builddir}/DerivedSources\" \
- -DWEBKIT_TEST_PLUGIN_DIR=\"${shell pwd}/${top_builddir}/TestNetscapePlugin/.libs\" \
- -DWEBKIT_TEST_WEB_EXTENSIONS_DIR=\"${shell pwd}/${top_builddir}/Libraries/WebExtensions/.libs\" \
- -DWEBKIT_INJECTED_BUNDLE_PATH=\"${shell pwd}/$(top_builddir)/.libs\" \
- $(javascriptcore_cppflags) \
- -I$(srcdir)/Source \
- -I$(srcdir)/Source/WebKit2 \
- -I$(srcdir)/Source/JavaScriptCore \
- -I$(srcdir)/Tools/TestWebKitAPI/gtk/WebKit2Gtk \
- -I$(top_builddir)/DerivedSources/WebKit2/include \
- -I$(top_builddir)/DerivedSources/WebKit2/webkit2gtk \
- -I$(top_builddir)/DerivedSources/WebKit2/webkit2gtk/include \
- -I$(srcdir)/Source/WebKit2/UIProcess/API/gtk \
- $(global_cppflags) \
- $(FREETYPE_CFLAGS) \
- $(GLIB_CFLAGS) \
- $(GTK_CFLAGS) \
- $(LIBSOUP_CFLAGS)
-
-webkit2gtk_tests_ldadd = \
- Libraries/libTestWebKit2GtkAPI.la \
- libjavascriptcoregtk-@WEBKITGTK_API_MAJOR_VERSION@.@WEBKITGTK_API_MINOR_VERSION@.la \
- libwebkit2gtk-@WEBKITGTK_API_MAJOR_VERSION@.@WEBKITGTK_API_MINOR_VERSION@.la \
- $(FREETYPE_LIBS) \
- $(GEOCLUE_LIBS) \
- $(GLIB_LIBS) \
- $(GTK_LIBS) \
- $(LIBSOUP_LIBS)
-
-webkit2gtk_tests_ldflags = \
- -no-install
-
-Libraries_libTestWebKit2GtkAPI_la_SOURCES = \
- Tools/TestWebKitAPI/gtk/WebKit2Gtk/LoadTrackingTest.cpp \
- Tools/TestWebKitAPI/gtk/WebKit2Gtk/LoadTrackingTest.h \
- Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestBus.cpp \
- Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestBus.h \
- Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestServer.cpp \
- Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestServer.h \
- Tools/TestWebKitAPI/gtk/WebKit2Gtk/TestMain.cpp \
- Tools/TestWebKitAPI/gtk/WebKit2Gtk/TestMain.h \
- Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebViewTest.cpp \
- Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebViewTest.h
-
-Libraries_libTestWebKit2GtkAPI_la_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-
-
-noinst_PROGRAMS += \
- Programs/TestWebKitAPI/WTF/TestWTF \
- Programs/TestWebKitAPI/JavaScriptCore/TestJavaScriptCore \
- Programs/TestWebKitAPI/WebCore/TestWebCore
-
-if ENABLE_WEBKIT1
-noinst_PROGRAMS += \
- Programs/TestWebKitAPI/WebKitGtk/testapplicationcache \
- Programs/TestWebKitAPI/WebKitGtk/testcontextmenu \
- Programs/TestWebKitAPI/WebKitGtk/testdomdocument \
- Programs/TestWebKitAPI/WebKitGtk/testdomdomwindow \
- Programs/TestWebKitAPI/WebKitGtk/testdomnode \
- Programs/TestWebKitAPI/WebKitGtk/testhttpbackend \
- Programs/TestWebKitAPI/WebKitGtk/testfavicondatabase \
- Programs/TestWebKitAPI/WebKitGtk/testloading \
- Programs/TestWebKitAPI/WebKitGtk/testglobals \
- Programs/TestWebKitAPI/WebKitGtk/testmimehandling \
- Programs/TestWebKitAPI/WebKitGtk/testnetworkrequest \
- Programs/TestWebKitAPI/WebKitGtk/testnetworkresponse \
- Programs/TestWebKitAPI/WebKitGtk/testwebframe \
- Programs/TestWebKitAPI/WebKitGtk/testwebbackforwardlist \
- Programs/TestWebKitAPI/WebKitGtk/testwebhistoryitem \
- Programs/TestWebKitAPI/WebKitGtk/testwindow \
- Programs/TestWebKitAPI/WebKitGtk/testdownload \
- Programs/TestWebKitAPI/WebKitGtk/testatk \
- Programs/TestWebKitAPI/WebKitGtk/testatkroles \
- Programs/TestWebKitAPI/WebKitGtk/testhittestresult \
- Programs/TestWebKitAPI/WebKitGtk/testwebinspector \
- Programs/TestWebKitAPI/WebKitGtk/testwebsettings \
- Programs/TestWebKitAPI/WebKitGtk/testwebresource \
- Programs/TestWebKitAPI/WebKitGtk/testwebdatasource \
- Programs/TestWebKitAPI/WebKitGtk/testwebplugindatabase \
- Programs/TestWebKitAPI/WebKitGtk/testwebview \
- Programs/TestWebKitAPI/WebKitGtk/testkeyevents \
- Programs/TestWebKitAPI/WebKitGtk/testcopyandpaste
-endif
-
-if ENABLE_WEBKIT2
-noinst_PROGRAMS += \
- Programs/TestWebKitAPI/WebKit2/TestWebKit2 \
- Programs/TestWebKitAPI/WebKit2Gtk/InspectorTestServer \
- Programs/TestWebKitAPI/WebKit2Gtk/TestAuthentication \
- Programs/TestWebKitAPI/WebKit2Gtk/TestBackForwardList \
- Programs/TestWebKitAPI/WebKit2Gtk/TestContextMenu \
- Programs/TestWebKitAPI/WebKit2Gtk/TestCookieManager \
- Programs/TestWebKitAPI/WebKit2Gtk/TestDOMNode \
- Programs/TestWebKitAPI/WebKit2Gtk/TestDownloads \
- Programs/TestWebKitAPI/WebKit2Gtk/TestFrame \
- Programs/TestWebKitAPI/WebKit2Gtk/TestInspector \
- Programs/TestWebKitAPI/WebKit2Gtk/TestInspectorServer \
- Programs/TestWebKitAPI/WebKit2Gtk/TestLoaderClient \
- Programs/TestWebKitAPI/WebKit2Gtk/TestMultiprocess \
- Programs/TestWebKitAPI/WebKit2Gtk/TestPrinting \
- Programs/TestWebKitAPI/WebKit2Gtk/TestResources \
- Programs/TestWebKitAPI/WebKit2Gtk/TestSSL \
- Programs/TestWebKitAPI/WebKit2Gtk/TestUIClient \
- Programs/TestWebKitAPI/WebKit2Gtk/TestWebExtensions \
- Programs/TestWebKitAPI/WebKit2Gtk/TestWebKitVersion \
- Programs/TestWebKitAPI/WebKit2Gtk/TestWebKitFaviconDatabase \
- Programs/TestWebKitAPI/WebKit2Gtk/TestWebKitFindController \
- Programs/TestWebKitAPI/WebKit2Gtk/TestWebKitPolicyClient \
- Programs/TestWebKitAPI/WebKit2Gtk/TestWebKitSettings \
- Programs/TestWebKitAPI/WebKit2Gtk/TestWebKitWebContext \
- Programs/TestWebKitAPI/WebKit2Gtk/TestWebKitWebView \
- Programs/TestWebKitAPI/WebKit2Gtk/TestWebKitWebViewGroup \
- Programs/TestWebKitAPI/WebKit2Gtk/TestWebViewEditor
-
-if HAVE_ATSPI2
-noinst_PROGRAMS += \
- Programs/TestWebKitAPI/WebKit2Gtk/AccessibilityTestServer \
- Programs/TestWebKitAPI/WebKit2Gtk/TestWebKitAccessibility
-endif
-endif # ENABLE_WEBKIT2
-
-Programs_TestWebKitAPI_WTF_TestWTF_CPPFLAGS = \
- $(Libraries_libTestWebKitAPIMain_la_CPPFLAGS) \
- $(GLIB_LIBS) \
- $(CAIRO_CFLAGS)
-
-Programs_TestWebKitAPI_WTF_TestWTF_CXXFLAGS = \
- -DGTEST_HAS_RTTI=0 \
- $(global_cxxflags)
-
-Programs_TestWebKitAPI_WTF_TestWTF_LDADD = \
- Libraries/libTestWebKitAPIMain.la \
- Libraries/libgtest.la \
- libWTF.la \
- $(GTK_LIBS) \
- $(GLIB_LIBS)
-
-Programs_TestWebKitAPI_WTF_TestWTF_LDFLAGS = \
- -no-install
-
-Programs_TestWebKitAPI_WTF_TestWTF_SOURCES = \
- Tools/TestWebKitAPI/Tests/WTF/AtomicString.cpp \
- Tools/TestWebKitAPI/Tests/WTF/CString.cpp \
- Tools/TestWebKitAPI/Tests/WTF/CheckedArithmeticOperations.cpp \
- Tools/TestWebKitAPI/Tests/WTF/Functional.cpp \
- Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp \
- Tools/TestWebKitAPI/Tests/WTF/HashSet.cpp \
- Tools/TestWebKitAPI/Tests/WTF/IntegerToStringConversion.cpp \
- Tools/TestWebKitAPI/Tests/WTF/ListHashSet.cpp \
- Tools/TestWebKitAPI/Tests/WTF/MD5.cpp \
- Tools/TestWebKitAPI/Tests/WTF/MathExtras.cpp \
- Tools/TestWebKitAPI/Tests/WTF/MediaTime.cpp \
- Tools/TestWebKitAPI/Tests/WTF/MetaAllocator.cpp \
- Tools/TestWebKitAPI/Tests/WTF/MoveOnly.h \
- Tools/TestWebKitAPI/Tests/WTF/RedBlackTree.cpp \
- Tools/TestWebKitAPI/Tests/WTF/Ref.cpp \
- Tools/TestWebKitAPI/Tests/WTF/RefLogger.h \
- Tools/TestWebKitAPI/Tests/WTF/RefPtr.cpp \
- Tools/TestWebKitAPI/Tests/WTF/SHA1.cpp \
- Tools/TestWebKitAPI/Tests/WTF/SaturatedArithmeticOperations.cpp \
- Tools/TestWebKitAPI/Tests/WTF/StringBuilder.cpp \
- Tools/TestWebKitAPI/Tests/WTF/StringHasher.cpp \
- Tools/TestWebKitAPI/Tests/WTF/StringImpl.cpp \
- Tools/TestWebKitAPI/Tests/WTF/StringOperators.cpp \
- Tools/TestWebKitAPI/Tests/WTF/TemporaryChange.cpp \
- Tools/TestWebKitAPI/Tests/WTF/Vector.cpp \
- Tools/TestWebKitAPI/Tests/WTF/gobject/GUniquePtr.cpp \
- Tools/TestWebKitAPI/WTFStringUtilities.h
-
-Programs_TestWebKitAPI_JavaScriptCore_TestJavaScriptCore_CPPFLAGS = \
- $(Libraries_libTestWebKitAPIMain_la_CPPFLAGS)
-
-Programs_TestWebKitAPI_JavaScriptCore_TestJavaScriptCore_CXXFLAGS = \
- -DGTEST_HAS_RTTI=0 \
- $(global_cxxflags)
-
-Programs_TestWebKitAPI_JavaScriptCore_TestJavaScriptCore_LDADD = \
- Libraries/libTestWebKitAPIMain.la \
- Libraries/libgtest.la \
- libWTF.la \
- $(GTK_LIBS)
-
-Programs_TestWebKitAPI_JavaScriptCore_TestJavaScriptCore_LDFLAGS = \
- -no-install
-
-Programs_TestWebKitAPI_JavaScriptCore_TestJavaScriptCore_SOURCES = \
- Tools/TestWebKitAPI/Tests/JavaScriptCore/VMInspector.cpp
-
-webcore_layer_deps = \
- libPlatform.la \
- libPlatformGtk.la \
- libWebCorePlatform.la \
- libWebCoreGtk.la \
- libWebCore.la \
- libWebCoreModules.la
-if ENABLE_SVG
-webcore_layer_deps += \
- libWebCoreSVG.la
-endif
-if ENABLE_INDEXED_DATABASE
-webcore_layer_deps += \
- libLevelDB.la
-endif
-if USE_OPENGL
-webcore_layer_deps += \
- libANGLE.la
-endif
-
-webcore_layer_archives = $(foreach lib, $(webcore_layer_deps), $(shell echo $(lib) | sed "s/\(.*\)\.la/.libs\/\1.a/"))
-
-libWebCoreLayer.a: $(webcore_layer_deps)
- $(AM_V_GEN)
- $(AM_V_at)$(shell rm -f $@)
- $(AM_V_at)$(shell find . -name "*.o" > objects_list)
- $(AM_V_at)$(foreach archive, $(webcore_layer_archives), $(shell $(AR) t $(archive) | xargs -n1 basename | xargs -I obj_file grep -F obj_file objects_list | xargs -n50 $(AR) $(AR_FLAGS) $@))
- $(AM_V_at)$(shell rm -f objects_list)
-
-DISTCLEANFILES += \
- $(top_builddir)/libWebCoreLayer.a
-
-Programs_TestWebKitAPI_WebCore_TestWebCore_CPPFLAGS = \
- $(Libraries_libTestWebKitAPIMain_la_CPPFLAGS) \
- $(platform_cppflags) \
- $(platformgtk_cppflags) \
- $(webcore_cppflags) \
- $(webcoregtk_cppflags) \
- $(LIBSOUP_CFLAGS)
-
-Programs_TestWebKitAPI_WebCore_TestWebCore_CXXFLAGS = \
- -DGTEST_HAS_RTTI=0 \
- $(global_cxxflags)
-
-Programs_TestWebKitAPI_WebCore_TestWebCore_LDADD = \
- Libraries/libTestWebKitAPIMain.la \
- Libraries/libgtest.la \
- libjavascriptcoregtk-@WEBKITGTK_API_MAJOR_VERSION@.@WEBKITGTK_API_MINOR_VERSION@.la \
- libWTF.la \
- libWebCoreLayer.a \
- $(CAIRO_LIBS) \
- $(FREETYPE_LIBS) \
- $(GAMEPAD_LIBS) \
- $(GEOCLUE_LIBS) \
- $(GLIB_LIBS) \
- $(GSTREAMER_LIBS) \
- $(GTK_LIBS) \
- $(JPEG_LIBS) \
- $(LIBSECRET_LIBS) \
- $(LIBSOUP_LIBS) \
- $(LIBXML_LIBS) \
- $(OPENGL_LIBS) \
- $(PANGO_LIBS) \
- $(PNG_LIBS) \
- $(SQLITE3_LIBS) \
- $(UNICODE_LIBS) \
- $(WEBP_LIBS) \
- $(XRENDER_LIBS) \
- $(XT_LIBS) \
- $(ZLIB_LIBS)
-
-Programs_TestWebKitAPI_WebCore_TestWebCore_LDFLAGS = \
- -no-install
-
-Programs_TestWebKitAPI_WebCore_TestWebCore_SOURCES = \
- Source/WebCore/platform/graphics/IntPoint.cpp \
- Source/WebCore/platform/graphics/IntRect.cpp \
- Source/WebCore/platform/graphics/IntSize.cpp \
- Source/WebCore/platform/graphics/cairo/IntRectCairo.cpp \
- Source/WebCore/platform/graphics/gtk/IntRectGtk.cpp \
- Source/WebCore/platform/gtk/GtkInputMethodFilter.cpp \
- Tools/TestWebKitAPI/config.h \
- Tools/TestWebKitAPI/Tests/gtk/InputMethodFilter.cpp \
- Tools/TestWebKitAPI/Tests/WebCore/gtk/UserAgentQuirks.cpp \
- Tools/TestWebKitAPI/Tests/WebCore/URL.cpp \
- Tools/TestWebKitAPI/Tests/WebCore/LayoutUnit.cpp
-
-Programs_TestWebKitAPI_WebKitGtk_testapplicationcache_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testapplicationcache.c
-Programs_TestWebKitAPI_WebKitGtk_testapplicationcache_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testapplicationcache_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testapplicationcache_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKitGtk_testcontextmenu_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testcontextmenu.c
-Programs_TestWebKitAPI_WebKitGtk_testcontextmenu_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testcontextmenu_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testcontextmenu_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKitGtk_testdomdocument_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testdomdocument.c
-Programs_TestWebKitAPI_WebKitGtk_testdomdocument_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testdomdocument_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testdomdocument_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKitGtk_testdomdomwindow_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testdomdomwindow.c
-Programs_TestWebKitAPI_WebKitGtk_testdomdomwindow_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testdomdomwindow_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testdomdomwindow_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKitGtk_testdomnode_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testdomnode.c
-Programs_TestWebKitAPI_WebKitGtk_testdomnode_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testdomnode_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testdomnode_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKitGtk_testhttpbackend_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testhttpbackend.c
-Programs_TestWebKitAPI_WebKitGtk_testhttpbackend_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testhttpbackend_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testhttpbackend_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKitGtk_testfavicondatabase_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testfavicondatabase.c \
- Tools/TestWebKitAPI/Tests/WebKitGtk/test_utils.c
-Programs_TestWebKitAPI_WebKitGtk_testfavicondatabase_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testfavicondatabase_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testfavicondatabase_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKitGtk_testglobals_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testglobals.c
-Programs_TestWebKitAPI_WebKitGtk_testglobals_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testglobals_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testglobals_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKitGtk_testloading_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testloading.c
-Programs_TestWebKitAPI_WebKitGtk_testloading_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testloading_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testloading_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKitGtk_testmimehandling_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testmimehandling.c \
- Tools/TestWebKitAPI/Tests/WebKitGtk/test_utils.c
-Programs_TestWebKitAPI_WebKitGtk_testmimehandling_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testmimehandling_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testmimehandling_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKitGtk_testnetworkrequest_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testnetworkrequest.c
-Programs_TestWebKitAPI_WebKitGtk_testnetworkrequest_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testnetworkrequest_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testnetworkrequest_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKitGtk_testnetworkresponse_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testnetworkresponse.c
-Programs_TestWebKitAPI_WebKitGtk_testnetworkresponse_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testnetworkresponse_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testnetworkresponse_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKitGtk_testwebframe_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testwebframe.c
-Programs_TestWebKitAPI_WebKitGtk_testwebframe_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testwebframe_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testwebframe_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKitGtk_testwebplugindatabase_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testwebplugindatabase.c
-Programs_TestWebKitAPI_WebKitGtk_testwebplugindatabase_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testwebplugindatabase_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testwebplugindatabase_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKitGtk_testwebbackforwardlist_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testwebbackforwardlist.c
-Programs_TestWebKitAPI_WebKitGtk_testwebbackforwardlist_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testwebbackforwardlist_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testwebbackforwardlist_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKitGtk_testwebhistoryitem_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testwebhistoryitem.c
-Programs_TestWebKitAPI_WebKitGtk_testwebhistoryitem_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testwebhistoryitem_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testwebhistoryitem_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKitGtk_testwindow_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testwindow.c
-Programs_TestWebKitAPI_WebKitGtk_testwindow_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testwindow_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testwindow_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKitGtk_testdownload_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testdownload.c
-Programs_TestWebKitAPI_WebKitGtk_testdownload_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testdownload_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testdownload_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKitGtk_testatk_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testatk.c
-Programs_TestWebKitAPI_WebKitGtk_testatk_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testatk_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testatk_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKitGtk_testatkroles_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testatkroles.c
-Programs_TestWebKitAPI_WebKitGtk_testatkroles_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testatkroles_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testatkroles_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKitGtk_testwebinspector_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testwebinspector.c \
- Tools/TestWebKitAPI/Tests/WebKitGtk/test_utils.c
-Programs_TestWebKitAPI_WebKitGtk_testwebinspector_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testwebinspector_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testwebinspector_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKitGtk_testwebsettings_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testwebsettings.c
-Programs_TestWebKitAPI_WebKitGtk_testwebsettings_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testwebsettings_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testwebsettings_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKitGtk_testwebresource_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testwebresource.c
-Programs_TestWebKitAPI_WebKitGtk_testwebresource_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testwebresource_LDADD = $(webkitgtk_tests_ldadd)
-
-Programs_TestWebKitAPI_WebKitGtk_testwebdatasource_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testwebdatasource.c
-Programs_TestWebKitAPI_WebKitGtk_testwebdatasource_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testwebdatasource_LDADD = $(webkitgtk_tests_ldadd)
-
-Programs_TestWebKitAPI_WebKitGtk_testwebview_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testwebview.c Tools/TestWebKitAPI/Tests/WebKitGtk/test_utils.c
-Programs_TestWebKitAPI_WebKitGtk_testwebview_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testwebview_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testwebview_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKitGtk_testhittestresult_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testhittestresult.c
-Programs_TestWebKitAPI_WebKitGtk_testhittestresult_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testhittestresult_LDADD = $(webkitgtk_tests_ldadd)
-
-Programs_TestWebKitAPI_WebKitGtk_testkeyevents_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testkeyevents.c
-Programs_TestWebKitAPI_WebKitGtk_testkeyevents_CFLAGS = $(webkitgtk_tests_cflags)
-Programs_TestWebKitAPI_WebKitGtk_testkeyevents_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testkeyevents_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKitGtk_testcopyandpaste_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKitGtk/testcopyandpaste.c \
- Source/WebCore/platform/gtk/GtkVersioning.c
-Programs_TestWebKitAPI_WebKitGtk_testcopyandpaste_CFLAGS = \
- $(webkitgtk_tests_cflags) \
- -I$(srcdir)/Source/WebCore/platform/gtk \
- -I$(srcdir)/Source/WebCore
-Programs_TestWebKitAPI_WebKitGtk_testcopyandpaste_LDADD = $(webkitgtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKitGtk_testcopyandpaste_LDFLAGS = $(webkitgtk_tests_ldflags)
-
-
-Programs_TestWebKitAPI_WebKit2_TestWebKit2_CPPFLAGS = \
- $(Programs_TestWebKitAPI_WTF_TestWTF_CPPFLAGS) \
- -I$(top_builddir)/DerivedSources/WebKit2/include \
- $(FREETYPE_CFLAGS) \
- $(GLIB_CFLAGS) \
- $(GTK_CFLAGS) \
- $(LIBSOUP_CFLAGS)
-
-Programs_TestWebKitAPI_WebKit2_TestWebKit2_CXXFLAGS = \
- -DGTEST_HAS_RTTI=0 \
- $(global_cxxflags)
-
-Programs_TestWebKitAPI_WebKit2_TestWebKit2_LDADD = \
- Libraries/libTestWebKitAPIMain.la \
- Libraries/libgtest.la \
- libjavascriptcoregtk-@WEBKITGTK_API_MAJOR_VERSION@.@WEBKITGTK_API_MINOR_VERSION@.la \
- libwebkit2gtk-@WEBKITGTK_API_MAJOR_VERSION@.@WEBKITGTK_API_MINOR_VERSION@.la \
- $(FREETYPE_LIBS) \
- $(GLIB_LIBS) \
- $(GTK_LIBS) \
- $(LIBSOUP_LIBS)
-
-Programs_TestWebKitAPI_WebKit2_TestWebKit2_LDFLAGS = \
- $(Programs_TestWebKitAPI_WTF_TestWTF_LDFLAGS)
-
-Programs_TestWebKitAPI_WebKit2_TestWebKit2_SOURCES = \
- Tools/TestWebKitAPI/config.h \
- Tools/TestWebKitAPI/gtk/PlatformUtilitiesGtk.cpp \
- Tools/TestWebKitAPI/gtk/PlatformWebViewGtk.cpp \
- Tools/TestWebKitAPI/JavaScriptTest.cpp \
- Tools/TestWebKitAPI/JavaScriptTest.h \
- Tools/TestWebKitAPI/PlatformUtilities.cpp \
- Tools/TestWebKitAPI/PlatformUtilities.h \
- Tools/TestWebKitAPI/PlatformWebView.h \
- Tools/TestWebKitAPI/Tests/WebKit2/AboutBlankLoad.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/CanHandleRequest.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/CloseThenTerminate.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/CookieManager.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/DidAssociateFormControls.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/DidNotHandleKeyDown.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/DOMWindowExtensionBasic.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/DOMWindowExtensionNoCache.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/DownloadDecideDestinationCrash.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/EvaluateJavaScript.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/FailedLoad.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/Find.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/ForceRepaint.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/FrameMIMETypeHTML.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/FrameMIMETypePNG.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/Geolocation.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/GetInjectedBundleInitializationUserDataCallback.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/HitTestResultNodeHandle.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleBasic.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleFrameHitTest.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleInitializationUserDataCallbackWins.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/LayoutMilestonesWithAllContentInFrame.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/LoadAlternateHTMLStringWithNonDirectoryURL.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/LoadCanceledNoServerRedirectCallback.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/LoadPageOnCrash.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/MouseMoveAfterCrash.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayout.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFails.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutForImages.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFrames.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/PageLoadBasic.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/PageLoadDidChangeLocationWithinPageForFrame.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/ParentFrame.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/PreventEmptyUserAgent.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/PrivateBrowsingPushStateNoHistoryCallback.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/ReloadPageAfterCrash.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/ResizeReversePaginatedWebView.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/ResizeWindowAfterCrash.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/ResponsivenessTimerDoesntFireEarly.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/RestoreSessionStateContainingFormData.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/ScrollPinningBehaviors.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/ShouldGoToBackForwardListItem.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/SpacebarScrolling.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/TerminateTwice.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/UserMessage.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/WillLoad.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/WillSendSubmitEvent.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/WKPageGetScaleFactorNotZero.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/WKPreferences.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/WKString.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/WKStringJSString.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/WKURL.cpp
-
-if ENABLE_WEBKIT2
-noinst_LTLIBRARIES += \
- Libraries/libTestWebKitAPIInjectedBundle.la
-endif # ENABLE_WEBKIT2
-
-Libraries_libTestWebKitAPIInjectedBundle_la_SOURCES = \
- Tools/TestWebKitAPI/InjectedBundleController.cpp \
- Tools/TestWebKitAPI/InjectedBundleController.h \
- Tools/TestWebKitAPI/InjectedBundleMain.cpp \
- Tools/TestWebKitAPI/InjectedBundleTest.h \
- Tools/TestWebKitAPI/PlatformUtilities.cpp \
- Tools/TestWebKitAPI/PlatformUtilities.h \
- Tools/TestWebKitAPI/Tests/WebKit2/CanHandleRequest_Bundle.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/DidAssociateFormControls_Bundle.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash_Bundle.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/DOMWindowExtensionBasic_Bundle.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/DOMWindowExtensionNoCache_Bundle.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/GetInjectedBundleInitializationUserDataCallback_Bundle.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/HitTestResultNodeHandle_Bundle.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleBasic_Bundle.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleFrameHitTest_Bundle.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleInitializationUserDataCallbackWins_Bundle.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/LoadCanceledNoServerRedirectCallback_Bundle.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/MouseMoveAfterCrash_Bundle.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayout_Bundle.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFails_Bundle.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutForImages_Bundle.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFrames_Bundle.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/ParentFrame_Bundle.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/ResponsivenessTimerDoesntFireEarly_Bundle.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/ShouldGoToBackForwardListItem_Bundle.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/UserMessage_Bundle.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/WillLoad_Bundle.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2/WillSendSubmitEvent_Bundle.cpp \
- Tools/TestWebKitAPI/gtk/InjectedBundleControllerGtk.cpp \
- Tools/TestWebKitAPI/gtk/PlatformUtilitiesGtk.cpp
-
-Libraries_libTestWebKitAPIInjectedBundle_la_LDFLAGS = \
- -rpath ${shell pwd}/$(top_builddir)/Libraries/.libs \
- $(no_undefined) \
- -avoid-version \
- -module
-
-Libraries_libTestWebKitAPIInjectedBundle_la_CPPFLAGS = \
- $(Libraries_libTestWebKitAPIMain_la_CPPFLAGS) \
- -I$(top_builddir)/DerivedSources/InjectedBundle \
- $(GTK_CFLAGS)
-
-Libraries_libTestWebKitAPIInjectedBundle_la_CXXFLAGS = \
- -DGTEST_HAS_RTTI=0 \
- $(global_cxxflags)
-
-Libraries_libTestWebKitAPIInjectedBundle_la_CFLAGS = \
- $(global_cflags)
-
-
-if ENABLE_WEBKIT2
-noinst_LTLIBRARIES += Libraries/WebExtensions/libWebExtensionTest.la
-endif
-
-Libraries_WebExtensions_libWebExtensionTest_la_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebExtensionTest.cpp
-
-Libraries_WebExtensions_libWebExtensionTest_la_LDFLAGS = \
- -rpath ${shell pwd}/$(top_builddir)/Libraries/WebExtensions/.libs \
- $(no_undefined) \
- -avoid-version \
- -module
-
-Libraries_WebExtensions_libWebExtensionTest_la_CPPFLAGS = \
- -I$(srcdir)/Source/WebKit2/WebProcess/InjectedBundle/API/gtk \
- -I$(top_builddir)/DerivedSources \
- -I$(top_builddir)/DerivedSources/WebKit2/webkit2extension/include \
- -DWEBKIT2_COMPILATION \
- $(webkit2gtk_tests_cppflags)
-
-Libraries_WebExtensions_libWebExtensionTest_la_CXXFLAGS = \
- $(global_cxxflags)
-
-Libraries_WebExtensions_libWebExtensionTest_la_CFLAGS = \
- $(global_cflags)
-
-
-if ENABLE_WEBKIT2
-noinst_LTLIBRARIES += Libraries/WebExtensions/libWebProcessTest.la
-endif
-
-Libraries_WebExtensions_libWebProcessTest_la_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/DOMNodeTest.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/FrameTest.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebProcessTest.cpp \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebProcessTest.h
-
-Libraries_WebExtensions_libWebProcessTest_la_LDFLAGS = \
- -rpath ${shell pwd}/$(top_builddir)/Libraries/WebExtensions/.libs \
- $(no_undefined) \
- -avoid-version \
- -module
-
-Libraries_WebExtensions_libWebProcessTest_la_CPPFLAGS = \
- -I$(srcdir)/Source/WebKit2/WebProcess/InjectedBundle/API/gtk \
- -I$(top_builddir)/DerivedSources \
- -I$(top_builddir)/DerivedSources/WebKit2/webkit2extension/include \
- -DWEBKIT2_COMPILATION \
- $(webkit2gtk_tests_cppflags)
-
-Libraries_WebExtensions_libWebProcessTest_la_CXXFLAGS = \
- $(global_cxxflags)
-
-Libraries_WebExtensions_libWebProcessTest_la_CFLAGS = \
- $(global_cflags)
-
-
-Programs/TestWebKitAPI/WebKit2Gtk/resources/webkit2gtk-tests-resources.gresource: Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/webkit2gtk-tests.gresource.xml $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --generate-dependencies $(srcdir)/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/webkit2gtk-tests.gresource.xml)
- $(AM_V_at)mkdir -p ${GENPROGRAMS}/TestWebKitAPI/WebKit2Gtk/resources
- $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(srcdir) $<
-
-DISTCLEANFILES += \
- Programs/TestWebKitAPI/WebKit2Gtk/resources/webkit2gtk-tests-resources.gresource
-
-noinst_DATA += \
- Programs/TestWebKitAPI/WebKit2Gtk/resources/webkit2gtk-tests-resources.gresource
-
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitWebContext_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitWebContext.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitWebContext_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitWebContext_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitWebContext_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitWebView_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitWebView.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitWebView_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitWebView_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitWebView_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestLoaderClient_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestLoaderClient.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestLoaderClient_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_TestLoaderClient_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_TestLoaderClient_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestMultiprocess_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestMultiprocess.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestMultiprocess_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_TestMultiprocess_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_TestMultiprocess_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitSettings_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitSettings.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitSettings_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitSettings_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitSettings_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_InspectorTestServer_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/InspectorTestServer.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_InspectorTestServer_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_InspectorTestServer_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_InspectorTestServer_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestBackForwardList_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestBackForwardList.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestBackForwardList_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_TestBackForwardList_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_TestBackForwardList_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitPolicyClient_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitPolicyClient.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitPolicyClient_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitPolicyClient_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitPolicyClient_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-if HAVE_ATSPI2
-Programs_TestWebKitAPI_WebKit2Gtk_AccessibilityTestServer_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/AccessibilityTestServer.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_AccessibilityTestServer_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_AccessibilityTestServer_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_AccessibilityTestServer_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitAccessibility_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitAccessibility.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitAccessibility_CPPFLAGS = $(webkit2gtk_tests_cppflags) $(ATSPI2_CFLAGS)
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitAccessibility_LDADD = $(webkit2gtk_tests_ldadd) $(ATSPI2_LIBS)
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitAccessibility_LDFLAGS = $(webkit2gtk_tests_ldflags)
-endif
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestDownloads_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDownloads.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestDownloads_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_TestDownloads_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_TestDownloads_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebViewEditor_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebViewEditor.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebViewEditor_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebViewEditor_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebViewEditor_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestPrinting_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestPrinting.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestPrinting_CPPFLAGS = $(webkit2gtk_tests_cppflags) $(GTK_UNIX_PRINTING_CFLAGS)
-Programs_TestWebKitAPI_WebKit2Gtk_TestPrinting_LDADD = $(webkit2gtk_tests_ldadd) $(GTK_UNIX_PRINTING_LIBS)
-Programs_TestWebKitAPI_WebKit2Gtk_TestPrinting_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitFaviconDatabase_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitFaviconDatabase.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitFaviconDatabase_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitFaviconDatabase_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitFaviconDatabase_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitFindController_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitFindController.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitFindController_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitFindController_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitFindController_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestResources_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestResources.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestResources_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_TestResources_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_TestResources_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestCookieManager_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestCookieManager.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestCookieManager_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_TestCookieManager_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_TestCookieManager_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestInspector_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestInspector.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestInspector_CPPFLAGS = \
- $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_TestInspector_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_TestInspector_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestInspectorServer_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestInspectorServer.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestInspectorServer_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_TestInspectorServer_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_TestInspectorServer_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitVersion_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitVersion.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitVersion_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitVersion_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitVersion_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestContextMenu_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestContextMenu.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestContextMenu_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_TestContextMenu_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_TestContextMenu_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestSSL_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestSSL.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestSSL_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_TestSSL_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_TestSSL_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebExtensions_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebExtensions.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebExtensions_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebExtensions_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebExtensions_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitWebViewGroup_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitWebViewGroup.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitWebViewGroup_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitWebViewGroup_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_TestWebKitWebViewGroup_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestDOMNode_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDOMNode.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestDOMNode_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_TestDOMNode_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_TestDOMNode_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestFrame_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestFrame.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestFrame_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_TestFrame_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_TestFrame_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestAuthentication_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestAuthentication.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestAuthentication_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_TestAuthentication_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_TestAuthentication_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-Programs_TestWebKitAPI_WebKit2Gtk_TestUIClient_SOURCES = \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestUIClient.cpp
-Programs_TestWebKitAPI_WebKit2Gtk_TestUIClient_CPPFLAGS = $(webkit2gtk_tests_cppflags)
-Programs_TestWebKitAPI_WebKit2Gtk_TestUIClient_LDADD = $(webkit2gtk_tests_ldadd)
-Programs_TestWebKitAPI_WebKit2Gtk_TestUIClient_LDFLAGS = $(webkit2gtk_tests_ldflags)
-
-
-stamp-testwebkitapi-webcore-forwarding-headers: $(WebKit2)/Scripts/generate-forwarding-headers.pl $(Programs_TestWebKitAPI_WebCore_TestWebCore_SOURCES)
- $(AM_V_GEN)$(PERL) $< $(srcdir)/Tools/TestWebKitAPI/Tests/WebCore $(GENSOURCES_WEBCORE)/include gtk \
- && echo timestamp > $(@F)
-
-stamp-testwebkitapi-webkit2-forwarding-headers: $(WebKit2)/Scripts/generate-forwarding-headers.pl $(Programs_TestWebKitAPI_WebKit2_TestWebKit2_SOURCES) $(Libraries_libTestWebKitAPIInjectedBundle_la_SOURCES)
- $(AM_V_GEN)$(PERL) $< $(srcdir)/Tools/TestWebKitAPI $(GENSOURCES_WEBKIT2)/include gtk \
- && echo timestamp > $(@F)
-
-BUILT_SOURCES += $(top_builddir)/stamp-testwebkitapi-webcore-forwarding-headers
-if ENABLE_WEBKIT2
-BUILT_SOURCES += $(top_builddir)/stamp-testwebkitapi-webkit2-forwarding-headers
-endif # ENABLE_WEBKIT2
-
-
-EXTRA_DIST += \
- Tools/TestWebKitAPI/Tests/WebKit2/18-characters.html \
- Tools/TestWebKitAPI/Tests/WebKit2/file-with-anchor.html \
- Tools/TestWebKitAPI/Tests/WebKit2/find.html \
- Tools/TestWebKitAPI/Tests/WebKit2/icon.png \
- Tools/TestWebKitAPI/Tests/WebKit2/lots-of-iframes.html \
- Tools/TestWebKitAPI/Tests/WebKit2/lots-of-images.html \
- Tools/TestWebKitAPI/Tests/WebKit2/lots-of-text.html \
- Tools/TestWebKitAPI/Tests/WebKit2/mouse-move-listener.html \
- Tools/TestWebKitAPI/Tests/WebKit2/push-state.html \
- Tools/TestWebKitAPI/Tests/WebKit2/simple-accelerated-compositing.html \
- Tools/TestWebKitAPI/Tests/WebKit2/simple-form.html \
- Tools/TestWebKitAPI/Tests/WebKit2/simple.html \
- Tools/TestWebKitAPI/Tests/WebKit2/simple-iframe.html \
- Tools/TestWebKitAPI/Tests/WebKit2/simple-tall.html \
- Tools/TestWebKitAPI/Tests/WebKit2/spacebar-scrolling.html \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/test-cert.pem \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/test-key.pem \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/webkit2gtk-tests.gresource.xml \
- Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/link-title.js \
- Tools/TestWebKitAPI/Tests/WebKitGtk/test_utils.h \
- Tools/TestWebKitAPI/Tests/WebKitGtk/resources/blank.ico \
- Tools/TestWebKitAPI/Tests/WebKitGtk/resources/test.html \
- Tools/TestWebKitAPI/Tests/WebKitGtk/resources/test.ogg \
- Tools/TestWebKitAPI/Tests/WebKitGtk/resources/test.pdf \
- Tools/TestWebKitAPI/Tests/WebKitGtk/resources/test.txt
diff --git a/Tools/TestWebKitAPI/InjectedBundleController.cpp b/Tools/TestWebKitAPI/InjectedBundleController.cpp
index 00b534b0e..53f39a874 100644
--- a/Tools/TestWebKitAPI/InjectedBundleController.cpp
+++ b/Tools/TestWebKitAPI/InjectedBundleController.cpp
@@ -24,6 +24,9 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "InjectedBundleController.h"
#include "InjectedBundleTest.h"
@@ -33,7 +36,7 @@
namespace TestWebKitAPI {
-InjectedBundleController& InjectedBundleController::shared()
+InjectedBundleController& InjectedBundleController::singleton()
{
static InjectedBundleController& shared = *new InjectedBundleController;
return shared;
@@ -138,3 +141,5 @@ void InjectedBundleController::registerCreateInjectedBundleTestFunction(const st
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/InjectedBundleController.h b/Tools/TestWebKitAPI/InjectedBundleController.h
index 0ca112584..eaa7f0d17 100644
--- a/Tools/TestWebKitAPI/InjectedBundleController.h
+++ b/Tools/TestWebKitAPI/InjectedBundleController.h
@@ -26,7 +26,7 @@
#ifndef InjectedBundleController_h
#define InjectedBundleController_h
-#include <WebKit2/WKBundle.h>
+#include <WebKit/WKBundle.h>
#include <map>
#include <string>
@@ -36,7 +36,7 @@ class InjectedBundleTest;
class InjectedBundleController {
public:
- static InjectedBundleController& shared();
+ static InjectedBundleController& singleton();
void initialize(WKBundleRef, WKTypeRef);
diff --git a/Tools/TestWebKitAPI/InjectedBundleMain.cpp b/Tools/TestWebKitAPI/InjectedBundleMain.cpp
index 8ad6c2bad..b2537f737 100644
--- a/Tools/TestWebKitAPI/InjectedBundleMain.cpp
+++ b/Tools/TestWebKitAPI/InjectedBundleMain.cpp
@@ -24,8 +24,11 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "InjectedBundleController.h"
-#include <WebKit2/WKBundleInitialize.h>
+#include <WebKit/WKBundleInitialize.h>
#if defined(WIN32) || defined(_WIN32)
extern "C" __declspec(dllexport)
@@ -34,5 +37,7 @@ extern "C"
#endif
void WKBundleInitialize(WKBundleRef bundle, WKTypeRef initializationUserData)
{
- TestWebKitAPI::InjectedBundleController::shared().initialize(bundle, initializationUserData);
+ TestWebKitAPI::InjectedBundleController::singleton().initialize(bundle, initializationUserData);
}
+
+#endif
diff --git a/Tools/TestWebKitAPI/InjectedBundleTest.h b/Tools/TestWebKitAPI/InjectedBundleTest.h
index d0f996aff..ad2cb9581 100644
--- a/Tools/TestWebKitAPI/InjectedBundleTest.h
+++ b/Tools/TestWebKitAPI/InjectedBundleTest.h
@@ -48,7 +48,7 @@ public:
public:
Register(const std::string& test)
{
- InjectedBundleController::shared().registerCreateInjectedBundleTestFunction(test, Register::create);
+ InjectedBundleController::singleton().registerCreateInjectedBundleTestFunction(test, Register::create);
}
private:
diff --git a/Tools/TestWebKitAPI/JavaScriptTest.cpp b/Tools/TestWebKitAPI/JavaScriptTest.cpp
index de1848fdc..133d99eee 100644
--- a/Tools/TestWebKitAPI/JavaScriptTest.cpp
+++ b/Tools/TestWebKitAPI/JavaScriptTest.cpp
@@ -24,14 +24,17 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "JavaScriptTest.h"
#include "PlatformUtilities.h"
#include "Test.h"
#include <JavaScriptCore/JSContextRef.h>
#include <JavaScriptCore/JSRetainPtr.h>
-#include <WebKit2/WKRetainPtr.h>
-#include <WebKit2/WKSerializedScriptValue.h>
+#include <WebKit/WKRetainPtr.h>
+#include <WebKit/WKSerializedScriptValue.h>
#include <wtf/StdLibExtras.h>
namespace TestWebKitAPI {
@@ -90,3 +93,5 @@ static void javaScriptCallback(WKSerializedScriptValueRef resultSerializedScript
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/JavaScriptTest.h b/Tools/TestWebKitAPI/JavaScriptTest.h
index c6e79c3b6..c0494b2ca 100644
--- a/Tools/TestWebKitAPI/JavaScriptTest.h
+++ b/Tools/TestWebKitAPI/JavaScriptTest.h
@@ -23,14 +23,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#if PLATFORM(MAC)
-#ifdef __OBJC__
-@class WKView;
-@class WebView;
-#else
-class WKView;
-class WebView;
-#endif
+#if PLATFORM(COCOA)
+OBJC_CLASS WKView;
+OBJC_CLASS WebView;
#endif
namespace TestWebKitAPI {
@@ -44,7 +39,7 @@ namespace TestWebKitAPI {
::testing::AssertionResult runJSTest(const char* pageExpr, const char* scriptExpr, const char* expectedResultExpr, WKPageRef, const char* script, const char* expectedResult);
::testing::AssertionResult compareJSResult(const char* script, const char* actualResult, const char* expectedResult);
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
::testing::AssertionResult runJSTest(const char* webViewExpr, const char* scriptExpr, const char* expectedResultExpr, WebView *, const char* script, const char* expectedResult);
::testing::AssertionResult runJSTest(const char* viewExpr, const char* scriptExpr, const char* expectedResultExpr, WKView *, const char* script, const char* expectedResult);
#endif
diff --git a/Tools/TestWebKitAPI/PlatformGTK.cmake b/Tools/TestWebKitAPI/PlatformGTK.cmake
new file mode 100644
index 000000000..ffc72f291
--- /dev/null
+++ b/Tools/TestWebKitAPI/PlatformGTK.cmake
@@ -0,0 +1,158 @@
+set(TESTWEBKITAPI_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/TestWebKitAPI")
+set(TESTWEBKITAPI_RUNTIME_OUTPUT_DIRECTORY_WTF "${TESTWEBKITAPI_RUNTIME_OUTPUT_DIRECTORY}/WTF")
+
+# This is necessary because it is possible to build TestWebKitAPI with WebKit2
+# disabled and this triggers the inclusion of the WebKit2 headers.
+add_definitions(-DBUILDING_WEBKIT2__)
+
+add_custom_target(TestWebKitAPI-forwarding-headers
+ COMMAND ${PERL_EXECUTABLE} ${WEBKIT2_DIR}/Scripts/generate-forwarding-headers.pl --include-path ${TESTWEBKITAPI_DIR} --output ${FORWARDING_HEADERS_DIR} --platform gtk --platform soup
+ DEPENDS WebKit2-forwarding-headers
+)
+
+set(ForwardingHeadersForTestWebKitAPI_NAME TestWebKitAPI-forwarding-headers)
+
+include_directories(
+ ${FORWARDING_HEADERS_DIR}
+ ${FORWARDING_HEADERS_DIR}/JavaScriptCore
+ ${WEBKIT2_DIR}/UIProcess/API/C/soup
+ ${WEBKIT2_DIR}/UIProcess/API/C/gtk
+ ${WEBKIT2_DIR}/UIProcess/API/gtk
+)
+
+include_directories(SYSTEM
+ ${GDK3_INCLUDE_DIRS}
+ ${GLIB_INCLUDE_DIRS}
+ ${GTK3_INCLUDE_DIRS}
+ ${LIBSOUP_INCLUDE_DIRS}
+)
+
+set(test_main_SOURCES
+ ${TESTWEBKITAPI_DIR}/gtk/main.cpp
+)
+
+set(bundle_harness_SOURCES
+ ${TESTWEBKITAPI_DIR}/gtk/InjectedBundleControllerGtk.cpp
+ ${TESTWEBKITAPI_DIR}/gtk/PlatformUtilitiesGtk.cpp
+)
+
+set(webkit2_api_harness_SOURCES
+ ${TESTWEBKITAPI_DIR}/gtk/PlatformUtilitiesGtk.cpp
+ ${TESTWEBKITAPI_DIR}/gtk/PlatformWebViewGtk.cpp
+)
+
+list(APPEND test_wtf_LIBRARIES
+ ${GDK3_LIBRARIES}
+ ${GTK3_LIBRARIES}
+)
+
+list(APPEND test_webkit2_api_LIBRARIES
+ ${GDK3_LIBRARIES}
+ ${GTK3_LIBRARIES}
+)
+
+list(APPEND test_webcore_LIBRARIES
+ WebCorePlatformGTK
+ ${GDK3_LIBRARIES}
+ ${GTK3_LIBRARIES}
+)
+ADD_WHOLE_ARCHIVE_TO_LIBRARIES(test_webcore_LIBRARIES)
+
+list(APPEND TestWebKitAPI_LIBRARIES
+ ${GDK3_LIBRARIES}
+ ${GTK3_LIBRARIES}
+)
+
+list(APPEND TestJavaScriptCore_LIBRARIES
+ ${GDK3_LIBRARIES}
+ ${GTK3_LIBRARIES}
+)
+
+add_executable(TestWebKit2
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/AboutBlankLoad.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/CanHandleRequest.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/CookieManager.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/DocumentStartUserScriptAlertCrash.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/DOMWindowExtensionBasic.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/DOMWindowExtensionNoCache.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/DownloadDecideDestinationCrash.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/EnumerateMediaDevices.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/EvaluateJavaScript.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/FailedLoad.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/Find.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/ForceRepaint.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/FrameMIMETypeHTML.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/FrameMIMETypePNG.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/Geolocation.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/GetInjectedBundleInitializationUserDataCallback.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/HitTestResultNodeHandle.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/InjectedBundleBasic.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/InjectedBundleFrameHitTest.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/InjectedBundleInitializationUserDataCallbackWins.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/LoadAlternateHTMLStringWithNonDirectoryURL.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/LoadCanceledNoServerRedirectCallback.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/LoadPageOnCrash.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/MouseMoveAfterCrash.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/NewFirstVisuallyNonEmptyLayout.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFails.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutForImages.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFrames.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/PageLoadBasic.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/PageLoadDidChangeLocationWithinPageForFrame.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/ParentFrame.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/PendingAPIRequestURL.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/PreventEmptyUserAgent.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/PrivateBrowsingPushStateNoHistoryCallback.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/ProvisionalURLAfterWillSendRequestCallback.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/ReloadPageAfterCrash.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/ResizeWindowAfterCrash.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/RestoreSessionStateContainingFormData.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/ShouldGoToBackForwardListItem.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/TextFieldDidBeginAndEndEditing.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/UserMedia.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/UserMessage.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/WillSendSubmitEvent.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/WKPageCopySessionStateWithFiltering.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/WKPageGetScaleFactorNotZero.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/WKPreferences.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/WKRetainPtr.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/WKString.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/WKStringJSString.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/WKURL.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebKit2/gtk/InputMethodFilter.cpp
+)
+
+target_link_libraries(TestWebKit2 ${test_webkit2_api_LIBRARIES})
+add_test(TestWebKit2 ${TESTWEBKITAPI_RUNTIME_OUTPUT_DIRECTORY}/WebKit2/TestWebKit2)
+set_tests_properties(TestWebKit2 PROPERTIES TIMEOUT 60)
+set_target_properties(TestWebKit2 PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${TESTWEBKITAPI_RUNTIME_OUTPUT_DIRECTORY}/WebKit2)
+
+add_executable(TestWebCore
+ ${test_main_SOURCES}
+ ${TESTWEBKITAPI_DIR}/TestsController.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebCore/CSSParser.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebCore/ComplexTextController.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebCore/FileSystem.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebCore/GridPosition.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebCore/HTMLParserIdioms.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebCore/LayoutUnit.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebCore/PublicSuffix.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebCore/SecurityOrigin.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebCore/SharedBuffer.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebCore/SharedBufferTest.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebCore/URL.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebCore/URLParser.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WebCore/UserAgentQuirks.cpp
+)
+
+target_link_libraries(TestWebCore ${test_webcore_LIBRARIES})
+add_dependencies(TestWebCore ${ForwardingHeadersForTestWebKitAPI_NAME})
+
+add_test(TestWebCore ${TESTWEBKITAPI_RUNTIME_OUTPUT_DIRECTORY}/WebCore/TestWebCore)
+set_tests_properties(TestWebCore PROPERTIES TIMEOUT 60)
+set_target_properties(TestWebCore PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${TESTWEBKITAPI_RUNTIME_OUTPUT_DIRECTORY}/WebCore)
+
+list(APPEND TestWTF_SOURCES
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/glib/GUniquePtr.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/glib/WorkQueueGLib.cpp
+)
diff --git a/Tools/TestWebKitAPI/PlatformJSCOnly.cmake b/Tools/TestWebKitAPI/PlatformJSCOnly.cmake
new file mode 100644
index 000000000..986796034
--- /dev/null
+++ b/Tools/TestWebKitAPI/PlatformJSCOnly.cmake
@@ -0,0 +1,21 @@
+set(TESTWEBKITAPI_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/TestWebKitAPI")
+set(TESTWEBKITAPI_RUNTIME_OUTPUT_DIRECTORY_WTF "${TESTWEBKITAPI_RUNTIME_OUTPUT_DIRECTORY}/WTF")
+
+include_directories(
+ ${DERIVED_SOURCES_DIR}/ForwardingHeaders
+)
+
+if (LOWERCASE_EVENT_LOOP_TYPE STREQUAL "glib")
+ include_directories(SYSTEM
+ ${GLIB_INCLUDE_DIRS}
+ )
+endif ()
+
+set(test_main_SOURCES
+ ${TESTWEBKITAPI_DIR}/jsconly/main.cpp
+)
+
+list(APPEND TestWTF_SOURCES
+ ${TESTWEBKITAPI_DIR}/jsconly/PlatformUtilitiesJSCOnly.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/RunLoop.cpp
+)
diff --git a/Tools/TestWebKitAPI/PlatformUtilities.cpp b/Tools/TestWebKitAPI/PlatformUtilities.cpp
index cebff7be9..c341d80be 100644
--- a/Tools/TestWebKitAPI/PlatformUtilities.cpp
+++ b/Tools/TestWebKitAPI/PlatformUtilities.cpp
@@ -31,6 +31,8 @@
namespace TestWebKitAPI {
namespace Util {
+#if WK_HAVE_C_SPI
+
WKContextRef createContextWithInjectedBundle()
{
WKRetainPtr<WKStringRef> injectedBundlePath(AdoptWK, createInjectedBundlePath());
@@ -76,14 +78,16 @@ std::string toSTD(WKRetainPtr<WKStringRef> string)
return toSTD(string.get());
}
-std::string toSTD(const char* string)
+WKRetainPtr<WKStringRef> toWK(const char* utf8String)
{
- return std::string(string);
+ return WKRetainPtr<WKStringRef>(AdoptWK, WKStringCreateWithUTF8CString(utf8String));
}
-WKRetainPtr<WKStringRef> toWK(const char* utf8String)
+#endif // WK_HAVE_C_SPI
+
+std::string toSTD(const char* string)
{
- return WKRetainPtr<WKStringRef>(AdoptWK, WKStringCreateWithUTF8CString(utf8String));
+ return std::string(string);
}
} // namespace Util
diff --git a/Tools/TestWebKitAPI/PlatformUtilities.h b/Tools/TestWebKitAPI/PlatformUtilities.h
index 10da84d33..86ddcfa57 100644
--- a/Tools/TestWebKitAPI/PlatformUtilities.h
+++ b/Tools/TestWebKitAPI/PlatformUtilities.h
@@ -26,15 +26,16 @@
#ifndef PlatformUtilities_h
#define PlatformUtilities_h
-#include <WebKit2/WKRetainPtr.h>
+#ifndef BUILDING_JSCONLY__
+#include <WebKit/WKNativeEvent.h>
+#include <WebKit/WKRetainPtr.h>
+#endif
+
+#include "Utilities.h"
#include <string>
-#if PLATFORM(MAC)
-#if __OBJC__
-@class NSString;
-#else
-class NSString;
-#endif
+#if USE(FOUNDATION)
+OBJC_CLASS NSString;
#endif
namespace TestWebKitAPI {
@@ -42,12 +43,14 @@ namespace Util {
// Runs a platform runloop until the 'done' is true.
void run(bool* done);
+void sleep(double seconds);
-#if PLATFORM(WIN)
-bool shouldTranslateMessage(const MSG&);
+std::string toSTD(const char*);
+#if USE(FOUNDATION)
+std::string toSTD(NSString *);
#endif
-void sleep(double seconds);
+#if WK_HAVE_C_SPI
WKContextRef createContextWithInjectedBundle();
WKContextRef createContextForInjectedBundleTest(const std::string&, WKTypeRef userData = 0);
@@ -62,13 +65,11 @@ bool isKeyDown(WKNativeEventPtr);
std::string toSTD(WKStringRef);
std::string toSTD(WKRetainPtr<WKStringRef>);
-std::string toSTD(const char*);
-#if PLATFORM(MAC)
-std::string toSTD(NSString *);
-#endif
WKRetainPtr<WKStringRef> toWK(const char* utf8String);
+#endif // WK_HAVE_C_SPI
+
template<typename T, typename U>
static inline ::testing::AssertionResult assertWKStringEqual(const char* expected_expression, const char* actual_expression, T expected, U actual)
{
@@ -78,6 +79,10 @@ static inline ::testing::AssertionResult assertWKStringEqual(const char* expecte
#define EXPECT_WK_STREQ(expected, actual) \
EXPECT_PRED_FORMAT2(TestWebKitAPI::Util::assertWKStringEqual, expected, actual)
+#if WK_API_ENABLED
+extern NSString * const TestPlugInClassNameParameter;
+#endif
+
} // namespace Util
} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/PlatformWebView.h b/Tools/TestWebKitAPI/PlatformWebView.h
index 8679fa2c4..9c807321c 100644
--- a/Tools/TestWebKitAPI/PlatformWebView.h
+++ b/Tools/TestWebKitAPI/PlatformWebView.h
@@ -30,7 +30,11 @@
#include <CoreGraphics/CGGeometry.h>
#endif
-#ifdef __APPLE__
+#if PLATFORM(MAC)
+#include <objc/objc.h>
+#endif
+
+#if defined(__APPLE__) && !PLATFORM(GTK)
#ifdef __OBJC__
@class WKView;
@class NSWindow;
@@ -40,32 +44,24 @@ class NSWindow;
#endif
typedef WKView *PlatformWKView;
typedef NSWindow *PlatformWindow;
-#elif defined(WIN32) || defined(_WIN32)
-typedef WKViewRef PlatformWKView;
-typedef HWND PlatformWindow;
#elif PLATFORM(GTK)
typedef WKViewRef PlatformWKView;
typedef GtkWidget *PlatformWindow;
#elif PLATFORM(EFL)
-typedef struct _Ecore_Evas Ecore_Evas;
-#if USE(EO)
-typedef struct _Eo_Opaque Evas_Object;
-#else
-typedef struct _Evas_Object Evas_Object;
-#endif
typedef Evas_Object* PlatformWKView;
typedef Ecore_Evas* PlatformWindow;
#endif
namespace TestWebKitAPI {
-#if PLATFORM(WIN)
-class WindowMessageObserver;
-#endif
-
class PlatformWebView {
public:
- PlatformWebView(WKContextRef, WKPageGroupRef = 0);
+ explicit PlatformWebView(WKPageConfigurationRef);
+ explicit PlatformWebView(WKContextRef, WKPageGroupRef = 0);
+ explicit PlatformWebView(WKPageRef relatedPage);
+#if PLATFORM(MAC)
+ explicit PlatformWebView(WKContextRef, WKPageGroupRef, Class wkViewSubclass);
+#endif
~PlatformWebView();
WKPageRef page() const;
@@ -76,25 +72,20 @@ public:
void simulateSpacebarKeyPress();
void simulateAltKeyPress();
void simulateRightClick(unsigned x, unsigned y);
- void simulateMouseMove(unsigned x, unsigned y);
-
-#if PLATFORM(WIN)
- void simulateAKeyDown();
- void setParentWindowMessageObserver(WindowMessageObserver* observer) { m_parentWindowMessageObserver = observer; }
+ void simulateMouseMove(unsigned x, unsigned y, WKEventModifiers = 0);
+#if PLATFORM(MAC)
+ void simulateButtonClick(WKEventMouseButton, unsigned x, unsigned y, WKEventModifiers);
#endif
private:
-#if PLATFORM(WIN)
- static void registerWindowClass();
- static LRESULT CALLBACK wndProc(HWND, UINT message, WPARAM, LPARAM);
+#if PLATFORM(MAC)
+ void initialize(WKPageConfigurationRef, Class wkViewSubclass);
+#elif PLATFORM(GTK)
+ void initialize(WKPageConfigurationRef);
#endif
PlatformWKView m_view;
PlatformWindow m_window;
-
-#if PLATFORM(WIN)
- WindowMessageObserver* m_parentWindowMessageObserver;
-#endif
};
} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Test.h b/Tools/TestWebKitAPI/Test.h
index ca43924a2..cf44045fb 100644
--- a/Tools/TestWebKitAPI/Test.h
+++ b/Tools/TestWebKitAPI/Test.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,6 +26,8 @@
#ifndef Test_h
#define Test_h
+#include <type_traits>
+
namespace TestWebKitAPI {
#define EXPECT_NOT_NULL(expression) \
@@ -40,6 +42,18 @@ namespace TestWebKitAPI {
#define ASSERT_NULL(expression) \
ASSERT_TRUE(!(expression))
+template<typename T>
+static inline ::testing::AssertionResult assertStrongEnum(const char* expected_expression, const char* actual_expression, T expected, T actual)
+{
+ static_assert(std::is_enum<T>::value, "T is not an enum type");
+ typedef typename std::underlying_type<T>::type UnderlyingStorageType;
+ return ::testing::internal::CmpHelperEQ(expected_expression, actual_expression, static_cast<UnderlyingStorageType>(expected), static_cast<UnderlyingStorageType>(actual));
+}
+
+#define EXPECT_STRONG_ENUM_EQ(expected, actual) \
+ EXPECT_PRED_FORMAT2(TestWebKitAPI::assertStrongEnum, expected, actual)
+
+
} // namespace TestWebKitAPI
#endif // Test_h
diff --git a/Tools/TestWebKitAPI/Tests/JavaScriptCore/VMInspector.cpp b/Tools/TestWebKitAPI/Tests/JavaScriptCore/VMInspector.cpp
deleted file mode 100644
index b1c1bacf3..000000000
--- a/Tools/TestWebKitAPI/Tests/JavaScriptCore/VMInspector.cpp
+++ /dev/null
@@ -1,689 +0,0 @@
-/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#include <interpreter/VMInspector.h>
-#include <stdarg.h>
-#include <stdio.h>
-
-using namespace JSC;
-
-// There's not much we can test for the VMInspector::printf() case except to
-// make sure it does not crash. Unfortunately, we also don't want all the
-// test strings crowding out stdout. So, we forego the printf tests.
-// NOTE that the most interesting part of VMInspector::printf() is the
-// formatting functionality, and it is are already being tested by the
-// fprintf() and sprintf() cases.
-
-
-// The VMInspector::fprintf() test works by printing the string to a temp file,
-// and then reading the file content back into a buffer, which we, in turn,
-// compare against the expected string.
-
-TEST(JSC, VMInspectorFprintf)
-{
-#if ENABLE(VMINSPECTOR)
- char actual[1024];
- char expected[1024];
- const char* format;
- const char* expectedLiteral;
- FILE* file;
- const char* filename = "/tmp/VMInspectorFprintfTest.txt";
- size_t size;
-
-#define OPEN_FILE(file) \
- do { \
- file = fopen(filename, "w"); \
- } while (false)
-
-#define READ_AND_CLOSE_FILE(file, actual) \
- do { \
- fclose(file); \
- file = fopen(filename, "r"); \
- fseek(file, 0, SEEK_END); \
- size = ftell(file); \
- rewind(file); \
- fread(actual, 1, size, file); \
- actual[size] = '\0'; \
- fclose(file); \
- } while (false)
-
- // Testing standard default format specifiers:
- // Note: should work just like sprintf. So, we just compare against that.
- memset(actual, 'z', sizeof(actual));
- // The compiler warning flags are configured to expect a literal string for
- // ::sprintf below. So, use a #define for this one case to keep the
- // compiler happy.
-#undef LITERAL_FORMAT
-#define LITERAL_FORMAT "'%%%%' ==> '%%'\n"
-
- OPEN_FILE(file);
- VMInspector::fprintf(file, LITERAL_FORMAT);
- READ_AND_CLOSE_FILE(file, actual);
- ::sprintf(expected, LITERAL_FORMAT);
-
-#undef LITERAL_FORMAT
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%c', 'x' ==> '%c'\n";
- OPEN_FILE(file);
- VMInspector::fprintf(file, format, 'x');
- READ_AND_CLOSE_FILE(file, actual);
- ::sprintf(expected, format, 'x');
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%*c', 8, 'x' ==> '%*c'\n";
- OPEN_FILE(file);
- VMInspector::fprintf(file, format, 8, 'x');
- READ_AND_CLOSE_FILE(file, actual);
- ::sprintf(expected, format, 8, 'x');
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%s', \"hello world\" ==> '%s'\n";
- OPEN_FILE(file);
- VMInspector::fprintf(file, format, "hello world");
- READ_AND_CLOSE_FILE(file, actual);
- ::sprintf(expected, format, "hello world");
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%*s', 8, \"hello world\" ==> '%*s'\n";
- OPEN_FILE(file);
- VMInspector::fprintf(file, format, 8, "hello world");
- READ_AND_CLOSE_FILE(file, actual);
- ::sprintf(expected, format, 8, "hello world");
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%*s', 8, \"hello\" ==> '%*s'\n";
- OPEN_FILE(file);
- VMInspector::fprintf(file, format, 8, "hello");
- READ_AND_CLOSE_FILE(file, actual);
- ::sprintf(expected, format, 8, "hello");
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%d', 987654321 ==> '%d'\n";
- OPEN_FILE(file);
- VMInspector::fprintf(file, format, 987654321);
- READ_AND_CLOSE_FILE(file, actual);
- ::sprintf(expected, format, 987654321);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%u', 4276543210u ==> '%u'\n";
- OPEN_FILE(file);
- VMInspector::fprintf(file, format, 4276543210u);
- READ_AND_CLOSE_FILE(file, actual);
- ::sprintf(expected, format, 4276543210u);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%u', 0xffffffff ==> '%u'\n";
- OPEN_FILE(file);
- VMInspector::fprintf(file, format, 0xffffffff);
- READ_AND_CLOSE_FILE(file, actual);
- ::sprintf(expected, format, 0xffffffff);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%x', 0xffffffff ==> '%x'\n";
- OPEN_FILE(file);
- VMInspector::fprintf(file, format, 0xffffffff);
- READ_AND_CLOSE_FILE(file, actual);
- ::sprintf(expected, format, 0xffffffff);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%p', (void*)0xabcdbabe ==> '%p'\n";
- OPEN_FILE(file);
- VMInspector::fprintf(file, format, (void*)0xabcdbabe);
- READ_AND_CLOSE_FILE(file, actual);
- ::sprintf(expected, format, (void*)0xabcdbabe);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%lu', 1234567890987654321ul ==> '%lu'\n";
- OPEN_FILE(file);
- VMInspector::fprintf(file, format, 1234567890987654321ul);
- READ_AND_CLOSE_FILE(file, actual);
- ::sprintf(expected, format, 1234567890987654321ul);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%f', 1234.567 ==> '%f'\n";
- OPEN_FILE(file);
- VMInspector::fprintf(file, format, 1234.567);
- READ_AND_CLOSE_FILE(file, actual);
- ::sprintf(expected, format, 1234.567);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%.2f', 1234.567 ==> '%.2f'\n";
- OPEN_FILE(file);
- VMInspector::fprintf(file, format, 1234.567);
- READ_AND_CLOSE_FILE(file, actual);
- ::sprintf(expected, format, 1234.567);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%10.2f', 1234.567 ==> '%10.2f'\n";
- OPEN_FILE(file);
- VMInspector::fprintf(file, format, 1234.567);
- READ_AND_CLOSE_FILE(file, actual);
- ::sprintf(expected, format, 1234.567);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%010.2f', 1234.567 ==> '%010.2f'\n";
- OPEN_FILE(file);
- VMInspector::fprintf(file, format, 1234.567);
- READ_AND_CLOSE_FILE(file, actual);
- ::sprintf(expected, format, 1234.567);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- // Bad / weird formats:
- memset(actual, 'z', sizeof(actual));
- format = "'%%5.4', 987654321 ==> '%5.4'\n";
- OPEN_FILE(file);
- VMInspector::fprintf(file, format, 987654321);
- READ_AND_CLOSE_FILE(file, actual);
- expectedLiteral = "'%5.4', 987654321 ==> 'ERROR @ \"%5.4' \"\n";
- ASSERT_EQ(strcmp(actual, expectedLiteral), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%5.4' '%%d', 987654321, 4 ==> '%5.4' '%d'\n";
- OPEN_FILE(file);
- VMInspector::fprintf(file, format, 987654321, 4);
- READ_AND_CLOSE_FILE(file, actual);
- ::sprintf(expected, format, 987654321, 4);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%w' '%%d', 987654321, 6 ==> '%w' '%d'\n";
- OPEN_FILE(file);
- VMInspector::fprintf(file, format, 987654321, 6);
- READ_AND_CLOSE_FILE(file, actual);
- ::sprintf(expected, format, 987654321, 6);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
-
- // Testing the %b extension:
- memset(actual, 'z', sizeof(actual));
- OPEN_FILE(file);
- VMInspector::fprintf(file, "'%%b', 0 ==> '%b'\n", 0);
- READ_AND_CLOSE_FILE(file, actual);
- ASSERT_EQ(strcmp(actual, "'%b', 0 ==> 'FALSE'\n"), 0);
-
- memset(actual, 'z', sizeof(actual));
- OPEN_FILE(file);
- VMInspector::fprintf(file, "'%%b', 1 ==> '%b'\n", 1);
- READ_AND_CLOSE_FILE(file, actual);
- ASSERT_EQ(strcmp(actual, "'%b', 1 ==> 'TRUE'\n"), 0);
-
- memset(actual, 'z', sizeof(actual));
- OPEN_FILE(file);
- VMInspector::fprintf(file, "'%%b', -123456789 ==> '%b'\n", -123456789);
- READ_AND_CLOSE_FILE(file, actual);
- ASSERT_EQ(strcmp(actual, "'%b', -123456789 ==> 'TRUE'\n"), 0);
-
- memset(actual, 'z', sizeof(actual));
- OPEN_FILE(file);
- VMInspector::fprintf(file, "'%%b', 123456789 ==> '%b'\n", 123456789);
- READ_AND_CLOSE_FILE(file, actual);
- ASSERT_EQ(strcmp(actual, "'%b', 123456789 ==> 'TRUE'\n"), 0);
-
-
- // Testing the %J<x> extensions:
- String str1("Test WTF String");
- String str2("");
-
- memset(actual, 'z', sizeof(actual));
- OPEN_FILE(file);
- VMInspector::fprintf(file, "'%%Js' is %%s, &str1, str1.isEmpty()?\"EMPTY\":\"NOT EMPTY\" ==> '%Js' is %s\n",
- &str1, str1.isEmpty() ? "EMPTY" : "NOT EMPTY");
- READ_AND_CLOSE_FILE(file, actual);
- expectedLiteral = "'%Js' is %s, &str1, str1.isEmpty()?\"EMPTY\":\"NOT EMPTY\" ==> 'Test WTF String' is NOT EMPTY\n";
- ASSERT_EQ(strcmp(actual, expectedLiteral), 0);
-
- memset(actual, 'z', sizeof(actual));
- OPEN_FILE(file);
- VMInspector::fprintf(file, "'%%Js' is %%s, &str2, str2.isEmpty()?\"EMPTY\":\"NOT EMPTY\" ==> '%Js' is %s\n",
- &str2, str2.isEmpty() ? "EMPTY" : "NOT EMPTY");
- READ_AND_CLOSE_FILE(file, actual);
- expectedLiteral = "'%Js' is %s, &str2, str2.isEmpty()?\"EMPTY\":\"NOT EMPTY\" ==> '' is EMPTY\n";
- ASSERT_EQ(strcmp(actual, expectedLiteral), 0);
-
- memset(actual, 'z', sizeof(actual));
- OPEN_FILE(file);
- VMInspector::fprintf(file, "'%%J+s' is %%s, &str1, str1.isEmpty()?\"EMPTY\":\"NOT EMPTY\" ==> '%J+s' is %s\n",
- &str1, str1.isEmpty() ? "EMPTY" : "NOT EMPTY");
- READ_AND_CLOSE_FILE(file, actual);
- expectedLiteral = "'%J+s' is %s, &str1, str1.isEmpty()?\"EMPTY\":\"NOT EMPTY\" ==> 'WTF::String \"Test WTF String\"' is NOT EMPTY\n";
- ASSERT_EQ(strcmp(actual, expectedLiteral), 0);
-
- memset(actual, 'z', sizeof(actual));
- OPEN_FILE(file);
- VMInspector::fprintf(file, "'%%J+s' is %%s, &str2, str2.isEmpty()?\"EMPTY\":\"NOT EMPTY\" ==> '%J+s' is %s\n",
- &str2, str2.isEmpty() ? "EMPTY" : "NOT EMPTY");
- READ_AND_CLOSE_FILE(file, actual);
- expectedLiteral = "'%J+s' is %s, &str2, str2.isEmpty()?\"EMPTY\":\"NOT EMPTY\" ==> 'WTF::String \"\"' is EMPTY\n";
- ASSERT_EQ(strcmp(actual, expectedLiteral), 0);
-
-#undef OPEN_FILE
-#undef READ_AND_CLOSE_FILE
-
-#endif
-}
-
-
-TEST(JSC, VMInspectorSprintf)
-{
-#if ENABLE(VMINSPECTOR)
- char actual[1024];
- char expected[1024];
- const char* format;
- const char* expectedLiteral;
-
- // Testing standard default format specifiers:
- // Note: should work just like sprintf. So, we just compare against that.
- memset(actual, 'z', sizeof(actual));
- // The compiler warning flags are configured to expect a literal string for
- // ::sprintf below. So, use a #define for this one case to keep the
- // compiler happy.
-#undef LITERAL_FORMAT
-#define LITERAL_FORMAT "'%%%%' ==> '%%'\n"
- VMInspector::sprintf(actual, LITERAL_FORMAT);
- ::sprintf(expected, LITERAL_FORMAT);
-#undef LITERAL_FORMAT
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%c', 'x' ==> '%c'\n";
- VMInspector::sprintf(actual, format, 'x');
- ::sprintf(expected, format, 'x');
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%*c', 8, 'x' ==> '%*c'\n";
- VMInspector::sprintf(actual, format, 8, 'x');
- ::sprintf(expected, format, 8, 'x');
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%s', \"hello world\" ==> '%s'\n";
- VMInspector::sprintf(actual, format, "hello world");
- ::sprintf(expected, format, "hello world");
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%*s', 8, \"hello world\" ==> '%*s'\n";
- VMInspector::sprintf(actual, format, 8, "hello world");
- ::sprintf(expected, format, 8, "hello world");
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%*s', 8, \"hello\" ==> '%*s'\n";
- VMInspector::sprintf(actual, format, 8, "hello");
- ::sprintf(expected, format, 8, "hello");
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%d', 987654321 ==> '%d'\n";
- VMInspector::sprintf(actual, format, 987654321);
- ::sprintf(expected, format, 987654321);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%u', 4276543210u ==> '%u'\n";
- VMInspector::sprintf(actual, format, 4276543210u);
- ::sprintf(expected, format, 4276543210u);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%u', 0xffffffff ==> '%u'\n";
- VMInspector::sprintf(actual, format, 0xffffffff);
- ::sprintf(expected, format, 0xffffffff);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%x', 0xffffffff ==> '%x'\n";
- VMInspector::sprintf(actual, format, 0xffffffff);
- ::sprintf(expected, format, 0xffffffff);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%p', (void*)0xabcdbabe ==> '%p'\n";
- VMInspector::sprintf(actual, format, (void*)0xabcdbabe);
- ::sprintf(expected, format, (void*)0xabcdbabe);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%lu', 1234567890987654321ul ==> '%lu'\n";
- VMInspector::sprintf(actual, format, 1234567890987654321ul);
- ::sprintf(expected, format, 1234567890987654321ul);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%f', 1234.567 ==> '%f'\n";
- VMInspector::sprintf(actual, format, 1234.567);
- ::sprintf(expected, format, 1234.567);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%.2f', 1234.567 ==> '%.2f'\n";
- VMInspector::sprintf(actual, format, 1234.567);
- ::sprintf(expected, format, 1234.567);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%10.2f', 1234.567 ==> '%10.2f'\n";
- VMInspector::sprintf(actual, format, 1234.567);
- ::sprintf(expected, format, 1234.567);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%010.2f', 1234.567 ==> '%010.2f'\n";
- VMInspector::sprintf(actual, format, 1234.567);
- ::sprintf(expected, format, 1234.567);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- // Bad / weird formats:
- memset(actual, 'z', sizeof(actual));
- format = "'%%5.4', 987654321 ==> '%5.4'\n";
- VMInspector::sprintf(actual, format, 987654321);
- expectedLiteral = "'%5.4', 987654321 ==> 'ERROR @ \"%5.4' \"\n";
- ASSERT_EQ(strcmp(actual, expectedLiteral), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%5.4' '%%d', 987654321, 4 ==> '%5.4' '%d'\n";
- VMInspector::sprintf(actual, format, 987654321, 4);
- ::sprintf(expected, format, 987654321, 4);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%w' '%%d', 987654321, 6 ==> '%w' '%d'\n";
- VMInspector::sprintf(actual, format, 987654321, 6);
- ::sprintf(expected, format, 987654321, 6);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
-
- // Testing the %b extension:
- memset(actual, 'z', sizeof(actual));
- VMInspector::sprintf(actual, "'%%b', 0 ==> '%b'\n", 0);
- ASSERT_EQ(strcmp(actual, "'%b', 0 ==> 'FALSE'\n"), 0);
-
- memset(actual, 'z', sizeof(actual));
- VMInspector::sprintf(actual, "'%%b', 1 ==> '%b'\n", 1);
- ASSERT_EQ(strcmp(actual, "'%b', 1 ==> 'TRUE'\n"), 0);
-
- memset(actual, 'z', sizeof(actual));
- VMInspector::sprintf(actual, "'%%b', -123456789 ==> '%b'\n", -123456789);
- ASSERT_EQ(strcmp(actual, "'%b', -123456789 ==> 'TRUE'\n"), 0);
-
- memset(actual, 'z', sizeof(actual));
- VMInspector::sprintf(actual, "'%%b', 123456789 ==> '%b'\n", 123456789);
- ASSERT_EQ(strcmp(actual, "'%b', 123456789 ==> 'TRUE'\n"), 0);
-
-
- // Testing the %J<x> extensions:
- String str1("Test WTF String");
- String str2("");
-
- memset(actual, 'z', sizeof(actual));
- VMInspector::sprintf(actual, "'%%Js' is %%s, &str1, str1.isEmpty()?\"EMPTY\":\"NOT EMPTY\" ==> '%Js' is %s\n",
- &str1, str1.isEmpty() ? "EMPTY" : "NOT EMPTY");
- expectedLiteral = "'%Js' is %s, &str1, str1.isEmpty()?\"EMPTY\":\"NOT EMPTY\" ==> 'Test WTF String' is NOT EMPTY\n";
- ASSERT_EQ(strcmp(actual, expectedLiteral), 0);
-
- memset(actual, 'z', sizeof(actual));
- VMInspector::sprintf(actual, "'%%Js' is %%s, &str2, str2.isEmpty()?\"EMPTY\":\"NOT EMPTY\" ==> '%Js' is %s\n",
- &str2, str2.isEmpty() ? "EMPTY" : "NOT EMPTY");
- expectedLiteral = "'%Js' is %s, &str2, str2.isEmpty()?\"EMPTY\":\"NOT EMPTY\" ==> '' is EMPTY\n";
- ASSERT_EQ(strcmp(actual, expectedLiteral), 0);
-
- memset(actual, 'z', sizeof(actual));
- VMInspector::sprintf(actual, "'%%J+s' is %%s, &str1, str1.isEmpty()?\"EMPTY\":\"NOT EMPTY\" ==> '%J+s' is %s\n",
- &str1, str1.isEmpty() ? "EMPTY" : "NOT EMPTY");
- expectedLiteral = "'%J+s' is %s, &str1, str1.isEmpty()?\"EMPTY\":\"NOT EMPTY\" ==> 'WTF::String \"Test WTF String\"' is NOT EMPTY\n";
- ASSERT_EQ(strcmp(actual, expectedLiteral), 0);
-
- memset(actual, 'z', sizeof(actual));
- VMInspector::sprintf(actual, "'%%J+s' is %%s, &str2, str2.isEmpty()?\"EMPTY\":\"NOT EMPTY\" ==> '%J+s' is %s\n",
- &str2, str2.isEmpty() ? "EMPTY" : "NOT EMPTY");
- expectedLiteral = "'%J+s' is %s, &str2, str2.isEmpty()?\"EMPTY\":\"NOT EMPTY\" ==> 'WTF::String \"\"' is EMPTY\n";
- ASSERT_EQ(strcmp(actual, expectedLiteral), 0);
-#endif
-}
-
-
-TEST(JSC, VMInspectorSnprintf)
-{
-#if ENABLE(VMINSPECTOR)
- char actual[1024];
- char expected[1024];
- const char* format;
- const char* expectedLiteral;
-
- size_t size = 1;
- while (size <= 100) {
-
- // Testing standard default format specifiers:
- // Note: should work just like snprintf. So, we just compare against that.
- memset(actual, 'z', sizeof(actual));
- // The compiler warning flags are configured to expect a literal string for
- // ::snprintf below. So, use a #define for this one case to keep the
- // compiler happy.
-#undef LITERAL_FORMAT
-#define LITERAL_FORMAT "'%%%%' ==> '%%'\n"
- VMInspector::snprintf(actual, size, LITERAL_FORMAT);
- ::snprintf(expected, size, LITERAL_FORMAT);
-#undef LITERAL_FORMAT
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%c', 'x' ==> '%c'\n";
- VMInspector::snprintf(actual, size, format, 'x');
- ::snprintf(expected, size, format, 'x');
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%*c', 8, 'x' ==> '%*c'\n";
- VMInspector::snprintf(actual, size, format, 8, 'x');
- ::snprintf(expected, size, format, 8, 'x');
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%s', \"hello world\" ==> '%s'\n";
- VMInspector::snprintf(actual, size, format, "hello world");
- ::snprintf(expected, size, format, "hello world");
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%*s', 8, \"hello world\" ==> '%*s'\n";
- VMInspector::snprintf(actual, size, format, 8, "hello world");
- ::snprintf(expected, size, format, 8, "hello world");
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%*s', 8, \"hello\" ==> '%*s'\n";
- VMInspector::snprintf(actual, size, format, 8, "hello");
- ::snprintf(expected, size, format, 8, "hello");
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%d', 987654321 ==> '%d'\n";
- VMInspector::snprintf(actual, size, format, 987654321);
- ::snprintf(expected, size, format, 987654321);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%u', 4276543210u ==> '%u'\n";
- VMInspector::snprintf(actual, size, format, 4276543210u);
- ::snprintf(expected, size, format, 4276543210u);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%u', 0xffffffff ==> '%u'\n";
- VMInspector::snprintf(actual, size, format, 0xffffffff);
- ::snprintf(expected, size, format, 0xffffffff);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%x', 0xffffffff ==> '%x'\n";
- VMInspector::snprintf(actual, size, format, 0xffffffff);
- ::snprintf(expected, size, format, 0xffffffff);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%p', (void*)0xabcdbabe ==> '%p'\n";
- VMInspector::snprintf(actual, size, format, (void*)0xabcdbabe);
- ::snprintf(expected, size, format, (void*)0xabcdbabe);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%lu', 1234567890987654321ul ==> '%lu'\n";
- VMInspector::snprintf(actual, size, format, 1234567890987654321ul);
- ::snprintf(expected, size, format, 1234567890987654321ul);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%f', 1234.567 ==> '%f'\n";
- VMInspector::snprintf(actual, size, format, 1234.567);
- ::snprintf(expected, size, format, 1234.567);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%.2f', 1234.567 ==> '%.2f'\n";
- VMInspector::snprintf(actual, size, format, 1234.567);
- ::snprintf(expected, size, format, 1234.567);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%10.2f', 1234.567 ==> '%10.2f'\n";
- VMInspector::snprintf(actual, size, format, 1234.567);
- ::snprintf(expected, size, format, 1234.567);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%010.2f', 1234.567 ==> '%010.2f'\n";
- VMInspector::snprintf(actual, size, format, 1234.567);
- ::snprintf(expected, size, format, 1234.567);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- // Bad / weird formats:
- memset(actual, 'z', sizeof(actual));
- format = "'%%5.4', 987654321 ==> '%5.4'\n";
- VMInspector::snprintf(actual, size, format, 987654321);
- expectedLiteral = "'%5.4', 987654321 ==> 'ERROR @ \"%5.4' \"\n";
- ::snprintf(expected, size, "%s", expectedLiteral);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%5.4' '%%d', 987654321, 4 ==> '%5.4' '%d'\n";
- VMInspector::snprintf(actual, size, format, 987654321, 4);
- ::snprintf(expected, size, format, 987654321, 4);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- format = "'%%w' '%%d', 987654321, 6 ==> '%w' '%d'\n";
- VMInspector::snprintf(actual, size, format, 987654321, 6);
- ::snprintf(expected, size, format, 987654321, 6);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
-
- // Testing the %b extension:
- memset(actual, 'z', sizeof(actual));
- VMInspector::snprintf(actual, size, "'%%b', 0 ==> '%b'\n", 0);
- expectedLiteral = "'%b', 0 ==> 'FALSE'\n";
- ::snprintf(expected, size, "%s", expectedLiteral);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- VMInspector::snprintf(actual, size, "'%%b', 1 ==> '%b'\n", 1);
- expectedLiteral = "'%b', 1 ==> 'TRUE'\n";
- ::snprintf(expected, size, "%s", expectedLiteral);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- VMInspector::snprintf(actual, size, "'%%b', -123456789 ==> '%b'\n", -123456789);
- expectedLiteral = "'%b', -123456789 ==> 'TRUE'\n";
- ::snprintf(expected, size, "%s", expectedLiteral);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- VMInspector::snprintf(actual, size, "'%%b', 123456789 ==> '%b'\n", 123456789);
- expectedLiteral = "'%b', 123456789 ==> 'TRUE'\n";
- ::snprintf(expected, size, "%s", expectedLiteral);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- // Testing the %J<x> extensions:
- String str1("Test WTF String");
- String str2("");
-
- memset(actual, 'z', sizeof(actual));
- VMInspector::snprintf(actual, size, "'%%Js' is %%s, &str1, str1.isEmpty()?\"EMPTY\":\"NOT EMPTY\" ==> '%Js' is %s\n",
- &str1, str1.isEmpty() ? "EMPTY" : "NOT EMPTY");
- expectedLiteral = "'%Js' is %s, &str1, str1.isEmpty()?\"EMPTY\":\"NOT EMPTY\" ==> 'Test WTF String' is NOT EMPTY\n";
- ::snprintf(expected, size, "%s", expectedLiteral);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- VMInspector::snprintf(actual, size, "'%%Js' is %%s, &str2, str2.isEmpty()?\"EMPTY\":\"NOT EMPTY\" ==> '%Js' is %s\n",
- &str2, str2.isEmpty() ? "EMPTY" : "NOT EMPTY");
- expectedLiteral = "'%Js' is %s, &str2, str2.isEmpty()?\"EMPTY\":\"NOT EMPTY\" ==> '' is EMPTY\n";
- ::snprintf(expected, size, "%s", expectedLiteral);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- VMInspector::snprintf(actual, size, "'%%J+s' is %%s, &str1, str1.isEmpty()?\"EMPTY\":\"NOT EMPTY\" ==> '%J+s' is %s\n",
- &str1, str1.isEmpty() ? "EMPTY" : "NOT EMPTY");
- expectedLiteral = "'%J+s' is %s, &str1, str1.isEmpty()?\"EMPTY\":\"NOT EMPTY\" ==> 'WTF::String \"Test WTF String\"' is NOT EMPTY\n";
- ::snprintf(expected, size, "%s", expectedLiteral);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- memset(actual, 'z', sizeof(actual));
- VMInspector::snprintf(actual, size, "'%%J+s' is %%s, &str2, str2.isEmpty()?\"EMPTY\":\"NOT EMPTY\" ==> '%J+s' is %s\n",
- &str2, str2.isEmpty() ? "EMPTY" : "NOT EMPTY");
- expectedLiteral = "'%J+s' is %s, &str2, str2.isEmpty()?\"EMPTY\":\"NOT EMPTY\" ==> 'WTF::String \"\"' is EMPTY\n";
- ::snprintf(expected, size, "%s", expectedLiteral);
- ASSERT_EQ(strcmp(actual, expected), 0);
-
- // Test lower sizes more densely, and then space out to larger sizes.
- // We're doing this because the lower sizes might be interesting, but
- // for expediency, we don't want to test at this fine grain resolution
- // for all possible sizes. Hence, we accelerate the rate once we're
- // pass the interesting small sizes.
- if (size <= 5)
- size++;
- else
- size += 4;
- }
-#endif
-}
diff --git a/Tools/TestWebKitAPI/Tests/WTF/AtomicString.cpp b/Tools/TestWebKitAPI/Tests/WTF/AtomicString.cpp
index 9df71ce44..de962ec42 100644
--- a/Tools/TestWebKitAPI/Tests/WTF/AtomicString.cpp
+++ b/Tools/TestWebKitAPI/Tests/WTF/AtomicString.cpp
@@ -39,7 +39,6 @@ TEST(WTF, AtomicStringCreationFromLiteral)
const char* programmaticStringData = "Explicit Size Literal";
AtomicString programmaticString(programmaticStringData, strlen(programmaticStringData), AtomicString::ConstructFromLiteral);
ASSERT_EQ(strlen(programmaticStringData), programmaticString.length());
- ASSERT_TRUE(programmaticStringData == programmaticStringData);
ASSERT_TRUE(programmaticString.string().is8Bit());
ASSERT_EQ(programmaticStringData, reinterpret_cast<const char*>(programmaticString.string().characters8()));
}
@@ -54,4 +53,12 @@ TEST(WTF, AtomicStringCreationFromLiteralUniqueness)
ASSERT_EQ(string1.impl(), string3.impl());
}
+TEST(WTF, AtomicStringExistingHash)
+{
+ AtomicString string1("Template Literal", AtomicString::ConstructFromLiteral);
+ ASSERT_EQ(string1.existingHash(), string1.impl()->existingHash());
+ AtomicString string2;
+ ASSERT_EQ(string2.existingHash(), 0u);
+}
+
} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/BloomFilter.cpp b/Tools/TestWebKitAPI/Tests/WTF/BloomFilter.cpp
new file mode 100644
index 000000000..802165211
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/BloomFilter.cpp
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <wtf/BloomFilter.h>
+#include <wtf/RandomNumber.h>
+#include <wtf/SHA1.h>
+
+namespace TestWebKitAPI {
+
+static Vector<unsigned> generateRandomHashes(size_t hashCount)
+{
+ Vector<unsigned> hashes;
+ for (unsigned i = 0; i < hashCount; ++i)
+ hashes.append(static_cast<unsigned>(randomNumber() * std::numeric_limits<unsigned>::max()));
+ return hashes;
+}
+
+static Vector<SHA1::Digest> generateRandomDigests(size_t hashCount)
+{
+ Vector<SHA1::Digest> hashes;
+ SHA1 sha1;
+ for (unsigned i = 0; i < hashCount; ++i) {
+ double random = randomNumber();
+ sha1.addBytes(reinterpret_cast<uint8_t*>(&random), sizeof(double));
+ SHA1::Digest digest;
+ sha1.computeHash(digest);
+ hashes.append(digest);
+ }
+ return hashes;
+}
+
+TEST(WTF_BloomFilter, Basic)
+{
+ const unsigned hashCount = 1000;
+ auto hashes = generateRandomHashes(hashCount);
+
+ BloomFilter<16> filter;
+ for (auto hash : hashes)
+ filter.add(hash);
+
+ for (auto hash : hashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+
+ auto moreHashes = generateRandomHashes(hashCount);
+ unsigned mayContainCount = 0;
+ for (auto hash : moreHashes)
+ mayContainCount += filter.mayContain(hash) ? 1 : 0;
+ // False positive rate is ~0.09% so this should always be true.
+ EXPECT_TRUE(mayContainCount < hashCount / 10);
+
+ for (auto hash : moreHashes)
+ filter.add(hash);
+
+ for (auto hash : hashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+ for (auto hash : moreHashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+}
+
+TEST(WTF_BloomFilter, BasicDigest)
+{
+ const unsigned hashCount = 1000;
+ auto hashes = generateRandomDigests(hashCount);
+
+ BloomFilter<20> filter;
+ for (auto hash : hashes)
+ filter.add(hash);
+
+ for (auto hash : hashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+
+ auto moreHashes = generateRandomDigests(hashCount);
+ unsigned mayContainCount = 0;
+ for (auto hash : moreHashes)
+ mayContainCount += filter.mayContain(hash) ? 1 : 0;
+ // False positive rate is ~0.000004% so this should always be true.
+ EXPECT_TRUE(mayContainCount < hashCount / 10);
+
+ for (auto hash : moreHashes)
+ filter.add(hash);
+
+ for (auto hash : hashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+ for (auto hash : moreHashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+}
+
+TEST(WTF_BloomFilter, BasicCounting)
+{
+ const unsigned hashCount = 1000;
+ auto hashes = generateRandomHashes(hashCount);
+
+ CountingBloomFilter<16> filter;
+ for (auto hash : hashes)
+ filter.add(hash);
+
+ for (auto hash : hashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+
+ for (auto hash : hashes)
+ filter.add(hash);
+
+ for (auto hash : hashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+
+ for (auto hash : hashes)
+ filter.remove(hash);
+
+ for (auto hash : hashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+
+ auto moreHashes = generateRandomHashes(hashCount);
+ unsigned mayContainCount = 0;
+ for (auto hash : moreHashes)
+ mayContainCount += filter.mayContain(hash) ? 1 : 0;
+ // False positive rate is ~0.09% so this should always be true.
+ EXPECT_TRUE(mayContainCount < hashCount / 10);
+
+ for (auto hash : moreHashes)
+ filter.add(hash);
+ for (auto hash : hashes)
+ filter.remove(hash);
+
+ for (auto hash : moreHashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+
+ for (auto hash : moreHashes)
+ filter.remove(hash);
+
+ for (auto hash : hashes)
+ EXPECT_TRUE(!filter.mayContain(hash));
+ for (auto hash : moreHashes)
+ EXPECT_TRUE(!filter.mayContain(hash));
+}
+
+TEST(WTF_BloomFilter, Clear)
+{
+ const unsigned hashCount = 1000;
+ auto hashes = generateRandomHashes(hashCount);
+
+ BloomFilter<16> filter;
+ for (auto hash : hashes)
+ filter.add(hash);
+
+ filter.clear();
+
+ for (auto hash : hashes)
+ EXPECT_TRUE(!filter.mayContain(hash));
+}
+
+TEST(WTF_BloomFilter, ClearCounting)
+{
+ const unsigned hashCount = 1000;
+ auto hashes = generateRandomHashes(hashCount);
+
+ CountingBloomFilter<16> filter;
+ for (auto hash : hashes)
+ filter.add(hash);
+ for (auto hash : hashes)
+ filter.add(hash);
+
+ filter.clear();
+
+ for (auto hash : hashes)
+ EXPECT_TRUE(!filter.mayContain(hash));
+}
+
+TEST(WTF_BloomFilter, CountingOverflow)
+{
+ const unsigned hashCount = 1000;
+ auto hashes = generateRandomHashes(hashCount);
+
+ CountingBloomFilter<16> filter;
+ for (auto hash : hashes)
+ filter.add(hash);
+
+ for (unsigned i = 0; i < filter.maximumCount() + 100; ++i)
+ filter.add(hashes[0]);
+
+ for (auto hash : hashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+
+ for (auto hash : hashes)
+ filter.remove(hash);
+
+ unsigned mayContainCount = 0;
+ for (auto hash : hashes) {
+ if (hash == hashes[0])
+ EXPECT_TRUE(filter.mayContain(hash));
+ else
+ mayContainCount += filter.mayContain(hash) ? 1 : 0;
+ }
+ // False positive rate should be very low.
+ EXPECT_TRUE(mayContainCount < hashCount / 100);
+
+ for (unsigned i = 0; i < filter.maximumCount() + 100; ++i)
+ filter.remove(hashes[0]);
+
+ // The bucket has overflowed and is stuck.
+ EXPECT_TRUE(filter.mayContain(hashes[0]));
+}
+
+TEST(WTF_BloomFilter, Combine)
+{
+ const unsigned hashCount = 1000;
+ auto hashes = generateRandomHashes(hashCount);
+
+ BloomFilter<16> filter;
+ for (auto hash : hashes)
+ filter.add(hash);
+
+ auto moreHashes = generateRandomHashes(hashCount);
+
+ BloomFilter<16> anotherFilter;
+ for (auto hash : moreHashes)
+ anotherFilter.add(hash);
+
+ filter.add(anotherFilter);
+
+ for (auto hash : hashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+ for (auto hash : moreHashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+}
+
+}
diff --git a/Tools/TestWebKitAPI/Tests/WTF/CheckedArithmeticOperations.cpp b/Tools/TestWebKitAPI/Tests/WTF/CheckedArithmeticOperations.cpp
index 77b8ff458..d6b548316 100644
--- a/Tools/TestWebKitAPI/Tests/WTF/CheckedArithmeticOperations.cpp
+++ b/Tools/TestWebKitAPI/Tests/WTF/CheckedArithmeticOperations.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,117 +28,397 @@
namespace TestWebKitAPI {
-#define CheckedArithmeticTest(type, coerceLiteral, MixedSignednessTest) \
+class OverflowCrashLogger {
+protected:
+ void overflowed()
+ {
+ m_overflowCount++;
+ }
+
+ void clearOverflow()
+ {
+ m_overflowCount = 0;
+ }
+
+ static void crash()
+ {
+ s_didCrash = true;
+ }
+
+public:
+ void reset()
+ {
+ m_overflowCount = 0;
+ s_didCrash = false;
+ }
+
+ bool hasOverflowed() const { return m_overflowCount > 0; }
+ int overflowCount() const { return m_overflowCount; }
+
+ bool didCrash() const { return s_didCrash; }
+
+private:
+ int m_overflowCount { 0 };
+ static bool s_didCrash;
+};
+
+bool OverflowCrashLogger::s_didCrash = false;
+
+template <typename type>
+static void resetOverflow(Checked<type, OverflowCrashLogger>& value)
+{
+ value.reset();
+ value = 100;
+ value *= std::numeric_limits<type>::max();
+}
+
+#define CheckedArithmeticTest(type, Coercer, MixedSignednessTester) \
TEST(WTF, Checked_##type) \
{ \
- Checked<type, RecordOverflow> value; \
- EXPECT_EQ(coerceLiteral(0), value.unsafeGet()); \
- EXPECT_EQ(std::numeric_limits<type>::max(), (value + std::numeric_limits<type>::max()).unsafeGet()); \
- EXPECT_EQ(std::numeric_limits<type>::max(), (std::numeric_limits<type>::max() + value).unsafeGet()); \
- EXPECT_EQ(std::numeric_limits<type>::min(), (value + std::numeric_limits<type>::min()).unsafeGet()); \
- EXPECT_EQ(std::numeric_limits<type>::min(), (std::numeric_limits<type>::min() + value).unsafeGet()); \
- EXPECT_EQ(coerceLiteral(0), (value * coerceLiteral(0)).unsafeGet()); \
- EXPECT_EQ(coerceLiteral(0), (coerceLiteral(0) * value).unsafeGet()); \
- EXPECT_EQ(coerceLiteral(0), (value * value).unsafeGet()); \
- EXPECT_EQ(coerceLiteral(0), (value - coerceLiteral(0)).unsafeGet()); \
- EXPECT_EQ(coerceLiteral(0), (coerceLiteral(0) - value).unsafeGet()); \
- EXPECT_EQ(coerceLiteral(0), (value - value).unsafeGet()); \
- EXPECT_EQ(coerceLiteral(0), (value++).unsafeGet()); \
- EXPECT_EQ(coerceLiteral(1), (value--).unsafeGet()); \
- EXPECT_EQ(coerceLiteral(1), (++value).unsafeGet()); \
- EXPECT_EQ(coerceLiteral(0), (--value).unsafeGet()); \
- EXPECT_EQ(coerceLiteral(10), (value += coerceLiteral(10)).unsafeGet()); \
- EXPECT_EQ(coerceLiteral(10), value.unsafeGet()); \
- EXPECT_EQ(coerceLiteral(100), (value *= coerceLiteral(10)).unsafeGet()); \
- EXPECT_EQ(coerceLiteral(100), value.unsafeGet()); \
- EXPECT_EQ(coerceLiteral(0), (value -= coerceLiteral(100)).unsafeGet()); \
- EXPECT_EQ(coerceLiteral(0), value.unsafeGet()); \
- value = 10; \
- EXPECT_EQ(coerceLiteral(10), value.unsafeGet()); \
- EXPECT_EQ(coerceLiteral(0), (value - coerceLiteral(10)).unsafeGet()); \
- EXPECT_EQ(coerceLiteral(10), value.unsafeGet()); \
- value = std::numeric_limits<type>::min(); \
- EXPECT_EQ(true, (Checked<type, RecordOverflow>(value - coerceLiteral(1))).hasOverflowed()); \
- EXPECT_EQ(true, !((value--).hasOverflowed())); \
- EXPECT_EQ(true, value.hasOverflowed()); \
- value = std::numeric_limits<type>::max(); \
- EXPECT_EQ(true, !value.hasOverflowed()); \
- EXPECT_EQ(true, (Checked<type, RecordOverflow>(value + coerceLiteral(1))).hasOverflowed()); \
- EXPECT_EQ(true, !(value++).hasOverflowed()); \
- EXPECT_EQ(true, value.hasOverflowed()); \
- value = std::numeric_limits<type>::max(); \
- EXPECT_EQ(true, (value += coerceLiteral(1)).hasOverflowed()); \
- EXPECT_EQ(true, value.hasOverflowed()); \
- value = 10; \
- type _value = 0; \
- EXPECT_EQ(true, CheckedState::DidNotOverflow == (value * Checked<type, RecordOverflow>(0)).safeGet(_value)); \
- _value = 0; \
- EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked<type, RecordOverflow>(0) * value).safeGet(_value)); \
- _value = 0; \
- EXPECT_EQ(true, CheckedState::DidOverflow == (value * Checked<type, RecordOverflow>(std::numeric_limits<type>::max())).safeGet(_value)); \
- _value = 0; \
- EXPECT_EQ(true, CheckedState::DidOverflow == (Checked<type, RecordOverflow>(std::numeric_limits<type>::max()) * value).safeGet(_value)); \
- value = 0; \
- _value = 0; \
- EXPECT_EQ(true, CheckedState::DidNotOverflow == (value * Checked<type, RecordOverflow>(std::numeric_limits<type>::max())).safeGet(_value)); \
- _value = 0; \
- EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked<type, RecordOverflow>(std::numeric_limits<type>::max()) * value).safeGet(_value)); \
- value = 1; \
- _value = 0; \
- EXPECT_EQ(true, CheckedState::DidNotOverflow == (value * Checked<type, RecordOverflow>(std::numeric_limits<type>::max())).safeGet(_value)); \
- _value = 0; \
- EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked<type, RecordOverflow>(std::numeric_limits<type>::max()) * value).safeGet(_value)); \
- _value = 0; \
- value = 0; \
- EXPECT_EQ(true, CheckedState::DidNotOverflow == (value * Checked<type, RecordOverflow>(std::numeric_limits<type>::max())).safeGet(_value)); \
- _value = 0; \
- EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked<type, RecordOverflow>(std::numeric_limits<type>::max()) * (type)0).safeGet(_value)); \
- _value = 0; \
- value = 1; \
- EXPECT_EQ(true, CheckedState::DidNotOverflow == (value * Checked<type, RecordOverflow>(std::numeric_limits<type>::max())).safeGet(_value)); \
- _value = 0; \
- EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked<type, RecordOverflow>(std::numeric_limits<type>::max()) * (type)1).safeGet(_value)); \
- _value = 0; \
- value = 2; \
- EXPECT_EQ(true, CheckedState::DidOverflow == (value * Checked<type, RecordOverflow>(std::numeric_limits<type>::max())).safeGet(_value)); \
- _value = 0; \
- EXPECT_EQ(true, CheckedState::DidOverflow == (Checked<type, RecordOverflow>(std::numeric_limits<type>::max()) * (type)2).safeGet(_value)); \
- value = 10; \
- EXPECT_EQ(true, (value * Checked<type, RecordOverflow>(std::numeric_limits<type>::max())).hasOverflowed()); \
- MixedSignednessTest(EXPECT_EQ(coerceLiteral(0), (value + -10).unsafeGet())); \
- MixedSignednessTest(EXPECT_EQ(0U, (value - 10U).unsafeGet())); \
- MixedSignednessTest(EXPECT_EQ(coerceLiteral(0), (-10 + value).unsafeGet())); \
- MixedSignednessTest(EXPECT_EQ(0U, (10U - value).unsafeGet())); \
- value = std::numeric_limits<type>::min(); \
- MixedSignednessTest(EXPECT_EQ(true, (Checked<type, RecordOverflow>(value - 1)).hasOverflowed())); \
- MixedSignednessTest(EXPECT_EQ(true, !(value--).hasOverflowed())); \
- MixedSignednessTest(EXPECT_EQ(true, value.hasOverflowed())); \
- value = std::numeric_limits<type>::max(); \
- MixedSignednessTest(EXPECT_EQ(true, !value.hasOverflowed())); \
- MixedSignednessTest(EXPECT_EQ(true, (Checked<type, RecordOverflow>(value + 1)).hasOverflowed())); \
- MixedSignednessTest(EXPECT_EQ(true, !(value++).hasOverflowed())); \
- MixedSignednessTest(EXPECT_EQ(true, value.hasOverflowed())); \
- value = std::numeric_limits<type>::max(); \
- MixedSignednessTest(EXPECT_EQ(true, (value += 1).hasOverflowed())); \
- MixedSignednessTest(EXPECT_EQ(true, value.hasOverflowed())); \
- value = std::numeric_limits<type>::min(); \
- MixedSignednessTest(EXPECT_EQ(true, (value - 1U).hasOverflowed())); \
- MixedSignednessTest(EXPECT_EQ(true, !(value--).hasOverflowed())); \
- MixedSignednessTest(EXPECT_EQ(true, value.hasOverflowed())); \
- value = std::numeric_limits<type>::max(); \
- MixedSignednessTest(EXPECT_EQ(true, !value.hasOverflowed())); \
- MixedSignednessTest(EXPECT_EQ(true, (Checked<type, RecordOverflow>(value + 1U)).hasOverflowed())); \
- MixedSignednessTest(EXPECT_EQ(true, !(value++).hasOverflowed())); \
- MixedSignednessTest(EXPECT_EQ(true, value.hasOverflowed())); \
- value = std::numeric_limits<type>::max(); \
- MixedSignednessTest(EXPECT_EQ(true, (value += 1U).hasOverflowed())); \
- MixedSignednessTest(EXPECT_EQ(true, value.hasOverflowed())); \
+ typedef Coercer<type> CoercerType; \
+ typedef MixedSignednessTester<type, CoercerType> MixedSignednessTesterType; \
+ CheckedArithmeticTester<type, CoercerType, MixedSignednessTesterType>::run(); \
}
+
+#define coerceLiteral(x) Coercer::coerce(x)
+
+template <typename type, typename Coercer, typename MixedSignednessTester>
+class CheckedArithmeticTester {
+public:
+ static void run()
+ {
+ Checked<type, RecordOverflow> value;
+ EXPECT_EQ(coerceLiteral(0), value.unsafeGet());
+ EXPECT_EQ(std::numeric_limits<type>::max(), (value + std::numeric_limits<type>::max()).unsafeGet());
+ EXPECT_EQ(std::numeric_limits<type>::max(), (std::numeric_limits<type>::max() + value).unsafeGet());
+ EXPECT_EQ(std::numeric_limits<type>::min(), (value + std::numeric_limits<type>::min()).unsafeGet());
+ EXPECT_EQ(std::numeric_limits<type>::min(), (std::numeric_limits<type>::min() + value).unsafeGet());
+
+ EXPECT_EQ(coerceLiteral(0), (value * coerceLiteral(0)).unsafeGet());
+ EXPECT_EQ(coerceLiteral(0), (coerceLiteral(0) * value).unsafeGet());
+ EXPECT_EQ(coerceLiteral(0), (value * value).unsafeGet());
+ EXPECT_EQ(coerceLiteral(0), (value - coerceLiteral(0)).unsafeGet());
+ EXPECT_EQ(coerceLiteral(0), (coerceLiteral(0) - value).unsafeGet());
+ EXPECT_EQ(coerceLiteral(0), (value - value).unsafeGet());
+ EXPECT_EQ(coerceLiteral(0), (value++).unsafeGet());
+ EXPECT_EQ(coerceLiteral(1), (value--).unsafeGet());
+ EXPECT_EQ(coerceLiteral(1), (++value).unsafeGet());
+ EXPECT_EQ(coerceLiteral(0), (--value).unsafeGet());
+ EXPECT_EQ(coerceLiteral(10), (value += coerceLiteral(10)).unsafeGet());
+ EXPECT_EQ(coerceLiteral(10), value.unsafeGet());
+ EXPECT_EQ(coerceLiteral(100), (value *= coerceLiteral(10)).unsafeGet());
+ EXPECT_EQ(coerceLiteral(100), value.unsafeGet());
+ EXPECT_EQ(coerceLiteral(0), (value -= coerceLiteral(100)).unsafeGet());
+ EXPECT_EQ(coerceLiteral(0), value.unsafeGet());
+ value = 10;
+ EXPECT_EQ(coerceLiteral(10), value.unsafeGet());
+ EXPECT_EQ(coerceLiteral(0), (value - coerceLiteral(10)).unsafeGet());
+ EXPECT_EQ(coerceLiteral(10), value.unsafeGet());
+
+ value = std::numeric_limits<type>::min();
+ EXPECT_EQ(true, (Checked<type, RecordOverflow>(value - coerceLiteral(1))).hasOverflowed());
+ EXPECT_EQ(true, !((value--).hasOverflowed()));
+ EXPECT_EQ(true, value.hasOverflowed());
+ value = std::numeric_limits<type>::max();
+ EXPECT_EQ(true, !value.hasOverflowed());
+ EXPECT_EQ(true, (Checked<type, RecordOverflow>(value + coerceLiteral(1))).hasOverflowed());
+ EXPECT_EQ(true, !(value++).hasOverflowed());
+ EXPECT_EQ(true, value.hasOverflowed());
+ value = std::numeric_limits<type>::max();
+ EXPECT_EQ(true, (value += coerceLiteral(1)).hasOverflowed());
+ EXPECT_EQ(true, value.hasOverflowed());
+
+ value = 10;
+ type _value = 0;
+ EXPECT_EQ(true, CheckedState::DidNotOverflow == (value * Checked<type, RecordOverflow>(0)).safeGet(_value));
+ _value = 0;
+ EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked<type, RecordOverflow>(0) * value).safeGet(_value));
+ _value = 0;
+ EXPECT_EQ(true, CheckedState::DidOverflow == (value * Checked<type, RecordOverflow>(std::numeric_limits<type>::max())).safeGet(_value));
+ _value = 0;
+ EXPECT_EQ(true, CheckedState::DidOverflow == (Checked<type, RecordOverflow>(std::numeric_limits<type>::max()) * value).safeGet(_value));
+ value = 0;
+ _value = 0;
+ EXPECT_EQ(true, CheckedState::DidNotOverflow == (value * Checked<type, RecordOverflow>(std::numeric_limits<type>::max())).safeGet(_value));
+ _value = 0;
+ EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked<type, RecordOverflow>(std::numeric_limits<type>::max()) * value).safeGet(_value));
+ value = 1;
+ _value = 0;
+ EXPECT_EQ(true, CheckedState::DidNotOverflow == (value * Checked<type, RecordOverflow>(std::numeric_limits<type>::max())).safeGet(_value));
+ _value = 0;
+ EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked<type, RecordOverflow>(std::numeric_limits<type>::max()) * value).safeGet(_value));
+ _value = 0;
+ value = 0;
+ EXPECT_EQ(true, CheckedState::DidNotOverflow == (value * Checked<type, RecordOverflow>(std::numeric_limits<type>::max())).safeGet(_value));
+ _value = 0;
+ EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked<type, RecordOverflow>(std::numeric_limits<type>::max()) * (type)0).safeGet(_value));
+ _value = 0;
+ value = 1;
+ EXPECT_EQ(true, CheckedState::DidNotOverflow == (value * Checked<type, RecordOverflow>(std::numeric_limits<type>::max())).safeGet(_value));
+ _value = 0;
+ EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked<type, RecordOverflow>(std::numeric_limits<type>::max()) * (type)1).safeGet(_value));
+ _value = 0;
+ value = 2;
+ EXPECT_EQ(true, CheckedState::DidOverflow == (value * Checked<type, RecordOverflow>(std::numeric_limits<type>::max())).safeGet(_value));
+ _value = 0;
+ EXPECT_EQ(true, CheckedState::DidOverflow == (Checked<type, RecordOverflow>(std::numeric_limits<type>::max()) * (type)2).safeGet(_value));
+ value = 10;
+ EXPECT_EQ(true, (value * Checked<type, RecordOverflow>(std::numeric_limits<type>::max())).hasOverflowed());
+
+
+ Checked<type, OverflowCrashLogger> nvalue; // to hold a not overflowed value.
+ Checked<type, OverflowCrashLogger> ovalue; // to hold an overflowed value.
+ bool unused;
+
+ _value = 75;
+ type _largeValue = 100;
+ type _smallValue = 50;
+
+ value = _smallValue;
+ nvalue = _value;
+ ovalue = _value;
+
+ // Make sure the OverflowCrashLogger is working as expected.
+ EXPECT_EQ(false, (ovalue.hasOverflowed()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), ovalue.hasOverflowed()));
+ EXPECT_EQ(false, (resetOverflow(ovalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (unused = (ovalue == ovalue), ovalue.didCrash()));
+ EXPECT_EQ(false, (resetOverflow(ovalue), ovalue.didCrash()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+ EXPECT_EQ(false, nvalue.didCrash());
+
+ // Test operator== that should not overflow nor crash.
+ EXPECT_EQ(true, (nvalue == nvalue));
+ EXPECT_EQ(true, (nvalue == Checked<type, OverflowCrashLogger>(_value)));
+ EXPECT_EQ(false, (nvalue == value));
+ EXPECT_EQ(true, (nvalue == _value));
+ EXPECT_EQ(false, (nvalue == Checked<type, OverflowCrashLogger>(std::numeric_limits<type>::max())));
+ EXPECT_EQ(false, (nvalue == std::numeric_limits<type>::max()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+ EXPECT_EQ(false, nvalue.didCrash());
+
+ // Test operator!= that should not overflow nor crash.
+ EXPECT_EQ(false, (nvalue != nvalue));
+ EXPECT_EQ(false, (nvalue != Checked<type, OverflowCrashLogger>(_value)));
+ EXPECT_EQ(true, (nvalue != value));
+ EXPECT_EQ(false, (nvalue != _value));
+ EXPECT_EQ(true, (nvalue != Checked<type, OverflowCrashLogger>(std::numeric_limits<type>::max())));
+ EXPECT_EQ(true, (nvalue != std::numeric_limits<type>::max()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+ EXPECT_EQ(false, nvalue.didCrash());
+
+ // Test operator< that should not overflow nor crash.
+ EXPECT_EQ(false, (nvalue < nvalue));
+ EXPECT_EQ(false, (nvalue < value));
+ EXPECT_EQ(true, (nvalue < Checked<type, OverflowCrashLogger>(_largeValue)));
+ EXPECT_EQ(false, (nvalue < Checked<type, OverflowCrashLogger>(_value)));
+ EXPECT_EQ(false, (nvalue < Checked<type, OverflowCrashLogger>(_smallValue)));
+ EXPECT_EQ(true, (nvalue < _largeValue));
+ EXPECT_EQ(false, (nvalue < _value));
+ EXPECT_EQ(false, (nvalue < _smallValue));
+ EXPECT_EQ(true, (nvalue < Checked<type, OverflowCrashLogger>(std::numeric_limits<type>::max())));
+ EXPECT_EQ(true, (nvalue < std::numeric_limits<type>::max()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+ EXPECT_EQ(false, nvalue.didCrash());
+
+ // Test operator<= that should not overflow nor crash.
+ EXPECT_EQ(true, (nvalue <= nvalue));
+ EXPECT_EQ(false, (nvalue <= value));
+ EXPECT_EQ(true, (nvalue <= Checked<type, OverflowCrashLogger>(_largeValue)));
+ EXPECT_EQ(true, (nvalue <= Checked<type, OverflowCrashLogger>(_value)));
+ EXPECT_EQ(false, (nvalue <= Checked<type, OverflowCrashLogger>(_smallValue)));
+ EXPECT_EQ(true, (nvalue <= _largeValue));
+ EXPECT_EQ(true, (nvalue <= _value));
+ EXPECT_EQ(false, (nvalue <= _smallValue));
+ EXPECT_EQ(true, (nvalue <= Checked<type, OverflowCrashLogger>(std::numeric_limits<type>::max())));
+ EXPECT_EQ(true, (nvalue <= std::numeric_limits<type>::max()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+ EXPECT_EQ(false, nvalue.didCrash());
+
+ // Test operator> that should not overflow nor crash.
+ EXPECT_EQ(false, (nvalue > nvalue));
+ EXPECT_EQ(true, (nvalue > value));
+ EXPECT_EQ(false, (nvalue > Checked<type, OverflowCrashLogger>(_largeValue)));
+ EXPECT_EQ(false, (nvalue > Checked<type, OverflowCrashLogger>(_value)));
+ EXPECT_EQ(true, (nvalue > Checked<type, OverflowCrashLogger>(_smallValue)));
+ EXPECT_EQ(false, (nvalue > _largeValue));
+ EXPECT_EQ(false, (nvalue > _value));
+ EXPECT_EQ(true, (nvalue > _smallValue));
+ EXPECT_EQ(false, (nvalue > Checked<type, OverflowCrashLogger>(std::numeric_limits<type>::max())));
+ EXPECT_EQ(false, (nvalue > std::numeric_limits<type>::max()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+ EXPECT_EQ(false, nvalue.didCrash());
+
+ // Test operator>= that should not overflow nor crash.
+ EXPECT_EQ(true, (nvalue >= nvalue));
+ EXPECT_EQ(true, (nvalue >= value));
+ EXPECT_EQ(false, (nvalue >= Checked<type, OverflowCrashLogger>(_largeValue)));
+ EXPECT_EQ(true, (nvalue >= Checked<type, OverflowCrashLogger>(_value)));
+ EXPECT_EQ(true, (nvalue >= Checked<type, OverflowCrashLogger>(_smallValue)));
+ EXPECT_EQ(false, (nvalue >= _largeValue));
+ EXPECT_EQ(true, (nvalue >= _value));
+ EXPECT_EQ(true, (nvalue >= _smallValue));
+ EXPECT_EQ(false, (nvalue >= Checked<type, OverflowCrashLogger>(std::numeric_limits<type>::max())));
+ EXPECT_EQ(false, (nvalue >= std::numeric_limits<type>::max()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+ EXPECT_EQ(false, nvalue.didCrash());
+
+ // Test operator== with an overflowed value.
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue == ovalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue == Checked<type, OverflowCrashLogger>(_value)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue == value), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue == _value), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue == _value * std::numeric_limits<type>::max()), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue == Checked<type, OverflowCrashLogger>(std::numeric_limits<type>::max())), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue == std::numeric_limits<type>::max()), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue == nvalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (nvalue == ovalue), ovalue.didCrash()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+
+ // Test operator!= with an overflowed value.
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue != ovalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue != Checked<type, OverflowCrashLogger>(_value)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue != value), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue != _value), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue != _value * std::numeric_limits<type>::max()), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue != Checked<type, OverflowCrashLogger>(std::numeric_limits<type>::max())), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue != std::numeric_limits<type>::max()), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue != nvalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (nvalue != ovalue), ovalue.didCrash()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+
+ // Test operator< with an overflowed value.
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < ovalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < value), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < Checked<type, OverflowCrashLogger>(_largeValue)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < Checked<type, OverflowCrashLogger>(_value)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < Checked<type, OverflowCrashLogger>(_smallValue)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < _largeValue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < _value), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < _smallValue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < Checked<type, OverflowCrashLogger>(std::numeric_limits<type>::max())), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < std::numeric_limits<type>::max()), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < nvalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (nvalue < ovalue), ovalue.didCrash()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+
+ // Test operator<= with an overflowed value.
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= ovalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= value), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= Checked<type, OverflowCrashLogger>(_largeValue)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= Checked<type, OverflowCrashLogger>(_value)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= Checked<type, OverflowCrashLogger>(_smallValue)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= _largeValue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= _value), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= _smallValue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= Checked<type, OverflowCrashLogger>(std::numeric_limits<type>::max())), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= std::numeric_limits<type>::max()), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= nvalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (nvalue <= ovalue), ovalue.didCrash()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+
+ // Test operator> with an overflowed value.
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > ovalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > value), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > Checked<type, OverflowCrashLogger>(_largeValue)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > Checked<type, OverflowCrashLogger>(_value)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > Checked<type, OverflowCrashLogger>(_smallValue)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > _largeValue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > _value), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > _smallValue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > Checked<type, OverflowCrashLogger>(std::numeric_limits<type>::max())), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > std::numeric_limits<type>::max()), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > nvalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (nvalue > ovalue), ovalue.didCrash()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+
+ // Test operator>= with an overflowed value.
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= ovalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= value), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= Checked<type, OverflowCrashLogger>(_largeValue)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= Checked<type, OverflowCrashLogger>(_value)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= Checked<type, OverflowCrashLogger>(_smallValue)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= _largeValue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= _value), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= _smallValue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= Checked<type, OverflowCrashLogger>(std::numeric_limits<type>::max())), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= std::numeric_limits<type>::max()), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= nvalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (nvalue >= ovalue), ovalue.didCrash()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+
+ MixedSignednessTester::run();
+ }
+};
+
+template <typename type, typename Coercer>
+class AllowMixedSignednessTest {
+public:
+ static void run()
+ {
+ Checked<type, RecordOverflow> value;
+ value = 10;
+
+ EXPECT_EQ(coerceLiteral(0), (value + -10).unsafeGet());
+ EXPECT_EQ(0U, (value - 10U).unsafeGet());
+ EXPECT_EQ(coerceLiteral(0), (-10 + value).unsafeGet());
+ EXPECT_EQ(0U, (10U - value).unsafeGet());
+ value = std::numeric_limits<type>::min();
+ EXPECT_EQ(true, (Checked<type, RecordOverflow>(value - 1)).hasOverflowed());
+ EXPECT_EQ(true, !(value--).hasOverflowed());
+ EXPECT_EQ(true, value.hasOverflowed());
+ value = std::numeric_limits<type>::max();
+ EXPECT_EQ(true, !value.hasOverflowed());
+ EXPECT_EQ(true, (Checked<type, RecordOverflow>(value + 1)).hasOverflowed());
+ EXPECT_EQ(true, !(value++).hasOverflowed());
+ EXPECT_EQ(true, value.hasOverflowed());
+ value = std::numeric_limits<type>::max();
+ EXPECT_EQ(true, (value += 1).hasOverflowed());
+ EXPECT_EQ(true, value.hasOverflowed());
+ value = std::numeric_limits<type>::min();
+ EXPECT_EQ(true, (value - 1U).hasOverflowed());
+ EXPECT_EQ(true, !(value--).hasOverflowed());
+ EXPECT_EQ(true, value.hasOverflowed());
+ value = std::numeric_limits<type>::max();
+ EXPECT_EQ(true, !value.hasOverflowed());
+ EXPECT_EQ(true, (Checked<type, RecordOverflow>(value + 1U)).hasOverflowed());
+ EXPECT_EQ(true, !(value++).hasOverflowed());
+ EXPECT_EQ(true, value.hasOverflowed());
+ value = std::numeric_limits<type>::max();
+ EXPECT_EQ(true, (value += 1U).hasOverflowed());
+ EXPECT_EQ(true, value.hasOverflowed());
+ }
+};
+
+template <typename type, typename Coercer>
+class IgnoreMixedSignednessTest {
+public:
+ static void run() { }
+};
+
+template <typename type> class CoerceLiteralToUnsigned {
+public:
+ static unsigned coerce(type x) { return static_cast<unsigned>(x); }
+};
+
+template <typename type> class CoerceLiteralNop {
+public:
+ static type coerce(type x) { return x; }
+};
-#define CoerceLiteralToUnsigned(x) x##U
-#define CoerceLiteralNop(x) x
-#define AllowMixedSignednessTest(x) x
-#define IgnoreMixedSignednessTest(x)
CheckedArithmeticTest(int8_t, CoerceLiteralNop, IgnoreMixedSignednessTest)
CheckedArithmeticTest(int16_t, CoerceLiteralNop, IgnoreMixedSignednessTest)
CheckedArithmeticTest(int32_t, CoerceLiteralNop, AllowMixedSignednessTest)
@@ -146,4 +426,62 @@ CheckedArithmeticTest(uint32_t, CoerceLiteralToUnsigned, AllowMixedSignednessTes
CheckedArithmeticTest(int64_t, CoerceLiteralNop, IgnoreMixedSignednessTest)
CheckedArithmeticTest(uint64_t, CoerceLiteralToUnsigned, IgnoreMixedSignednessTest)
+TEST(CheckedArithmeticTest, IsInBounds)
+{
+ // bigger precision, signed, signed
+ EXPECT_TRUE(WTF::isInBounds<int32_t>(std::numeric_limits<int16_t>::max()));
+ EXPECT_TRUE(WTF::isInBounds<int32_t>(std::numeric_limits<int16_t>::min()));
+
+ // bigger precision, unsigned, signed
+ EXPECT_TRUE(WTF::isInBounds<uint32_t>(std::numeric_limits<int32_t>::max()));
+ EXPECT_FALSE(WTF::isInBounds<uint32_t>(std::numeric_limits<int16_t>::min()));
+
+ EXPECT_FALSE(WTF::isInBounds<uint32_t>((int32_t)-1));
+ EXPECT_FALSE(WTF::isInBounds<uint16_t>((int32_t)-1));
+ EXPECT_FALSE(WTF::isInBounds<unsigned long>((int)-1));
+
+ EXPECT_TRUE(WTF::isInBounds<uint32_t>((int32_t)1));
+ EXPECT_TRUE(WTF::isInBounds<uint32_t>((int16_t)1));
+ EXPECT_TRUE(WTF::isInBounds<unsigned>((int)1));
+
+ EXPECT_TRUE(WTF::isInBounds<uint32_t>((int32_t)0));
+ EXPECT_TRUE(WTF::isInBounds<uint16_t>((int32_t)0));
+ EXPECT_TRUE(WTF::isInBounds<uint32_t>((int16_t)0));
+ EXPECT_TRUE(WTF::isInBounds<unsigned>((int)0));
+
+ EXPECT_TRUE(WTF::isInBounds<uint32_t>(std::numeric_limits<int32_t>::max()));
+ EXPECT_TRUE(WTF::isInBounds<uint32_t>(std::numeric_limits<int16_t>::max()));
+ EXPECT_TRUE(WTF::isInBounds<unsigned>(std::numeric_limits<int>::max()));
+
+ // bigger precision, signed, unsigned
+ EXPECT_TRUE(WTF::isInBounds<int32_t>(std::numeric_limits<uint16_t>::max()));
+ EXPECT_FALSE(WTF::isInBounds<int32_t>(std::numeric_limits<uint32_t>::max()));
+ EXPECT_TRUE(WTF::isInBounds<int32_t>((uint32_t)0));
+
+ // bigger precision, unsigned, unsigned
+ EXPECT_TRUE(WTF::isInBounds<uint32_t>(std::numeric_limits<uint16_t>::max()));
+ EXPECT_TRUE(WTF::isInBounds<uint32_t>(std::numeric_limits<uint16_t>::min()));
+
+ // lower precision, signed signed
+ EXPECT_FALSE(WTF::isInBounds<int16_t>(std::numeric_limits<int32_t>::max()));
+ EXPECT_FALSE(WTF::isInBounds<int16_t>(std::numeric_limits<int32_t>::min()));
+ EXPECT_TRUE(WTF::isInBounds<int16_t>((int32_t)-1));
+ EXPECT_TRUE(WTF::isInBounds<int16_t>((int32_t)0));
+ EXPECT_TRUE(WTF::isInBounds<int16_t>((int32_t)1));
+ // lower precision, unsigned, signed
+ EXPECT_FALSE(WTF::isInBounds<uint16_t>(std::numeric_limits<int32_t>::max()));
+ EXPECT_FALSE(WTF::isInBounds<uint16_t>(std::numeric_limits<int32_t>::min()));
+ EXPECT_FALSE(WTF::isInBounds<uint16_t>((int32_t)-1));
+ EXPECT_TRUE(WTF::isInBounds<uint16_t>((int32_t)0));
+ EXPECT_TRUE(WTF::isInBounds<uint16_t>((int32_t)1));
+ // lower precision, signed, unsigned
+ EXPECT_FALSE(WTF::isInBounds<int16_t>(std::numeric_limits<uint32_t>::max()));
+ EXPECT_TRUE(WTF::isInBounds<int16_t>((uint32_t)0));
+ EXPECT_TRUE(WTF::isInBounds<int16_t>((uint32_t)1));
+ // lower precision, unsigned, unsigned
+ EXPECT_FALSE(WTF::isInBounds<uint16_t>(std::numeric_limits<uint32_t>::max()));
+ EXPECT_TRUE(WTF::isInBounds<uint16_t>((uint32_t)0));
+ EXPECT_TRUE(WTF::isInBounds<uint16_t>((uint32_t)1));
+}
+
} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/Condition.cpp b/Tools/TestWebKitAPI/Tests/WTF/Condition.cpp
new file mode 100644
index 000000000..848527351
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/Condition.cpp
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include <mutex>
+#include <thread>
+#include <wtf/Condition.h>
+#include <wtf/DataLog.h>
+#include <wtf/Deque.h>
+#include <wtf/Lock.h>
+#include <wtf/StringPrintStream.h>
+#include <wtf/Threading.h>
+#include <wtf/Vector.h>
+
+using namespace WTF;
+
+namespace TestWebKitAPI {
+
+namespace {
+
+const bool verbose = false;
+
+enum NotifyStyle {
+ AlwaysNotifyOne,
+ TacticallyNotifyAll
+};
+
+template<typename Functor>
+void wait(Condition& condition, std::unique_lock<Lock>& locker, const Functor& predicate, Seconds timeout)
+{
+ if (timeout == Seconds::infinity())
+ condition.wait(locker, predicate);
+ else {
+ // This tests timeouts in the sense that it verifies that we can call wait() again after a
+ // timeout happened. That's a non-trivial piece of functionality since upon timeout the
+ // ParkingLot has to remove us from the queue.
+ while (!predicate())
+ condition.waitFor(locker, timeout, predicate);
+ }
+}
+
+void notify(NotifyStyle notifyStyle, Condition& condition, bool shouldNotify)
+{
+ switch (notifyStyle) {
+ case AlwaysNotifyOne:
+ condition.notifyOne();
+ break;
+ case TacticallyNotifyAll:
+ if (shouldNotify)
+ condition.notifyAll();
+ break;
+ }
+}
+
+void runTest(
+ unsigned numProducers,
+ unsigned numConsumers,
+ unsigned maxQueueSize,
+ unsigned numMessagesPerProducer,
+ NotifyStyle notifyStyle,
+ Seconds timeout = Seconds::infinity(),
+ Seconds delay = 0_s)
+{
+ Deque<unsigned> queue;
+ bool shouldContinue = true;
+ Lock lock;
+ Condition emptyCondition;
+ Condition fullCondition;
+
+ Vector<ThreadIdentifier> consumerThreads;
+ Vector<ThreadIdentifier> producerThreads;
+
+ Vector<unsigned> received;
+ Lock receivedLock;
+
+ for (unsigned i = numConsumers; i--;) {
+ ThreadIdentifier threadIdentifier = createThread(
+ "Consumer thread",
+ [&] () {
+ for (;;) {
+ unsigned result;
+ unsigned shouldNotify = false;
+ {
+ std::unique_lock<Lock> locker(lock);
+ wait(
+ emptyCondition, locker,
+ [&] () {
+ if (verbose)
+ dataLog(toString(currentThread(), ": Checking consumption predicate with shouldContinue = ", shouldContinue, ", queue.size() == ", queue.size(), "\n"));
+ return !shouldContinue || !queue.isEmpty();
+ },
+ timeout);
+ if (!shouldContinue && queue.isEmpty())
+ return;
+ shouldNotify = queue.size() == maxQueueSize;
+ result = queue.takeFirst();
+ }
+ notify(notifyStyle, fullCondition, shouldNotify);
+
+ {
+ std::lock_guard<Lock> locker(receivedLock);
+ received.append(result);
+ }
+ }
+ });
+ consumerThreads.append(threadIdentifier);
+ }
+
+ sleep(delay);
+
+ for (unsigned i = numProducers; i--;) {
+ ThreadIdentifier threadIdentifier = createThread(
+ "Producer Thread",
+ [&] () {
+ for (unsigned i = 0; i < numMessagesPerProducer; ++i) {
+ bool shouldNotify = false;
+ {
+ std::unique_lock<Lock> locker(lock);
+ wait(
+ fullCondition, locker,
+ [&] () {
+ if (verbose)
+ dataLog(toString(currentThread(), ": Checking production predicate with shouldContinue = ", shouldContinue, ", queue.size() == ", queue.size(), "\n"));
+ return queue.size() < maxQueueSize;
+ },
+ timeout);
+ shouldNotify = queue.isEmpty();
+ queue.append(i);
+ }
+ notify(notifyStyle, emptyCondition, shouldNotify);
+ }
+ });
+ producerThreads.append(threadIdentifier);
+ }
+
+ for (ThreadIdentifier threadIdentifier : producerThreads)
+ waitForThreadCompletion(threadIdentifier);
+
+ {
+ std::lock_guard<Lock> locker(lock);
+ shouldContinue = false;
+ }
+ emptyCondition.notifyAll();
+
+ for (ThreadIdentifier threadIdentifier : consumerThreads)
+ waitForThreadCompletion(threadIdentifier);
+
+ EXPECT_EQ(numProducers * numMessagesPerProducer, received.size());
+ std::sort(received.begin(), received.end());
+ for (unsigned messageIndex = 0; messageIndex < numMessagesPerProducer; ++messageIndex) {
+ for (unsigned producerIndex = 0; producerIndex < numProducers; ++producerIndex)
+ EXPECT_EQ(messageIndex, received[messageIndex * numProducers + producerIndex]);
+ }
+}
+
+} // anonymous namespace
+
+TEST(WTF_Condition, OneProducerOneConsumerOneSlot)
+{
+ runTest(1, 1, 1, 100000, TacticallyNotifyAll);
+}
+
+TEST(WTF_Condition, OneProducerOneConsumerOneSlotTimeout)
+{
+ runTest(
+ 1, 1, 1, 100000, TacticallyNotifyAll,
+ Seconds::fromMilliseconds(10),
+ Seconds(1));
+}
+
+TEST(WTF_Condition, OneProducerOneConsumerHundredSlots)
+{
+ runTest(1, 1, 100, 1000000, TacticallyNotifyAll);
+}
+
+TEST(WTF_Condition, TenProducersOneConsumerOneSlot)
+{
+ runTest(10, 1, 1, 10000, TacticallyNotifyAll);
+}
+
+TEST(WTF_Condition, TenProducersOneConsumerHundredSlotsNotifyAll)
+{
+ runTest(10, 1, 100, 10000, TacticallyNotifyAll);
+}
+
+TEST(WTF_Condition, TenProducersOneConsumerHundredSlotsNotifyOne)
+{
+ runTest(10, 1, 100, 10000, AlwaysNotifyOne);
+}
+
+TEST(WTF_Condition, OneProducerTenConsumersOneSlot)
+{
+ runTest(1, 10, 1, 10000, TacticallyNotifyAll);
+}
+
+TEST(WTF_Condition, OneProducerTenConsumersHundredSlotsNotifyAll)
+{
+ runTest(1, 10, 100, 100000, TacticallyNotifyAll);
+}
+
+TEST(WTF_Condition, OneProducerTenConsumersHundredSlotsNotifyOne)
+{
+ runTest(1, 10, 100, 100000, AlwaysNotifyOne);
+}
+
+TEST(WTF_Condition, TenProducersTenConsumersOneSlot)
+{
+ runTest(10, 10, 1, 50000, TacticallyNotifyAll);
+}
+
+TEST(WTF_Condition, TenProducersTenConsumersHundredSlotsNotifyAll)
+{
+ runTest(10, 10, 100, 50000, TacticallyNotifyAll);
+}
+
+TEST(WTF_Condition, TenProducersTenConsumersHundredSlotsNotifyOne)
+{
+ runTest(10, 10, 100, 50000, AlwaysNotifyOne);
+}
+
+TEST(WTF_Condition, TimeoutTimesOut)
+{
+ Lock lock;
+ Condition condition;
+
+ lock.lock();
+ bool result = condition.waitFor(
+ lock, Seconds::fromMilliseconds(10), [] () -> bool { return false; });
+ lock.unlock();
+
+ EXPECT_FALSE(result);
+}
+
+} // namespace TestWebKitAPI
+
diff --git a/Tools/TestWebKitAPI/Tests/WTF/Consume.cpp b/Tools/TestWebKitAPI/Tests/WTF/Consume.cpp
new file mode 100644
index 000000000..e1a5d7a07
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/Consume.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <thread>
+#include <wtf/Atomics.h>
+
+template <typename T>
+NEVER_INLINE auto testConsume(const T* location)
+{
+ WTF::compilerFence(); // Paranoid testing.
+ auto ret = WTF::consumeLoad(location);
+ WTF::compilerFence(); // Paranoid testing.
+ return ret;
+}
+
+namespace TestWebKitAPI {
+
+TEST(WTF, Consumei8)
+{
+ uint8_t i8 = 42;
+ auto i8_consumed = testConsume(&i8);
+ ASSERT_EQ(i8_consumed.value, 42u);
+ ASSERT_EQ(i8_consumed.dependency, 0u);
+}
+
+TEST(WTF, Consumei16)
+{
+ uint16_t i16 = 42;
+ auto i16_consumed = testConsume(&i16);
+ ASSERT_EQ(i16_consumed.value, 42u);
+ ASSERT_EQ(i16_consumed.dependency, 0u);
+}
+
+TEST(WTF, Consumei32)
+{
+ uint32_t i32 = 42;
+ auto i32_consumed = testConsume(&i32);
+ ASSERT_EQ(i32_consumed.value, 42u);
+ ASSERT_EQ(i32_consumed.dependency, 0u);
+}
+
+TEST(WTF, Consumei64)
+{
+ uint64_t i64 = 42;
+ auto i64_consumed = testConsume(&i64);
+ ASSERT_EQ(i64_consumed.value, 42u);
+ ASSERT_EQ(i64_consumed.dependency, 0u);
+}
+
+TEST(WTF, Consumef32)
+{
+ float f32 = 42.f;
+ auto f32_consumed = testConsume(&f32);
+ ASSERT_EQ(f32_consumed.value, 42.f);
+ ASSERT_EQ(f32_consumed.dependency, 0u);
+}
+
+TEST(WTF, Consumef64)
+{
+ double f64 = 42.;
+ auto f64_consumed = testConsume(&f64);
+ ASSERT_EQ(f64_consumed.value, 42.);
+ ASSERT_EQ(f64_consumed.dependency, 0u);
+}
+
+static int* global;
+
+TEST(WTF, ConsumeGlobalPtr)
+{
+ auto* ptr = &global;
+ auto ptr_consumed = testConsume(&ptr);
+ ASSERT_EQ(ptr_consumed.value, &global);
+ ASSERT_EQ(ptr_consumed.dependency, 0u);
+}
+
+static int* globalArray[128];
+
+TEST(WTF, ConsumeGlobalArrayPtr)
+{
+ auto* ptr = &globalArray[64];
+ auto ptr_consumed = testConsume(&ptr);
+ ASSERT_EQ(ptr_consumed.value, &globalArray[64]);
+ ASSERT_EQ(ptr_consumed.dependency, 0u);
+}
+
+TEST(WTF, ConsumeStackPtr)
+{
+ char* hello = nullptr;
+ auto* stack = &hello;
+ auto stack_consumed = testConsume(&stack);
+ ASSERT_EQ(stack_consumed.value, &hello);
+ ASSERT_EQ(stack_consumed.dependency, 0u);
+}
+
+TEST(WTF, ConsumeWithThread)
+{
+ bool ready = false;
+ constexpr size_t num = 1024;
+ uint32_t* vec = new uint32_t[num];
+ std::thread t([&]() {
+ for (size_t i = 0; i != num; ++i)
+ vec[i] = i * 2;
+ WTF::storeStoreFence();
+ ready = true;
+ });
+ do {
+ auto stack_consumed = testConsume(&ready);
+ if (stack_consumed.value) {
+ for (size_t i = 0; i != num; ++i)
+ ASSERT_EQ(vec[i + stack_consumed.dependency], i * 2);
+ break;
+ }
+ } while (true);
+ t.join();
+ delete[] vec;
+}
+}
diff --git a/Tools/TestWebKitAPI/Tests/WTF/CrossThreadTask.cpp b/Tools/TestWebKitAPI/Tests/WTF/CrossThreadTask.cpp
new file mode 100644
index 000000000..52c0bcd41
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/CrossThreadTask.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <wtf/CrossThreadTask.h>
+#include <wtf/HashCountedSet.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/StringHash.h>
+
+namespace TestWebKitAPI {
+
+static size_t totalDestructorCalls;
+static size_t totalIsolatedCopyCalls;
+
+static HashCountedSet<String> defaultConstructorSet;
+static HashCountedSet<String> nameConstructorSet;
+static HashCountedSet<String> copyConstructorSet;
+static HashCountedSet<String> moveConstructorSet;
+
+struct LifetimeLogger {
+ LifetimeLogger()
+ {
+ defaultConstructorSet.add(fullName());
+ }
+
+ LifetimeLogger(const char* inputName)
+ : name(*inputName)
+ {
+ nameConstructorSet.add(fullName());
+ }
+
+ LifetimeLogger(const LifetimeLogger& other)
+ : name(other.name)
+ , copyGeneration(other.copyGeneration + 1)
+ , moveGeneration(other.moveGeneration)
+ {
+ copyConstructorSet.add(fullName());
+ }
+
+ LifetimeLogger(LifetimeLogger&& other)
+ : name(other.name)
+ , copyGeneration(other.copyGeneration)
+ , moveGeneration(other.moveGeneration + 1)
+ {
+ moveConstructorSet.add(fullName());
+ }
+
+ ~LifetimeLogger()
+ {
+ ++totalDestructorCalls;
+ }
+
+ LifetimeLogger isolatedCopy() const
+ {
+ ++totalIsolatedCopyCalls;
+ return LifetimeLogger(*this);
+ }
+
+ String fullName()
+ {
+ StringBuilder builder;
+ builder.append(&name);
+ builder.append("-");
+ builder.append(String::number(copyGeneration));
+ builder.append("-");
+ builder.append(String::number(moveGeneration));
+
+ return builder.toString();
+ }
+
+ const char& name { *"<default>" };
+ int copyGeneration { 0 };
+ int moveGeneration { 0 };
+};
+
+void testFunction(const LifetimeLogger&, const LifetimeLogger&, const LifetimeLogger&)
+{
+ // Do nothing - Just need to check the side effects of the arguments getting in here.
+}
+
+TEST(WTF_CrossThreadTask, Basic)
+{
+ {
+ LifetimeLogger logger1;
+ LifetimeLogger logger2(logger1);
+ LifetimeLogger logger3("logger");
+
+ auto task = createCrossThreadTask(testFunction, logger1, logger2, logger3);
+ task.performTask();
+ }
+
+ ASSERT_EQ(1u, defaultConstructorSet.size());
+ ASSERT_EQ(1u, defaultConstructorSet.count("<default>-0-0"));
+
+ ASSERT_EQ(1u, nameConstructorSet.size());
+ ASSERT_EQ(1u, nameConstructorSet.count("logger-0-0"));
+
+ ASSERT_EQ(3u, copyConstructorSet.size());
+ ASSERT_EQ(1u, copyConstructorSet.count("logger-1-0"));
+ ASSERT_EQ(2u, copyConstructorSet.count("<default>-1-0"));
+ ASSERT_EQ(1u, copyConstructorSet.count("<default>-2-0"));
+
+#if !COMPILER(MSVC)
+ ASSERT_EQ(6u, moveConstructorSet.size());
+#else
+ // The number of times the move constructor is called is different on Windows in this test.
+ // This seems to be caused by differences in MSVC's implementation of lambdas or std functions like std::make_tuple.
+ ASSERT_EQ(9u, moveConstructorSet.size());
+#endif
+ ASSERT_EQ(1u, moveConstructorSet.count("logger-1-1"));
+ ASSERT_EQ(1u, moveConstructorSet.count("logger-1-2"));
+ ASSERT_EQ(1u, moveConstructorSet.count("<default>-2-1"));
+ ASSERT_EQ(1u, moveConstructorSet.count("<default>-2-2"));
+ ASSERT_EQ(1u, moveConstructorSet.count("<default>-1-1"));
+ ASSERT_EQ(1u, moveConstructorSet.count("<default>-1-2"));
+
+#if !COMPILER(MSVC)
+ ASSERT_EQ(12u, totalDestructorCalls);
+#else
+ // Since the move constructor is called 3 more times on Windows (see above), we will have 3 more destructor calls.
+ ASSERT_EQ(15u, totalDestructorCalls);
+#endif
+ ASSERT_EQ(3u, totalIsolatedCopyCalls);
+
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/DateMath.cpp b/Tools/TestWebKitAPI/Tests/WTF/DateMath.cpp
new file mode 100644
index 000000000..463041d48
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/DateMath.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "Test.h"
+#include <wtf/DateMath.h>
+
+namespace TestWebKitAPI {
+
+// Note: The results of these function look weird if you do not understand the following mappings:
+// dayOfWeek: [0, 6] 0 being Monday, day: [1, 31], month: [0, 11], year: ex: 2011,
+// hours: [0, 23], minutes: [0, 59], seconds: [0, 59], utcOffset: [-720,720].
+
+TEST(WTF_DateMath, dateToDaysFrom1970)
+{
+ EXPECT_EQ(0.0, dateToDaysFrom1970(1970, 0, 1));
+ EXPECT_EQ(157.0, dateToDaysFrom1970(1970, 5, 7));
+ EXPECT_EQ(-145.0, dateToDaysFrom1970(1969, 7, 9));
+ EXPECT_EQ(16322, dateToDaysFrom1970(2014, 8, 9));
+}
+
+
+TEST(WTF_DateMath, isLeapYear)
+{
+ EXPECT_TRUE(isLeapYear(1804));
+ EXPECT_FALSE(isLeapYear(1900));
+ EXPECT_TRUE(isLeapYear(1968));
+ EXPECT_TRUE(isLeapYear(1976));
+ EXPECT_TRUE(isLeapYear(2000));
+ EXPECT_FALSE(isLeapYear(2010));
+ EXPECT_TRUE(isLeapYear(2012));
+ EXPECT_FALSE(isLeapYear(2100));
+}
+
+TEST(WTF_DateMath, msToYear)
+{
+ EXPECT_EQ(1962, msToYear(-220953600000));
+ EXPECT_EQ(1970, msToYear(0));
+ EXPECT_EQ(1970, msToYear(100));
+ EXPECT_EQ(1977, msToYear(220953600000));
+ EXPECT_EQ(2013, msToYear(1365318000000));
+}
+
+TEST(WTF_DateMath, msToDays)
+{
+ EXPECT_EQ(0, msToDays(0));
+ EXPECT_EQ(2557, msToDays(220953600000));
+ EXPECT_EQ(255, msToDays(22095360000));
+ EXPECT_EQ(25, msToDays(2209536000));
+ EXPECT_EQ(2, msToDays(220953600));
+ EXPECT_EQ(0, msToDays(22095360));
+ EXPECT_EQ(0, msToDays(2209536));
+}
+
+TEST(WTF_DateMath, msToMinutes)
+{
+ EXPECT_EQ(0, msToMinutes(0));
+ EXPECT_EQ(0, msToMinutes(220953600000));
+ EXPECT_EQ(36, msToMinutes(22095360000));
+ EXPECT_EQ(36, msToMinutes(22095360000));
+ EXPECT_EQ(45, msToMinutes(2209536000));
+ EXPECT_EQ(22, msToMinutes(220953600));
+ EXPECT_EQ(8, msToMinutes(22095360));
+ EXPECT_EQ(36, msToMinutes(2209536));
+}
+
+TEST(WTF_DateMath, msToHours)
+{
+ EXPECT_EQ(0, msToHours(0));
+ EXPECT_EQ(8, msToHours(220953600000));
+ EXPECT_EQ(17, msToHours(22095360000));
+ EXPECT_EQ(13, msToHours(2209536000));
+ EXPECT_EQ(13, msToHours(220953600));
+ EXPECT_EQ(6, msToHours(22095360));
+ EXPECT_EQ(0, msToHours(2209536));
+}
+
+TEST(WTF_DateMath, dayInYear)
+{
+ EXPECT_EQ(59, dayInYear(2015, 2, 1));
+ EXPECT_EQ(60, dayInYear(2012, 2, 1));
+ EXPECT_EQ(0, dayInYear(2015, 0, 1));
+ EXPECT_EQ(31, dayInYear(2015, 1, 1));
+}
+
+TEST(WTF_DateMath, monthFromDayInYear)
+{
+ EXPECT_EQ(2, monthFromDayInYear(59, false));
+ EXPECT_EQ(1, monthFromDayInYear(59, true));
+ EXPECT_EQ(2, monthFromDayInYear(60, true));
+ EXPECT_EQ(0, monthFromDayInYear(0, false));
+ EXPECT_EQ(0, monthFromDayInYear(0, true));
+ EXPECT_EQ(1, monthFromDayInYear(31, true));
+ EXPECT_EQ(1, monthFromDayInYear(31, false));
+}
+
+TEST(WTF_DateMath, dayInMonthFromDayInYear)
+{
+ EXPECT_EQ(1, dayInMonthFromDayInYear(0, false));
+ EXPECT_EQ(1, dayInMonthFromDayInYear(0, true));
+ EXPECT_EQ(1, dayInMonthFromDayInYear(59, false));
+ EXPECT_EQ(29, dayInMonthFromDayInYear(59, true));
+ EXPECT_EQ(1, dayInMonthFromDayInYear(60, true));
+ EXPECT_EQ(1, dayInMonthFromDayInYear(0, false));
+ EXPECT_EQ(1, dayInMonthFromDayInYear(0, true));
+ EXPECT_EQ(31, dayInMonthFromDayInYear(30, true));
+ EXPECT_EQ(31, dayInMonthFromDayInYear(30, false));
+ EXPECT_EQ(31, dayInMonthFromDayInYear(365, true));
+ EXPECT_EQ(32, dayInMonthFromDayInYear(365, false));
+ EXPECT_EQ(32, dayInMonthFromDayInYear(366, true));
+}
+
+TEST(WTF_DateMath, calculateLocalTimeOffset)
+{
+ // DST Start: April 30, 1967 (02:00 am)
+ LocalTimeOffset dstStart1967 = calculateLocalTimeOffset(-84301200000, WTF::LocalTime);
+ EXPECT_TRUE(dstStart1967.isDST);
+ EXPECT_EQ(-25200000, dstStart1967.offset);
+
+ // November 1, 1967 (02:00 am)
+ LocalTimeOffset dstAlmostEnd1967 = calculateLocalTimeOffset(-68317200000, WTF::LocalTime);
+ EXPECT_TRUE(dstAlmostEnd1967.isDST);
+ EXPECT_EQ(-25200000, dstAlmostEnd1967.offset);
+
+ // DST End: November 11, 1967 (02:00 am)
+ LocalTimeOffset dstEnd1967 = calculateLocalTimeOffset(-67536000000, WTF::LocalTime);
+ EXPECT_FALSE(dstEnd1967.isDST);
+ EXPECT_EQ(-25200000, dstStart1967.offset);
+
+ // DST Start: April 3, 1988 (02:00 am)
+ LocalTimeOffset dstStart1988 = calculateLocalTimeOffset(576054000000, WTF::LocalTime);
+ EXPECT_TRUE(dstStart1988.isDST);
+ EXPECT_EQ(-25200000, dstStart1988.offset);
+
+ // DST End: November 4, 2012 (02:00 am)
+ LocalTimeOffset dstEnd2012 = calculateLocalTimeOffset(1352012400000, WTF::LocalTime);
+ EXPECT_FALSE(dstEnd2012.isDST);
+ EXPECT_EQ(-28800000, dstEnd2012.offset);
+
+ // DST Begin: March 8, 2015
+ LocalTimeOffset dstBegin2015 = calculateLocalTimeOffset(1425801600000, WTF::LocalTime);
+ EXPECT_TRUE(dstBegin2015.isDST);
+ EXPECT_EQ(-25200000, dstBegin2015.offset);
+
+ LocalTimeOffset dstBegin2015UTC = calculateLocalTimeOffset(1425801600000, WTF::UTCTime);
+ EXPECT_FALSE(dstBegin2015UTC.isDST);
+ EXPECT_EQ(-28800000, dstBegin2015UTC.offset);
+
+ // DST End: November 1, 2015
+ LocalTimeOffset dstEnd2015 = calculateLocalTimeOffset(1446361200000, WTF::LocalTime);
+ EXPECT_FALSE(dstEnd2015.isDST);
+ EXPECT_EQ(-28800000, dstEnd2015.offset);
+
+ // DST Begin: March 13, 2016
+ LocalTimeOffset dstBegin2016 = calculateLocalTimeOffset(1458111600000, WTF::LocalTime);
+ EXPECT_TRUE(dstBegin2016.isDST);
+ EXPECT_EQ(-25200000, dstBegin2016.offset);
+
+ // DST End: November 6, 2016
+ LocalTimeOffset dstEnd2016 = calculateLocalTimeOffset(1478415600000, WTF::LocalTime);
+ EXPECT_FALSE(dstEnd2016.isDST);
+ EXPECT_EQ(-28800000, dstEnd2016.offset);
+
+ // DST Begin: March 12, 2017
+ LocalTimeOffset dstBegin2017 = calculateLocalTimeOffset(1489305600000, WTF::LocalTime);
+ EXPECT_TRUE(dstBegin2017.isDST);
+ EXPECT_EQ(-25200000, dstBegin2017.offset);
+
+ // DST End: November 5, 2017
+ LocalTimeOffset dstEnd2017 = calculateLocalTimeOffset(1509865200000, WTF::LocalTime);
+ EXPECT_FALSE(dstEnd2017.isDST);
+ EXPECT_EQ(-28800000, dstEnd2017.offset);
+
+ // DST Begin: March 11, 2018
+ LocalTimeOffset dstBegin2018 = calculateLocalTimeOffset(1520755200000, WTF::LocalTime);
+ EXPECT_TRUE(dstBegin2018.isDST);
+ EXPECT_EQ(-25200000, dstBegin2018.offset);
+
+ // DST End: November 4, 2018
+ LocalTimeOffset dstEnd2018 = calculateLocalTimeOffset(1541314800000, WTF::LocalTime);
+ EXPECT_FALSE(dstEnd2018.isDST);
+ EXPECT_EQ(-28800000, dstEnd2018.offset);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/DeletedAddressOfOperator.h b/Tools/TestWebKitAPI/Tests/WTF/DeletedAddressOfOperator.h
new file mode 100644
index 000000000..31d5d80b9
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/DeletedAddressOfOperator.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/HashFunctions.h>
+#include <wtf/HashTraits.h>
+
+class DeletedAddressOfOperator {
+public:
+ DeletedAddressOfOperator()
+ : m_value(0)
+ {
+ }
+
+ DeletedAddressOfOperator(unsigned value)
+ : m_value(value)
+ {
+ }
+
+ DeletedAddressOfOperator* operator&() = delete;
+
+ unsigned value() const
+ {
+ return m_value;
+ }
+
+ friend bool operator==(const DeletedAddressOfOperator& a, const DeletedAddressOfOperator& b)
+ {
+ return a.m_value == b.m_value;
+ }
+
+private:
+ unsigned m_value;
+};
+
+namespace WTF {
+
+template<> struct HashTraits<DeletedAddressOfOperator> : public GenericHashTraits<DeletedAddressOfOperator> {
+ static const bool emptyValueIsZero = true;
+
+ static void constructDeletedValue(DeletedAddressOfOperator& slot) { slot = DeletedAddressOfOperator(std::numeric_limits<unsigned>::max()); }
+ static bool isDeletedValue(const DeletedAddressOfOperator& slot) { return slot.value() == std::numeric_limits<unsigned>::max(); }
+};
+
+template<> struct DefaultHash<DeletedAddressOfOperator> {
+ struct Hash {
+ static unsigned hash(const DeletedAddressOfOperator& key)
+ {
+ return intHash(key.value());
+ }
+
+ static bool equal(const DeletedAddressOfOperator& a, const DeletedAddressOfOperator& b)
+ {
+ return a == b;
+ }
+
+ static const bool safeToCompareToEmptyOrDeleted = true;
+ };
+};
+}
+
diff --git a/Tools/TestWebKitAPI/Tests/WTF/Deque.cpp b/Tools/TestWebKitAPI/Tests/WTF/Deque.cpp
new file mode 100644
index 000000000..83f1f82ee
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/Deque.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "MoveOnly.h"
+#include <wtf/Deque.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF_Deque, Iterator)
+{
+ Deque<int> deque;
+ deque.append(11);
+ deque.prepend(10);
+ deque.append(12);
+ deque.append(13);
+
+ Deque<int>::iterator it = deque.begin();
+ Deque<int>::iterator end = deque.end();
+ EXPECT_TRUE(end != it);
+
+ EXPECT_EQ(10, *it);
+ ++it;
+ EXPECT_EQ(11, *it);
+ ++it;
+ EXPECT_EQ(12, *it);
+ ++it;
+ EXPECT_EQ(13, *it);
+ ++it;
+
+ EXPECT_TRUE(end == it);
+}
+
+TEST(WTF_Deque, InitializerList)
+{
+ Deque<int> deque = { 1, 2, 3, 4 };
+
+ EXPECT_EQ(4u, deque.size());
+
+ auto it = deque.begin();
+ auto end = deque.end();
+ EXPECT_TRUE(end != it);
+
+ EXPECT_EQ(1, *it);
+ ++it;
+ EXPECT_EQ(2, *it);
+ ++it;
+ EXPECT_EQ(3, *it);
+ ++it;
+ EXPECT_EQ(4, *it);
+ ++it;
+
+ EXPECT_TRUE(end == it);
+}
+
+TEST(WTF, DequeReverseIterator)
+{
+ Deque<int> deque;
+ deque.append(11);
+ deque.prepend(10);
+ deque.append(12);
+ deque.append(13);
+
+ Deque<int>::reverse_iterator it = deque.rbegin();
+ Deque<int>::reverse_iterator end = deque.rend();
+ EXPECT_TRUE(end != it);
+
+ EXPECT_EQ(13, *it);
+ ++it;
+ EXPECT_EQ(12, *it);
+ ++it;
+ EXPECT_EQ(11, *it);
+ ++it;
+ EXPECT_EQ(10, *it);
+ ++it;
+
+ EXPECT_TRUE(end == it);
+}
+
+TEST(WTF_Deque, Remove)
+{
+ Deque<int> deque;
+ deque.append(11);
+ deque.prepend(10);
+ deque.append(12);
+ deque.append(13);
+
+ EXPECT_EQ(10, deque.first());
+ EXPECT_EQ(13, deque.last());
+
+ deque.removeLast();
+ EXPECT_EQ(10, deque.first());
+ EXPECT_EQ(12, deque.last());
+
+ deque.removeFirst();
+ EXPECT_EQ(11, deque.first());
+ EXPECT_EQ(12, deque.last());
+
+ deque.removeFirst();
+ EXPECT_EQ(12, deque.first());
+ EXPECT_EQ(12, deque.last());
+
+ deque.removeLast();
+ EXPECT_TRUE(deque.isEmpty());
+}
+
+TEST(WTF_Deque, MoveOnly)
+{
+ Deque<MoveOnly> deque;
+
+ deque.append(MoveOnly(1));
+ deque.prepend(MoveOnly(0));
+
+ EXPECT_EQ(0U, deque.first().value());
+ EXPECT_EQ(1U, deque.last().value());
+
+ auto first = deque.takeFirst();
+ EXPECT_EQ(0U, first.value());
+
+ auto last = deque.takeLast();
+ EXPECT_EQ(1U, last.value());
+}
+
+TEST(WTF_Deque, MoveConstructor)
+{
+ Deque<MoveOnly, 4> deque;
+
+ for (unsigned i = 0; i < 10; ++i)
+ deque.append(MoveOnly(i));
+
+ EXPECT_EQ(10u, deque.size());
+
+ Deque<MoveOnly, 4> deque2 = WTFMove(deque);
+
+ EXPECT_EQ(10u, deque2.size());
+
+ unsigned i = 0;
+ for (auto& element : deque2) {
+ EXPECT_EQ(i, element.value());
+ ++i;
+ }
+}
+
+TEST(WTF_Deque, MoveAssignmentOperator)
+{
+ Deque<MoveOnly, 4> deque1;
+
+ for (unsigned i = 0; i < 10; ++i)
+ deque1.append(MoveOnly(i));
+
+ EXPECT_EQ(10u, deque1.size());
+
+ Deque<MoveOnly, 4> deque2;
+ for (unsigned i = 0; i < 10; ++i)
+ deque2.append(MoveOnly(i * 2));
+
+ deque1 = WTFMove(deque2);
+
+ EXPECT_EQ(10u, deque2.size());
+
+ unsigned i = 0;
+ for (auto& element : deque1) {
+ EXPECT_EQ(i * 2, element.value());
+ ++i;
+ }
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/EnumTraits.cpp b/Tools/TestWebKitAPI/Tests/WTF/EnumTraits.cpp
new file mode 100644
index 000000000..0246fde29
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/EnumTraits.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <wtf/EnumTraits.h>
+
+enum class TestEnum {
+ A,
+ B,
+ C,
+};
+
+namespace WTF {
+template<> struct EnumTraits<TestEnum> {
+ using values = EnumValues<TestEnum, TestEnum::A, TestEnum::B, TestEnum::C>;
+};
+}
+
+namespace TestWebKitAPI {
+
+static_assert(WTF::isValidEnum<TestEnum>(0), "");
+static_assert(!WTF::isValidEnum<TestEnum>(-1), "");
+static_assert(!WTF::isValidEnum<TestEnum>(3), "");
+
+TEST(WTF_EnumTraits, IsValidEnum)
+{
+ EXPECT_TRUE(isValidEnum<TestEnum>(0));
+ EXPECT_FALSE(isValidEnum<TestEnum>(-1));
+ EXPECT_FALSE(isValidEnum<TestEnum>(3));
+}
+
+}
diff --git a/Tools/TestWebKitAPI/Tests/WTF/Expected.cpp b/Tools/TestWebKitAPI/Tests/WTF/Expected.cpp
new file mode 100644
index 000000000..73654c5dd
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/Expected.cpp
@@ -0,0 +1,512 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "RefLogger.h"
+
+#include <string>
+#include <unordered_map>
+
+#include <wtf/Expected.h>
+#include <wtf/Ref.h>
+
+namespace WTF {
+
+template <class E> std::ostream& operator<<(std::ostream& os, const UnexpectedType<E>& u)
+{
+ return os << u.value();
+}
+
+template <class T, class E> std::ostream& operator<<(std::ostream& os, const Expected<T, E>& e)
+{
+ if (e.hasValue())
+ return os << e.value();
+ return os << e.error();
+}
+
+template <class E> std::ostream& operator<<(std::ostream& os, const Expected<void, E>& e)
+{
+ if (e.hasValue())
+ return os << "";
+ return os << e.error();
+}
+
+}
+
+namespace TestWebKitAPI {
+
+constexpr const char* oops = "oops";
+constexpr const char* foof = "foof";
+
+TEST(WTF_Expected, UnexpectedType)
+{
+ {
+ auto u = UnexpectedType<int>(42);
+ EXPECT_EQ(u.value(), 42);
+ constexpr auto c = makeUnexpected(42);
+ EXPECT_EQ(c.value(), 42);
+ EXPECT_EQ(u, c);
+ EXPECT_FALSE(u != c);
+ EXPECT_FALSE(u < c);
+ EXPECT_FALSE(u > c);
+ EXPECT_LE(u, c);
+ EXPECT_GE(u, c);
+ }
+ {
+ auto c = makeUnexpected(oops);
+ EXPECT_EQ(c.value(), oops);
+ }
+ {
+ auto s = makeUnexpected(std::string(oops));
+ EXPECT_EQ(s.value(), oops);
+ }
+ {
+ constexpr auto s0 = makeUnexpected(oops);
+ constexpr auto s1(s0);
+ EXPECT_EQ(s0, s1);
+ }
+}
+
+struct foo {
+ int v;
+ foo(int v)
+ : v(v)
+ { }
+ ~foo() { }
+ bool operator==(const foo& y) const { return v == y.v; }
+ friend std::ostream& operator<<(std::ostream&, const foo&);
+};
+std::ostream& operator<<(std::ostream& os, const foo& f) { return os << f.v; }
+
+TEST(WTF_Expected, expected)
+{
+ typedef Expected<int, const char*> E;
+ typedef Expected<int, const void*> EV;
+ typedef Expected<foo, const char*> FooChar;
+ typedef Expected<foo, std::string> FooString;
+ {
+ auto e = E();
+ EXPECT_TRUE(e.hasValue());
+ EXPECT_EQ(e.value(), 0);
+ EXPECT_EQ(e.valueOr(3.14), 0);
+ }
+ {
+ constexpr E e;
+ EXPECT_TRUE(e.hasValue());
+ EXPECT_EQ(e.value(), 0);
+ EXPECT_EQ(e.valueOr(3.14), 0);
+ }
+ {
+ auto e = E(42);
+ EXPECT_TRUE(e.hasValue());
+ EXPECT_EQ(e.value(), 42);
+ EXPECT_EQ(e.valueOr(3.14), 42);
+ const auto e2(e);
+ EXPECT_TRUE(e2.hasValue());
+ EXPECT_EQ(e2.value(), 42);
+ EXPECT_EQ(e2.valueOr(3.14), 42);
+ E e3;
+ e3 = e2;
+ EXPECT_TRUE(e3.hasValue());
+ EXPECT_EQ(e3.value(), 42);
+ EXPECT_EQ(e3.valueOr(3.14), 42);
+ const E e4 = e2;
+ EXPECT_TRUE(e4.hasValue());
+ EXPECT_EQ(e4.value(), 42);
+ EXPECT_EQ(e4.valueOr(3.14), 42);
+ }
+ {
+ constexpr E c(42);
+ EXPECT_TRUE(c.hasValue());
+ EXPECT_EQ(c.value(), 42);
+ EXPECT_EQ(c.valueOr(3.14), 42);
+ constexpr const auto c2(c);
+ EXPECT_TRUE(c2.hasValue());
+ EXPECT_EQ(c2.value(), 42);
+ EXPECT_EQ(c2.valueOr(3.14), 42);
+ }
+ {
+ auto u = E(makeUnexpected(oops));
+ EXPECT_FALSE(u.hasValue());
+ EXPECT_EQ(u.error(), oops);
+ EXPECT_EQ(u.getUnexpected().value(), oops);
+ EXPECT_EQ(u.valueOr(3.14), 3);
+ }
+ {
+ auto uv = EV(makeUnexpected(oops));
+ EXPECT_FALSE(uv.hasValue());
+ EXPECT_EQ(uv.error(), oops);
+ EXPECT_EQ(uv.getUnexpected().value(), oops);
+ EXPECT_EQ(uv.valueOr(3.14), 3);
+ }
+ {
+ E e = makeUnexpected(oops);
+ EXPECT_FALSE(e.hasValue());
+ EXPECT_EQ(e.error(), oops);
+ EXPECT_EQ(e.getUnexpected().value(), oops);
+ EXPECT_EQ(e.valueOr(3.14), 3);
+ }
+ {
+ auto e = makeExpectedFromError<int, const char*>(oops);
+ EXPECT_FALSE(e.hasValue());
+ EXPECT_EQ(e.error(), oops);
+ EXPECT_EQ(e.getUnexpected().value(), oops);
+ EXPECT_EQ(e.valueOr(3.14), 3);
+ }
+ {
+ auto e = makeExpectedFromError<int, const void*>(oops);
+ EXPECT_FALSE(e.hasValue());
+ EXPECT_EQ(e.error(), oops);
+ EXPECT_EQ(e.getUnexpected().value(), oops);
+ EXPECT_EQ(e.valueOr(3.14), 3);
+ }
+ {
+ auto e = FooChar(42);
+ EXPECT_EQ(e->v, 42);
+ EXPECT_EQ((*e).v, 42);
+ }
+ {
+ auto e0 = E(42);
+ auto e1 = E(1024);
+ swap(e0, e1);
+ EXPECT_EQ(e0.value(), 1024);
+ EXPECT_EQ(e1.value(), 42);
+ }
+ {
+ auto e0 = E(makeUnexpected(oops));
+ auto e1 = E(makeUnexpected(foof));
+ swap(e0, e1);
+ EXPECT_EQ(e0.error(), foof);
+ EXPECT_EQ(e1.error(), oops);
+ }
+ {
+ FooChar c(foo(42));
+ EXPECT_EQ(c->v, 42);
+ EXPECT_EQ((*c).v, 42);
+ }
+ {
+ FooString s(foo(42));
+ EXPECT_EQ(s->v, 42);
+ EXPECT_EQ((*s).v, 42);
+ const char* message = "very long failure string, for very bad failure cases";
+ FooString e0(makeUnexpected<std::string>(message));
+ FooString e1(makeUnexpected<std::string>(message));
+ FooString e2(makeUnexpected<std::string>(std::string()));
+ EXPECT_EQ(e0.error(), std::string(message));
+ EXPECT_EQ(e0, e1);
+ EXPECT_NE(e0, e2);
+ FooString* e4 = new FooString(makeUnexpected<std::string>(message));
+ FooString* e5 = new FooString(*e4);
+ EXPECT_EQ(e0, *e4);
+ delete e4;
+ EXPECT_EQ(e0, *e5);
+ delete e5;
+ }
+}
+
+TEST(WTF_Expected, Expected_void)
+{
+ typedef Expected<void, const char*> E;
+ typedef Expected<void, const void*> EV;
+ typedef Expected<void, std::string> String;
+ {
+ auto e = E();
+ EXPECT_TRUE(e.hasValue());
+ const auto e2(e);
+ EXPECT_TRUE(e2.hasValue());
+ EXPECT_EQ(e, e2);
+ E e3;
+ e3 = e2;
+ EXPECT_TRUE(e3.hasValue());
+ EXPECT_EQ(e, e3);
+ }
+ {
+ constexpr E c;
+ EXPECT_TRUE(c.hasValue());
+ constexpr const auto c2(c);
+ EXPECT_TRUE(c2.hasValue());
+ EXPECT_EQ(c, c2);
+ }
+ {
+ auto u = E(makeUnexpected(oops));
+ EXPECT_FALSE(u.hasValue());
+ EXPECT_EQ(u.error(), oops);
+ EXPECT_EQ(u.getUnexpected().value(), oops);
+ }
+ {
+ auto uv = EV(makeUnexpected(oops));
+ EXPECT_FALSE(uv.hasValue());
+ EXPECT_EQ(uv.error(), oops);
+ EXPECT_EQ(uv.getUnexpected().value(), oops);
+ }
+ {
+ E e = makeUnexpected(oops);
+ EXPECT_FALSE(e.hasValue());
+ EXPECT_EQ(e.error(), oops);
+ EXPECT_EQ(e.getUnexpected().value(), oops);
+ }
+ {
+ auto e = makeExpectedFromError<void, const char*>(oops);
+ EXPECT_FALSE(e.hasValue());
+ EXPECT_EQ(e.error(), oops);
+ EXPECT_EQ(e.getUnexpected().value(), oops);
+ }
+ {
+ auto e = makeExpectedFromError<void, const void*>(oops);
+ EXPECT_FALSE(e.hasValue());
+ EXPECT_EQ(e.error(), oops);
+ EXPECT_EQ(e.getUnexpected().value(), oops);
+ }
+ {
+ auto e0 = E();
+ auto e1 = E();
+ swap(e0, e1);
+ EXPECT_EQ(e0, e1);
+ }
+ {
+ auto e0 = E(makeUnexpected(oops));
+ auto e1 = E(makeUnexpected(foof));
+ swap(e0, e1);
+ EXPECT_EQ(e0.error(), foof);
+ EXPECT_EQ(e1.error(), oops);
+ }
+ {
+ const char* message = "very long failure string, for very bad failure cases";
+ String e0(makeUnexpected<std::string>(message));
+ String e1(makeUnexpected<std::string>(message));
+ String e2(makeUnexpected<std::string>(std::string()));
+ EXPECT_EQ(e0.error(), std::string(message));
+ EXPECT_EQ(e0, e1);
+ EXPECT_NE(e0, e2);
+ String* e4 = new String(makeUnexpected<std::string>(message));
+ String* e5 = new String(*e4);
+ EXPECT_EQ(e0, *e4);
+ delete e4;
+ EXPECT_EQ(e0, *e5);
+ delete e5;
+ }
+}
+
+TEST(WTF_Expected, comparison)
+{
+ typedef Expected<int, const char*> Ex;
+ typedef Expected<int, int> Er;
+
+ // Two Expected, no errors.
+ EXPECT_EQ(Ex(42), Ex(42));
+ EXPECT_NE(Ex(42), Ex(1024));
+ EXPECT_LT(Ex(42), Ex(1024));
+ EXPECT_GT(Ex(1024), Ex(42));
+ EXPECT_LE(Ex(42), Ex(42));
+ EXPECT_GE(Ex(42), Ex(42));
+ EXPECT_LE(Ex(42), Ex(1024));
+ EXPECT_GE(Ex(1024), Ex(42));
+
+ EXPECT_FALSE(Ex(42) == Ex(1024));
+ EXPECT_FALSE(Ex(42) != Ex(42));
+ EXPECT_FALSE(Ex(1024) < Ex(42));
+ EXPECT_FALSE(Ex(42) > Ex(1024));
+ EXPECT_FALSE(Ex(1024) < Ex(42));
+ EXPECT_FALSE(Ex(42) >= Ex(1024));
+
+ // Two Expected, half errors.
+ EXPECT_FALSE(Ex(42) == Ex(makeUnexpected(oops)));
+ EXPECT_NE(Ex(42), Ex(makeUnexpected(oops)));
+ EXPECT_LT(Ex(42), Ex(makeUnexpected(oops)));
+ EXPECT_FALSE(Ex(42) > Ex(makeUnexpected(oops)));
+ EXPECT_LE(Ex(42), Ex(makeUnexpected(oops)));
+ EXPECT_FALSE(Ex(42) >= Ex(makeUnexpected(oops)));
+
+ EXPECT_FALSE(Ex(makeUnexpected(oops)) == Ex(42));
+ EXPECT_NE(Ex(makeUnexpected(oops)), Ex(42));
+ EXPECT_FALSE(Ex(makeUnexpected(oops)) < Ex(42));
+ EXPECT_GT(Ex(makeUnexpected(oops)), Ex(42));
+ EXPECT_FALSE(Ex(makeUnexpected(oops)) <= Ex(42));
+ EXPECT_GE(Ex(makeUnexpected(oops)), Ex(42));
+
+ // Two Expected, all errors.
+ EXPECT_EQ(Er(42), Er(42));
+ EXPECT_NE(Er(42), Er(1024));
+ EXPECT_LT(Er(42), Er(1024));
+ EXPECT_GT(Er(1024), Er(42));
+ EXPECT_LE(Er(42), Er(42));
+ EXPECT_GE(Er(42), Er(42));
+ EXPECT_LE(Er(42), Er(1024));
+ EXPECT_GE(Er(1024), Er(42));
+
+ EXPECT_FALSE(Er(42) == Er(1024));
+ EXPECT_FALSE(Er(42) != Er(42));
+ EXPECT_FALSE(Er(1024) < Er(42));
+ EXPECT_FALSE(Er(42) > Er(1024));
+ EXPECT_FALSE(Er(1024) <= Er(42));
+ EXPECT_FALSE(Er(42) >= Er(1024));
+
+ // One Expected, one value.
+ EXPECT_EQ(Ex(42), 42);
+ EXPECT_NE(Ex(42), 0);
+ EXPECT_LT(Ex(42), 1024);
+ EXPECT_GT(Ex(1024), 42);
+ EXPECT_LE(Ex(42), 42);
+ EXPECT_GE(Ex(42), 42);
+ EXPECT_LE(Ex(42), 1024);
+ EXPECT_GE(Ex(1024), 42);
+
+ EXPECT_FALSE(Ex(42) == 0);
+ EXPECT_FALSE(Ex(42) != 42);
+ EXPECT_FALSE(Ex(1024) < 42);
+ EXPECT_FALSE(Ex(42) > 1024);
+ EXPECT_FALSE(Ex(1024) < 42);
+ EXPECT_FALSE(Ex(42) >= 1024);
+
+ EXPECT_EQ(42, Ex(42));
+ EXPECT_NE(42, Ex(1024));
+ EXPECT_LT(42, Ex(1024));
+ EXPECT_GT(1024, Ex(42));
+ EXPECT_LE(42, Ex(42));
+ EXPECT_GE(42, Ex(42));
+ EXPECT_LE(42, Ex(1024));
+ EXPECT_GE(1024, Ex(42));
+
+ EXPECT_FALSE(42 == Ex(1024));
+ EXPECT_FALSE(42 != Ex(42));
+ EXPECT_FALSE(1024 < Ex(42));
+ EXPECT_FALSE(42 > Ex(1024));
+ EXPECT_FALSE(1024 <= Ex(42));
+ EXPECT_FALSE(42 >= Ex(1024));
+
+ // One Expected, one unexpected.
+ EXPECT_FALSE(Ex(42) == makeUnexpected(oops));
+ EXPECT_NE(Ex(42), makeUnexpected(oops));
+ EXPECT_LT(Ex(42), makeUnexpected(oops));
+ EXPECT_FALSE(Ex(42) > makeUnexpected(oops));
+ EXPECT_LE(Ex(42), makeUnexpected(oops));
+ EXPECT_FALSE(Ex(42) >= makeUnexpected(oops));
+
+ EXPECT_FALSE(makeUnexpected(oops) == Ex(42));
+ EXPECT_NE(makeUnexpected(oops), Ex(42));
+ EXPECT_FALSE(makeUnexpected(oops) < Ex(42));
+ EXPECT_GT(makeUnexpected(oops), Ex(42));
+ EXPECT_FALSE(makeUnexpected(oops) <= Ex(42));
+ EXPECT_GE(makeUnexpected(oops), Ex(42));
+}
+
+struct NonTrivialDtor {
+ ~NonTrivialDtor() { ++count; }
+ static int count;
+};
+int NonTrivialDtor::count = 0;
+
+TEST(WTF_Expected, destructors)
+{
+ typedef Expected<NonTrivialDtor, const char*> NT;
+ typedef Expected<const char*, NonTrivialDtor> TN;
+ typedef Expected<NonTrivialDtor, NonTrivialDtor> NN;
+ typedef Expected<void, NonTrivialDtor> VN;
+ EXPECT_EQ(NonTrivialDtor::count, 0);
+ { NT nt; }
+ EXPECT_EQ(NonTrivialDtor::count, 1);
+ { NT nt = makeUnexpected(oops); }
+ EXPECT_EQ(NonTrivialDtor::count, 1);
+ { TN tn; }
+ EXPECT_EQ(NonTrivialDtor::count, 1);
+ { TN tn = makeUnexpected(NonTrivialDtor()); }
+ EXPECT_EQ(NonTrivialDtor::count, 4);
+ { NN nn; }
+ EXPECT_EQ(NonTrivialDtor::count, 5);
+ { NN nn = makeUnexpected(NonTrivialDtor()); }
+ EXPECT_EQ(NonTrivialDtor::count, 8);
+ { VN vn; }
+ EXPECT_EQ(NonTrivialDtor::count, 8);
+ { VN vn = makeUnexpected(NonTrivialDtor()); }
+ EXPECT_EQ(NonTrivialDtor::count, 11);
+}
+
+TEST(WTF_Expected, hash)
+{
+ typedef Expected<int, const char*> E;
+ std::unordered_map<E, int> m;
+ m.insert({ E(42), 42 });
+ m.insert({ E(makeUnexpected(oops)), 5 });
+ m.insert({ E(1024), 1024 });
+ m.insert({ E(makeUnexpected(foof)), 0xf00f });
+ EXPECT_EQ(m[E(42)], 42);
+ EXPECT_EQ(m[E(1024)], 1024);
+ EXPECT_EQ(m[E(makeUnexpected(oops))], 5);
+ EXPECT_EQ(m[E(makeUnexpected(foof))], 0xf00f);
+}
+
+TEST(WTF_Expected, hash_void)
+{
+ typedef Expected<void, const char*> E;
+ std::unordered_map<E, int> m;
+ m.insert({ E(), 42 });
+ m.insert({ E(makeUnexpected(oops)), 5 });
+ m.insert({ E(makeUnexpected(foof)), 0xf00f });
+ EXPECT_EQ(m[E()], 42);
+ EXPECT_EQ(m[E(makeUnexpected(oops))], 5);
+ EXPECT_EQ(m[E(makeUnexpected(foof))], 0xf00f);
+}
+
+TEST(WTF_Expected, Ref)
+{
+ {
+ RefLogger a("a");
+ Expected<Ref<RefLogger>, int> expected = Ref<RefLogger>(a);
+ EXPECT_TRUE(expected.hasValue());
+ EXPECT_EQ(&a, expected.value().ptr());
+ }
+
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefLogger a("a");
+ Expected<Ref<RefLogger>, int> expected = makeExpected<Ref<RefLogger>, int>(Ref<RefLogger>(a));
+ EXPECT_TRUE(expected.hasValue());
+ EXPECT_EQ(&a, expected.value().ptr());
+ }
+
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefLogger a("a");
+ Expected<int, Ref<RefLogger>> expected = makeUnexpected(Ref<RefLogger>(a));
+ EXPECT_FALSE(expected.hasValue());
+ EXPECT_EQ(&a, expected.error().ptr());
+ }
+
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefLogger a("a");
+ Expected<void, Ref<RefLogger>> expected = makeUnexpected(Ref<RefLogger>(a));
+ EXPECT_FALSE(expected.hasValue());
+ EXPECT_EQ(&a, expected.error().ptr());
+ }
+
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+} // namespace TestWebkitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/Functional.cpp b/Tools/TestWebKitAPI/Tests/WTF/Functional.cpp
deleted file mode 100644
index cf8c3c39c..000000000
--- a/Tools/TestWebKitAPI/Tests/WTF/Functional.cpp
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include <wtf/RefCounted.h>
-#include <wtf/Functional.h>
-
-namespace TestWebKitAPI {
-
-static int returnFortyTwo()
-{
- return 42;
-}
-
-TEST(FunctionalTest, Basic)
-{
- Function<int ()> emptyFunction;
- ASSERT_TRUE(emptyFunction.isNull());
-
- Function<int ()> returnFortyTwoFunction = bind(returnFortyTwo);
- ASSERT_FALSE(returnFortyTwoFunction.isNull());
- ASSERT_EQ(42, returnFortyTwoFunction());
-}
-
-static int multiplyByTwo(int n)
-{
- return n * 2;
-}
-
-static double multiplyByOneAndAHalf(double d)
-{
- return d * 1.5;
-}
-
-TEST(FunctionalTest, UnaryBind)
-{
- Function<int ()> multiplyFourByTwoFunction = bind(multiplyByTwo, 4);
- ASSERT_EQ(8, multiplyFourByTwoFunction());
-
- Function<double ()> multiplyByOneAndAHalfFunction = bind(multiplyByOneAndAHalf, 3);
- ASSERT_EQ(4.5, multiplyByOneAndAHalfFunction());
-}
-
-static int multiply(int x, int y)
-{
- return x * y;
-}
-
-static int subtract(int x, int y)
-{
- return x - y;
-}
-
-TEST(FunctionalTest, BinaryBind)
-{
- Function<int ()> multiplyFourByTwoFunction = bind(multiply, 4, 2);
- ASSERT_EQ(8, multiplyFourByTwoFunction());
-
- Function<int ()> subtractTwoFromFourFunction = bind(subtract, 4, 2);
- ASSERT_EQ(2, subtractTwoFromFourFunction());
-}
-
-class A {
-public:
- explicit A(int i)
- : m_i(i)
- {
- }
-
- int f() { return m_i; }
- int addF(int j) { return m_i + j; }
-
-private:
- int m_i;
-};
-
-TEST(FunctionalTest, MemberFunctionBind)
-{
- A a(10);
- Function<int ()> function1 = bind(&A::f, &a);
- ASSERT_EQ(10, function1());
-
- Function<int ()> function2 = bind(&A::addF, &a, 15);
- ASSERT_EQ(25, function2());
-}
-
-class B {
-public:
- B()
- : m_numRefCalls(0)
- , m_numDerefCalls(0)
- {
- }
-
- ~B()
- {
- }
-
- void ref()
- {
- m_numRefCalls++;
- }
-
- void deref()
- {
- m_numDerefCalls++;
- }
-
- void f() { ASSERT_GT(m_numRefCalls, 0); }
- void g(int) { ASSERT_GT(m_numRefCalls, 0); }
-
- int m_numRefCalls;
- int m_numDerefCalls;
-};
-
-TEST(FunctionalTest, MemberFunctionBindRefDeref)
-{
- B b;
-
- {
- Function<void ()> function1 = bind(&B::f, &b);
- function1();
-
- Function<void ()> function2 = bind(&B::g, &b, 10);
- function2();
- }
-
- ASSERT_TRUE(b.m_numRefCalls == b.m_numDerefCalls);
- ASSERT_GT(b.m_numRefCalls, 0);
-
-}
-
-class Number : public RefCounted<Number> {
-public:
- static PassRefPtr<Number> create(int value)
- {
- return adoptRef(new Number(value));
- }
-
- ~Number()
- {
- m_value = 0;
- }
-
- int value() const { return m_value; }
-
-private:
- explicit Number(int value)
- : m_value(value)
- {
- }
-
- int m_value;
-};
-
-static int multiplyNumberByTwo(Number* number)
-{
- return number->value() * 2;
-}
-
-TEST(FunctionalTest, RefCountedStorage)
-{
- RefPtr<Number> five = Number::create(5);
- Function<int ()> multiplyFiveByTwoFunction = bind(multiplyNumberByTwo, five);
- ASSERT_EQ(10, multiplyFiveByTwoFunction());
-
- Function<int ()> multiplyFourByTwoFunction = bind(multiplyNumberByTwo, Number::create(4));
- ASSERT_EQ(8, multiplyFourByTwoFunction());
-
- RefPtr<Number> six = Number::create(6);
- Function<int ()> multiplySixByTwoFunction = bind(multiplyNumberByTwo, six.release());
- ASSERT_FALSE(six);
- ASSERT_EQ(12, multiplySixByTwoFunction());
-}
-
-namespace RefAndDerefTests {
-
- template<typename T> struct RefCounted {
- void ref();
- void deref();
- };
- struct Connection : RefCounted<Connection> { };
- COMPILE_ASSERT(WTF::HasRefAndDeref<Connection>::value, class_has_ref_and_deref);
-
- struct NoRefOrDeref { };
- COMPILE_ASSERT(!WTF::HasRefAndDeref<NoRefOrDeref>::value, class_has_no_ref_or_deref);
-
- struct RefOnly { void ref(); };
- COMPILE_ASSERT(!WTF::HasRefAndDeref<RefOnly>::value, class_has_ref_only);
-
- struct DerefOnly { void deref(); };
- COMPILE_ASSERT(!WTF::HasRefAndDeref<DerefOnly>::value, class_has_deref_only);
-
-}
-
-} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/HashCountedSet.cpp b/Tools/TestWebKitAPI/Tests/WTF/HashCountedSet.cpp
new file mode 100644
index 000000000..9627bd05a
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/HashCountedSet.cpp
@@ -0,0 +1,468 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "Counters.h"
+#include "MoveOnly.h"
+#include "RefLogger.h"
+#include <string>
+#include <wtf/HashCountedSet.h>
+#include <wtf/text/StringHash.h>
+
+namespace TestWebKitAPI {
+
+typedef WTF::HashCountedSet<int> IntHashCountedSet;
+
+TEST(WTF_HashCountedSet, HashTableIteratorComparison)
+{
+ IntHashCountedSet hashCountedSet;
+ hashCountedSet.add(1);
+ ASSERT_TRUE(hashCountedSet.begin() != hashCountedSet.end());
+ ASSERT_FALSE(hashCountedSet.begin() == hashCountedSet.end());
+
+ IntHashCountedSet::const_iterator begin = hashCountedSet.begin();
+ ASSERT_TRUE(begin == hashCountedSet.begin());
+ ASSERT_TRUE(hashCountedSet.begin() == begin);
+ ASSERT_TRUE(begin != hashCountedSet.end());
+ ASSERT_TRUE(hashCountedSet.end() != begin);
+ ASSERT_FALSE(begin != hashCountedSet.begin());
+ ASSERT_FALSE(hashCountedSet.begin() != begin);
+ ASSERT_FALSE(begin == hashCountedSet.end());
+ ASSERT_FALSE(hashCountedSet.end() == begin);
+}
+
+struct TestDoubleHashTraits : HashTraits<double> {
+ static const int minimumTableSize = 8;
+};
+
+typedef HashCountedSet<double, DefaultHash<double>::Hash, TestDoubleHashTraits> DoubleHashCountedSet;
+
+static int bucketForKey(double key)
+{
+ return DefaultHash<double>::Hash::hash(key) & (TestDoubleHashTraits::minimumTableSize - 1);
+}
+
+TEST(WTF_HashCountedSet, DoubleHashCollisions)
+{
+ // The "clobber" key here is one that ends up stealing the bucket that the -0 key
+ // originally wants to be in. This makes the 0 and -0 keys collide and the test then
+ // fails unless the FloatHash::equals() implementation can distinguish them.
+ const double clobberKey = 6;
+ const double zeroKey = 0;
+ const double negativeZeroKey = -zeroKey;
+
+ DoubleHashCountedSet hashCountedSet;
+
+ hashCountedSet.add(clobberKey);
+
+ ASSERT_EQ(hashCountedSet.count(clobberKey), 1u);
+ ASSERT_EQ(hashCountedSet.count(zeroKey), 0u);
+ ASSERT_EQ(hashCountedSet.count(negativeZeroKey), 0u);
+
+ hashCountedSet.add(zeroKey);
+ hashCountedSet.add(negativeZeroKey);
+
+ ASSERT_EQ(bucketForKey(clobberKey), bucketForKey(negativeZeroKey));
+ ASSERT_EQ(hashCountedSet.count(clobberKey), 1u);
+ ASSERT_EQ(hashCountedSet.count(zeroKey), 1u);
+ ASSERT_EQ(hashCountedSet.count(negativeZeroKey), 1u);
+
+ hashCountedSet.add(clobberKey);
+ hashCountedSet.add(zeroKey);
+ hashCountedSet.add(negativeZeroKey);
+
+ ASSERT_EQ(hashCountedSet.count(clobberKey), 2u);
+ ASSERT_EQ(hashCountedSet.count(zeroKey), 2u);
+ ASSERT_EQ(hashCountedSet.count(negativeZeroKey), 2u);
+
+ hashCountedSet.add(clobberKey, 12);
+ hashCountedSet.add(zeroKey, 15);
+ hashCountedSet.add(negativeZeroKey, 17);
+
+ ASSERT_EQ(hashCountedSet.count(clobberKey), 14u);
+ ASSERT_EQ(hashCountedSet.count(zeroKey), 17u);
+ ASSERT_EQ(hashCountedSet.count(negativeZeroKey), 19u);
+}
+
+TEST(WTF_HashCountedSet, DoubleHashCollisionsInitialCount)
+{
+ // The "clobber" key here is one that ends up stealing the bucket that the -0 key
+ // originally wants to be in. This makes the 0 and -0 keys collide and the test then
+ // fails unless the FloatHash::equals() implementation can distinguish them.
+ const double clobberKey = 6;
+ const double zeroKey = 0;
+ const double negativeZeroKey = -zeroKey;
+
+ DoubleHashCountedSet hashCountedSet;
+
+ hashCountedSet.add(clobberKey, 5);
+
+ ASSERT_EQ(hashCountedSet.count(clobberKey), 5u);
+ ASSERT_EQ(hashCountedSet.count(zeroKey), 0u);
+ ASSERT_EQ(hashCountedSet.count(negativeZeroKey), 0u);
+
+ hashCountedSet.add(zeroKey, 22);
+ hashCountedSet.add(negativeZeroKey, 0);
+
+ ASSERT_EQ(bucketForKey(clobberKey), bucketForKey(negativeZeroKey));
+ ASSERT_EQ(hashCountedSet.count(clobberKey), 5u);
+ ASSERT_EQ(hashCountedSet.count(zeroKey), 22u);
+ ASSERT_EQ(hashCountedSet.count(negativeZeroKey), 0u);
+
+ hashCountedSet.add(clobberKey);
+ hashCountedSet.add(zeroKey);
+ hashCountedSet.add(negativeZeroKey);
+
+ ASSERT_EQ(hashCountedSet.count(clobberKey), 6u);
+ ASSERT_EQ(hashCountedSet.count(zeroKey), 23u);
+ ASSERT_EQ(hashCountedSet.count(negativeZeroKey), 1u);
+}
+
+
+TEST(WTF_HashCountedSet, MoveOnlyKeys)
+{
+ HashCountedSet<MoveOnly> moveOnlyKeys;
+
+ for (size_t i = 0; i < 100; ++i) {
+ MoveOnly moveOnly(i + 1);
+ moveOnlyKeys.add(WTFMove(moveOnly));
+ }
+
+ for (size_t i = 0; i < 100; ++i) {
+ auto it = moveOnlyKeys.find(MoveOnly(i + 1));
+ ASSERT_FALSE(it == moveOnlyKeys.end());
+ ASSERT_EQ(it->value, 1u);
+ }
+
+ for (size_t i = 0; i < 100; ++i)
+ ASSERT_FALSE(moveOnlyKeys.add(MoveOnly(i + 1)).isNewEntry);
+
+ for (size_t i = 0; i < 100; ++i)
+ ASSERT_FALSE(moveOnlyKeys.remove(MoveOnly(i + 1)));
+
+ for (size_t i = 0; i < 100; ++i)
+ ASSERT_TRUE(moveOnlyKeys.remove(MoveOnly(i + 1)));
+
+ ASSERT_TRUE(moveOnlyKeys.isEmpty());
+}
+
+TEST(WTF_HashCountedSet, MoveOnlyKeysInitialCount)
+{
+ HashCountedSet<MoveOnly> moveOnlyKeys;
+
+ for (size_t i = 0; i < 100; ++i) {
+ MoveOnly moveOnly(i + 1);
+ moveOnlyKeys.add(WTFMove(moveOnly), i + 1);
+ }
+
+ for (size_t i = 0; i < 100; ++i) {
+ auto it = moveOnlyKeys.find(MoveOnly(i + 1));
+ ASSERT_FALSE(it == moveOnlyKeys.end());
+ ASSERT_EQ(it->value, i + 1);
+ }
+
+ for (size_t i = 0; i < 100; ++i)
+ ASSERT_FALSE(moveOnlyKeys.add(MoveOnly(i + 1)).isNewEntry);
+
+ for (size_t i = 0; i < 100; ++i)
+ ASSERT_EQ(moveOnlyKeys.count(MoveOnly(i + 1)), i + 2);
+
+ for (size_t i = 0; i < 100; ++i)
+ ASSERT_FALSE(moveOnlyKeys.remove(MoveOnly(i + 1)));
+
+ for (size_t i = 0; i < 100; ++i)
+ ASSERT_EQ(moveOnlyKeys.count(MoveOnly(i + 1)), i + 1);
+}
+
+TEST(WTF_HashCountedSet, InitializerList)
+{
+ HashCountedSet<String> hashCountedSet = {
+ "one",
+ "two",
+ "three",
+ "four",
+ "four",
+ "four",
+ "four",
+ };
+
+ EXPECT_EQ(4u, hashCountedSet.size());
+
+ EXPECT_EQ(hashCountedSet.count("one"), 1u);
+ EXPECT_EQ(hashCountedSet.count("two"), 1u);
+ EXPECT_EQ(hashCountedSet.count("three"), 1u);
+ EXPECT_EQ(hashCountedSet.count("four"), 4u);
+}
+
+TEST(WTF_HashCountedSet, InitializerListInitialCount)
+{
+ HashCountedSet<String> hashCountedSet = {
+ { String("one"), 1u },
+ { String("two"), 2u },
+ { String("three"), 3u },
+ { String("four"), 4u },
+ };
+
+ EXPECT_EQ(4u, hashCountedSet.size());
+
+ EXPECT_EQ(hashCountedSet.count("one"), 1u);
+ EXPECT_EQ(hashCountedSet.count("two"), 2u);
+ EXPECT_EQ(hashCountedSet.count("three"), 3u);
+ EXPECT_EQ(hashCountedSet.count("four"), 4u);
+}
+
+TEST(WTF_HashCountedSet, UniquePtrKey)
+{
+ ConstructorDestructorCounter::TestingScope scope;
+
+ HashCountedSet<std::unique_ptr<ConstructorDestructorCounter>> hashCountedSet;
+
+ auto uniquePtr = std::make_unique<ConstructorDestructorCounter>();
+ hashCountedSet.add(WTFMove(uniquePtr));
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
+
+ hashCountedSet.clear();
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount);
+}
+
+TEST(WTF_HashCountedSet, UniquePtrKeyInitialCount)
+{
+ ConstructorDestructorCounter::TestingScope scope;
+
+ HashCountedSet<std::unique_ptr<ConstructorDestructorCounter>> hashCountedSet;
+
+ auto uniquePtr = std::make_unique<ConstructorDestructorCounter>();
+ hashCountedSet.add(WTFMove(uniquePtr), 12);
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
+
+ hashCountedSet.clear();
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount);
+}
+
+TEST(WTF_HashCountedSet, UniquePtrKey_CustomDeleter)
+{
+ ConstructorDestructorCounter::TestingScope constructorDestructorCounterScope;
+ DeleterCounter<ConstructorDestructorCounter>::TestingScope deleterCounterScope;
+
+ HashCountedSet<std::unique_ptr<ConstructorDestructorCounter, DeleterCounter<ConstructorDestructorCounter>>> hashCountedSet;
+
+ std::unique_ptr<ConstructorDestructorCounter, DeleterCounter<ConstructorDestructorCounter>> uniquePtr(new ConstructorDestructorCounter(), DeleterCounter<ConstructorDestructorCounter>());
+ hashCountedSet.add(WTFMove(uniquePtr));
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
+
+ EXPECT_EQ(0u, DeleterCounter<ConstructorDestructorCounter>::deleterCount());
+
+ hashCountedSet.clear();
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount);
+
+ EXPECT_EQ(1u, DeleterCounter<ConstructorDestructorCounter>::deleterCount());
+}
+
+TEST(WTF_HashCountedSet, UniquePtrKey_FindUsingRawPointer)
+{
+ HashCountedSet<std::unique_ptr<int>> hashCountedSet;
+
+ auto uniquePtr = std::make_unique<int>(5);
+ int* ptr = uniquePtr.get();
+ hashCountedSet.add(WTFMove(uniquePtr));
+
+ auto it = hashCountedSet.find(ptr);
+ ASSERT_TRUE(it != hashCountedSet.end());
+ EXPECT_EQ(ptr, it->key.get());
+ EXPECT_EQ(1u, it->value);
+}
+
+TEST(WTF_HashCountedSet, UniquePtrKey_ContainsUsingRawPointer)
+{
+ HashCountedSet<std::unique_ptr<int>> hashCountedSet;
+
+ auto uniquePtr = std::make_unique<int>(5);
+ int* ptr = uniquePtr.get();
+ hashCountedSet.add(WTFMove(uniquePtr));
+
+ EXPECT_EQ(true, hashCountedSet.contains(ptr));
+}
+
+TEST(WTF_HashCountedSet, UniquePtrKey_GetUsingRawPointer)
+{
+ HashCountedSet<std::unique_ptr<int>> hashCountedSet;
+
+ auto uniquePtr = std::make_unique<int>(5);
+ int* ptr = uniquePtr.get();
+ hashCountedSet.add(WTFMove(uniquePtr));
+
+ int value = hashCountedSet.count(ptr);
+ EXPECT_EQ(1, value);
+}
+
+TEST(WTF_HashCountedSet, UniquePtrKey_RemoveUsingRawPointer)
+{
+ ConstructorDestructorCounter::TestingScope scope;
+
+ HashCountedSet<std::unique_ptr<ConstructorDestructorCounter>> hashCountedSet;
+
+ auto uniquePtr = std::make_unique<ConstructorDestructorCounter>();
+ ConstructorDestructorCounter* ptr = uniquePtr.get();
+ hashCountedSet.add(WTFMove(uniquePtr));
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
+
+ bool result = hashCountedSet.remove(ptr);
+ EXPECT_EQ(true, result);
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount);
+}
+
+TEST(WTF_HashCountedSet, RefPtrKey_Add)
+{
+ HashCountedSet<RefPtr<RefLogger>> hashCountedSet;
+
+ DerivedRefLogger a("a");
+ RefPtr<RefLogger> ptr(&a);
+ hashCountedSet.add(ptr);
+
+ ASSERT_STREQ("ref(a) ref(a) ", takeLogStr().c_str());
+ EXPECT_EQ(1U, hashCountedSet.count(ptr));
+ EXPECT_EQ(1U, hashCountedSet.count(ptr.get()));
+}
+
+TEST(WTF_HashCountedSet, RefPtrKey_AddUsingRelease)
+{
+ HashCountedSet<RefPtr<RefLogger>> hashCountedSet;
+
+ DerivedRefLogger a("a");
+ RefPtr<RefLogger> ptr(&a);
+ hashCountedSet.add(WTFMove(ptr));
+
+ EXPECT_STREQ("ref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashCountedSet, RefPtrKey_AddUsingMove)
+{
+ HashCountedSet<RefPtr<RefLogger>> hashCountedSet;
+
+ DerivedRefLogger a("a");
+ RefPtr<RefLogger> ptr(&a);
+ hashCountedSet.add(WTFMove(ptr));
+
+ EXPECT_STREQ("ref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashCountedSet, RefPtrKey_AddUsingRaw)
+{
+ HashCountedSet<RefPtr<RefLogger>> hashCountedSet;
+
+ DerivedRefLogger a("a");
+ RefPtr<RefLogger> ptr(&a);
+ hashCountedSet.add(ptr.get());
+
+ EXPECT_STREQ("ref(a) ref(a) ", takeLogStr().c_str());
+ EXPECT_EQ(1U, hashCountedSet.count(ptr));
+ EXPECT_EQ(1U, hashCountedSet.count(ptr.get()));
+}
+
+TEST(WTF_HashCountedSet, RefPtrKey_AddKeyAlreadyPresent)
+{
+ HashCountedSet<RefPtr<RefLogger>> hashCountedSet;
+
+ DerivedRefLogger a("a");
+
+ {
+ RefPtr<RefLogger> ptr(&a);
+ hashCountedSet.add(ptr);
+ }
+
+ EXPECT_STREQ("ref(a) ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr2(&a);
+ auto addResult = hashCountedSet.add(ptr2);
+ EXPECT_FALSE(addResult.isNewEntry);
+ }
+
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashCountedSet, RefPtrKey_AddUsingReleaseKeyAlreadyPresent)
+{
+ HashCountedSet<RefPtr<RefLogger>> hashCountedSet;
+
+ DerivedRefLogger a("a");
+
+ {
+ RefPtr<RefLogger> ptr(&a);
+ hashCountedSet.add(ptr);
+ }
+
+ EXPECT_STREQ("ref(a) ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr2(&a);
+ auto addResult = hashCountedSet.add(WTFMove(ptr2));
+ EXPECT_FALSE(addResult.isNewEntry);
+ }
+
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashCountedSet, RefPtrKey_AddUsingMoveKeyAlreadyPresent)
+{
+ HashCountedSet<RefPtr<RefLogger>> hashCountedSet;
+
+ DerivedRefLogger a("a");
+
+ {
+ RefPtr<RefLogger> ptr(&a);
+ hashCountedSet.add(ptr);
+ }
+
+ EXPECT_STREQ("ref(a) ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr2(&a);
+ auto addResult = hashCountedSet.add(WTFMove(ptr2));
+ EXPECT_FALSE(addResult.isNewEntry);
+ }
+
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp b/Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp
index d03fb9594..222f23c5c 100644
--- a/Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp
+++ b/Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp
@@ -25,9 +25,14 @@
#include "config.h"
+#include "Counters.h"
+#include "DeletedAddressOfOperator.h"
#include "MoveOnly.h"
+#include "RefLogger.h"
+#include "Test.h"
#include <string>
#include <wtf/HashMap.h>
+#include <wtf/Ref.h>
#include <wtf/text/StringHash.h>
namespace TestWebKitAPI {
@@ -90,7 +95,7 @@ TEST(WTF_HashMap, MoveOnlyValues)
for (size_t i = 0; i < 100; ++i) {
MoveOnly moveOnly(i + 1);
- moveOnlyValues.set(i + 1, std::move(moveOnly));
+ moveOnlyValues.set(i + 1, WTFMove(moveOnly));
}
for (size_t i = 0; i < 100; ++i) {
@@ -113,7 +118,7 @@ TEST(WTF_HashMap, MoveOnlyKeys)
for (size_t i = 0; i < 100; ++i) {
MoveOnly moveOnly(i + 1);
- moveOnlyKeys.set(std::move(moveOnly), i + 1);
+ moveOnlyKeys.set(WTFMove(moveOnly), i + 1);
}
for (size_t i = 0; i < 100; ++i) {
@@ -139,7 +144,7 @@ TEST(WTF_HashMap, InitializerList)
{ 4, "four" },
};
- EXPECT_EQ(4, map.size());
+ EXPECT_EQ(4u, map.size());
EXPECT_EQ("one", map.get(1));
EXPECT_EQ("two", map.get(2));
@@ -148,4 +153,773 @@ TEST(WTF_HashMap, InitializerList)
EXPECT_EQ(std::string(), map.get(5));
}
+TEST(WTF_HashMap, EfficientGetter)
+{
+ HashMap<unsigned, CopyMoveCounter> map;
+ map.set(1, CopyMoveCounter());
+
+ {
+ CopyMoveCounter::TestingScope scope;
+ map.get(1);
+ EXPECT_EQ(0U, CopyMoveCounter::constructionCount);
+ EXPECT_EQ(1U, CopyMoveCounter::copyCount);
+ EXPECT_EQ(0U, CopyMoveCounter::moveCount);
+ }
+
+ {
+ CopyMoveCounter::TestingScope scope;
+ map.get(2);
+ EXPECT_EQ(1U, CopyMoveCounter::constructionCount);
+ EXPECT_EQ(0U, CopyMoveCounter::copyCount);
+ EXPECT_EQ(1U, CopyMoveCounter::moveCount);
+ }
+}
+
+TEST(WTF_HashMap, UniquePtrKey)
+{
+ ConstructorDestructorCounter::TestingScope scope;
+
+ HashMap<std::unique_ptr<ConstructorDestructorCounter>, int> map;
+
+ auto uniquePtr = std::make_unique<ConstructorDestructorCounter>();
+ map.add(WTFMove(uniquePtr), 2);
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
+
+ map.clear();
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount);
+}
+
+TEST(WTF_HashMap, UniquePtrKey_CustomDeleter)
+{
+ ConstructorDestructorCounter::TestingScope constructorDestructorCounterScope;
+ DeleterCounter<ConstructorDestructorCounter>::TestingScope deleterCounterScope;
+
+ HashMap<std::unique_ptr<ConstructorDestructorCounter, DeleterCounter<ConstructorDestructorCounter>>, int> map;
+
+ std::unique_ptr<ConstructorDestructorCounter, DeleterCounter<ConstructorDestructorCounter>> uniquePtr(new ConstructorDestructorCounter(), DeleterCounter<ConstructorDestructorCounter>());
+ map.add(WTFMove(uniquePtr), 2);
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
+
+ EXPECT_EQ(0u, DeleterCounter<ConstructorDestructorCounter>::deleterCount());
+
+ map.clear();
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount);
+
+ EXPECT_EQ(1u, DeleterCounter<ConstructorDestructorCounter>::deleterCount());
+}
+
+TEST(WTF_HashMap, UniquePtrKey_FindUsingRawPointer)
+{
+ HashMap<std::unique_ptr<int>, int> map;
+
+ auto uniquePtr = std::make_unique<int>(5);
+ int* ptr = uniquePtr.get();
+ map.add(WTFMove(uniquePtr), 2);
+
+ auto it = map.find(ptr);
+ ASSERT_TRUE(it != map.end());
+ EXPECT_EQ(ptr, it->key.get());
+ EXPECT_EQ(2, it->value);
+}
+
+TEST(WTF_HashMap, UniquePtrKey_ContainsUsingRawPointer)
+{
+ HashMap<std::unique_ptr<int>, int> map;
+
+ auto uniquePtr = std::make_unique<int>(5);
+ int* ptr = uniquePtr.get();
+ map.add(WTFMove(uniquePtr), 2);
+
+ EXPECT_EQ(true, map.contains(ptr));
+}
+
+TEST(WTF_HashMap, UniquePtrKey_GetUsingRawPointer)
+{
+ HashMap<std::unique_ptr<int>, int> map;
+
+ auto uniquePtr = std::make_unique<int>(5);
+ int* ptr = uniquePtr.get();
+ map.add(WTFMove(uniquePtr), 2);
+
+ int value = map.get(ptr);
+ EXPECT_EQ(2, value);
+}
+
+TEST(WTF_HashMap, UniquePtrKey_RemoveUsingRawPointer)
+{
+ ConstructorDestructorCounter::TestingScope scope;
+
+ HashMap<std::unique_ptr<ConstructorDestructorCounter>, int> map;
+
+ auto uniquePtr = std::make_unique<ConstructorDestructorCounter>();
+ ConstructorDestructorCounter* ptr = uniquePtr.get();
+ map.add(WTFMove(uniquePtr), 2);
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
+
+ bool result = map.remove(ptr);
+ EXPECT_EQ(true, result);
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount);
+}
+
+TEST(WTF_HashMap, UniquePtrKey_TakeUsingRawPointer)
+{
+ ConstructorDestructorCounter::TestingScope scope;
+
+ HashMap<std::unique_ptr<ConstructorDestructorCounter>, int> map;
+
+ auto uniquePtr = std::make_unique<ConstructorDestructorCounter>();
+ ConstructorDestructorCounter* ptr = uniquePtr.get();
+ map.add(WTFMove(uniquePtr), 2);
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
+
+ int result = map.take(ptr);
+ EXPECT_EQ(2, result);
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount);
+}
+
+TEST(WTF_HashMap, RefPtrKey_Add)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+ RefPtr<RefLogger> ptr(&a);
+ map.add(ptr, 0);
+
+ ASSERT_STREQ("ref(a) ref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, RefPtrKey_AddUsingRelease)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+ RefPtr<RefLogger> ptr(&a);
+ map.add(WTFMove(ptr), 0);
+
+ EXPECT_STREQ("ref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, RefPtrKey_AddUsingMove)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+ RefPtr<RefLogger> ptr(&a);
+ map.add(WTFMove(ptr), 0);
+
+ EXPECT_STREQ("ref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, RefPtrKey_AddUsingRaw)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+ RefPtr<RefLogger> ptr(&a);
+ map.add(ptr.get(), 0);
+
+ EXPECT_STREQ("ref(a) ref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, RefPtrKey_AddKeyAlreadyPresent)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+
+ {
+ RefPtr<RefLogger> ptr(&a);
+ map.add(ptr, 0);
+ }
+
+ EXPECT_STREQ("ref(a) ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr2(&a);
+ auto addResult = map.add(ptr2, 0);
+ EXPECT_FALSE(addResult.isNewEntry);
+ }
+
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, RefPtrKey_AddUsingReleaseKeyAlreadyPresent)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+
+ {
+ RefPtr<RefLogger> ptr(&a);
+ map.add(ptr, 0);
+ }
+
+ EXPECT_STREQ("ref(a) ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr2(&a);
+ auto addResult = map.add(WTFMove(ptr2), 0);
+ EXPECT_FALSE(addResult.isNewEntry);
+ }
+
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, RefPtrKey_AddUsingMoveKeyAlreadyPresent)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+
+ {
+ RefPtr<RefLogger> ptr(&a);
+ map.add(ptr, 0);
+ }
+
+ EXPECT_STREQ("ref(a) ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr2(&a);
+ auto addResult = map.add(WTFMove(ptr2), 0);
+ EXPECT_FALSE(addResult.isNewEntry);
+ }
+
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, RefPtrKey_Set)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+ RefPtr<RefLogger> ptr(&a);
+ map.set(ptr, 0);
+
+ ASSERT_STREQ("ref(a) ref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, RefPtrKey_SetUsingRelease)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+ RefPtr<RefLogger> ptr(&a);
+ map.set(WTFMove(ptr), 0);
+
+ EXPECT_STREQ("ref(a) ", takeLogStr().c_str());
+}
+
+
+TEST(WTF_HashMap, RefPtrKey_SetUsingMove)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+ RefPtr<RefLogger> ptr(&a);
+ map.set(WTFMove(ptr), 0);
+
+ EXPECT_STREQ("ref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, RefPtrKey_SetUsingRaw)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+ RefPtr<RefLogger> ptr(&a);
+ map.set(ptr.get(), 0);
+
+ EXPECT_STREQ("ref(a) ref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, RefPtrKey_SetKeyAlreadyPresent)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+
+ RefPtr<RefLogger> ptr(&a);
+ map.set(ptr, 0);
+
+ EXPECT_STREQ("ref(a) ref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr2(&a);
+ auto addResult = map.set(ptr2, 1);
+ EXPECT_FALSE(addResult.isNewEntry);
+ EXPECT_EQ(1, map.get(ptr.get()));
+ }
+
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, RefPtrKey_SetUsingReleaseKeyAlreadyPresent)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+
+ RefPtr<RefLogger> ptr(&a);
+ map.set(ptr, 0);
+
+ EXPECT_STREQ("ref(a) ref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr2(&a);
+ auto addResult = map.set(WTFMove(ptr2), 1);
+ EXPECT_FALSE(addResult.isNewEntry);
+ EXPECT_EQ(1, map.get(ptr.get()));
+ }
+
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, RefPtrKey_SetUsingMoveKeyAlreadyPresent)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+
+ RefPtr<RefLogger> ptr(&a);
+ map.set(ptr, 0);
+
+ EXPECT_STREQ("ref(a) ref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr2(&a);
+ auto addResult = map.set(WTFMove(ptr2), 1);
+ EXPECT_FALSE(addResult.isNewEntry);
+ EXPECT_EQ(1, map.get(ptr.get()));
+ }
+
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, Ensure)
+{
+ HashMap<unsigned, unsigned> map;
+ {
+ auto addResult = map.ensure(1, [] { return 1; });
+ EXPECT_EQ(1u, addResult.iterator->value);
+ EXPECT_EQ(1u, addResult.iterator->key);
+ EXPECT_TRUE(addResult.isNewEntry);
+ auto addResult2 = map.ensure(1, [] { return 2; });
+ EXPECT_EQ(1u, addResult2.iterator->value);
+ EXPECT_EQ(1u, addResult2.iterator->key);
+ EXPECT_FALSE(addResult2.isNewEntry);
+ }
+}
+
+TEST(WTF_HashMap, Ensure_MoveOnlyValues)
+{
+ HashMap<unsigned, MoveOnly> moveOnlyValues;
+ {
+ auto addResult = moveOnlyValues.ensure(1, [] { return MoveOnly(1); });
+ EXPECT_EQ(1u, addResult.iterator->value.value());
+ EXPECT_EQ(1u, addResult.iterator->key);
+ EXPECT_TRUE(addResult.isNewEntry);
+ auto addResult2 = moveOnlyValues.ensure(1, [] { return MoveOnly(2); });
+ EXPECT_EQ(1u, addResult2.iterator->value.value());
+ EXPECT_EQ(1u, addResult2.iterator->key);
+ EXPECT_FALSE(addResult2.isNewEntry);
+ }
+}
+
+TEST(WTF_HashMap, Ensure_UniquePointer)
+{
+ HashMap<unsigned, std::unique_ptr<unsigned>> map;
+ {
+ auto addResult = map.ensure(1, [] { return std::make_unique<unsigned>(1); });
+ EXPECT_EQ(1u, *map.get(1));
+ EXPECT_EQ(1u, *addResult.iterator->value.get());
+ EXPECT_EQ(1u, addResult.iterator->key);
+ EXPECT_TRUE(addResult.isNewEntry);
+ auto addResult2 = map.ensure(1, [] { return std::make_unique<unsigned>(2); });
+ EXPECT_EQ(1u, *map.get(1));
+ EXPECT_EQ(1u, *addResult2.iterator->value.get());
+ EXPECT_EQ(1u, addResult2.iterator->key);
+ EXPECT_FALSE(addResult2.isNewEntry);
+ }
+}
+
+TEST(WTF_HashMap, Ensure_RefPtr)
+{
+ HashMap<unsigned, RefPtr<RefLogger>> map;
+
+ {
+ DerivedRefLogger a("a");
+
+ map.ensure(1, [&] { return RefPtr<RefLogger>(&a); });
+ EXPECT_STREQ("ref(a) ", takeLogStr().c_str());
+
+ map.ensure(1, [&] { return RefPtr<RefLogger>(&a); });
+ EXPECT_STREQ("", takeLogStr().c_str());
+ }
+}
+
+class ObjectWithRefLogger {
+public:
+ ObjectWithRefLogger(Ref<RefLogger>&& logger)
+ : m_logger(WTFMove(logger))
+ {
+ }
+
+ Ref<RefLogger> m_logger;
+};
+
+
+void testMovingUsingEnsure(Ref<RefLogger>&& logger)
+{
+ HashMap<unsigned, std::unique_ptr<ObjectWithRefLogger>> map;
+
+ map.ensure(1, [&] { return std::make_unique<ObjectWithRefLogger>(WTFMove(logger)); });
+}
+
+void testMovingUsingAdd(Ref<RefLogger>&& logger)
+{
+ HashMap<unsigned, std::unique_ptr<ObjectWithRefLogger>> map;
+
+ auto& slot = map.add(1, nullptr).iterator->value;
+ slot = std::make_unique<ObjectWithRefLogger>(WTFMove(logger));
+}
+
+TEST(WTF_HashMap, Ensure_LambdasCapturingByReference)
+{
+ {
+ DerivedRefLogger a("a");
+ Ref<RefLogger> ref(a);
+ testMovingUsingEnsure(WTFMove(ref));
+
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+ }
+
+ {
+ DerivedRefLogger a("a");
+ Ref<RefLogger> ref(a);
+ testMovingUsingAdd(WTFMove(ref));
+
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+ }
+}
+
+
+TEST(WTF_HashMap, ValueIsDestructedOnRemove)
+{
+ struct DestructorObserver {
+ DestructorObserver() = default;
+
+ DestructorObserver(bool* destructed)
+ : destructed(destructed)
+ {
+ }
+
+ ~DestructorObserver()
+ {
+ if (destructed)
+ *destructed = true;
+ }
+
+ DestructorObserver(DestructorObserver&& other)
+ : destructed(other.destructed)
+ {
+ other.destructed = nullptr;
+ }
+
+ DestructorObserver& operator=(DestructorObserver&& other)
+ {
+ destructed = other.destructed;
+ other.destructed = nullptr;
+ return *this;
+ }
+
+ bool* destructed { nullptr };
+ };
+
+ HashMap<int, DestructorObserver> map;
+
+ bool destructed = false;
+ map.add(5, DestructorObserver { &destructed });
+
+ EXPECT_FALSE(destructed);
+
+ bool removeResult = map.remove(5);
+
+ EXPECT_TRUE(removeResult);
+ EXPECT_TRUE(destructed);
+}
+
+TEST(WTF_HashMap, RefPtrNotZeroedBeforeDeref)
+{
+ struct DerefObserver {
+ NEVER_INLINE void ref()
+ {
+ ++count;
+ }
+ NEVER_INLINE void deref()
+ {
+ --count;
+ observedBucket = bucketAddress->get();
+ }
+ unsigned count { 1 };
+ const RefPtr<DerefObserver>* bucketAddress { nullptr };
+ const DerefObserver* observedBucket { nullptr };
+ };
+
+ auto observer = std::make_unique<DerefObserver>();
+
+ HashMap<RefPtr<DerefObserver>, int> map;
+ map.add(adoptRef(observer.get()), 5);
+
+ auto iterator = map.find(observer.get());
+ EXPECT_TRUE(iterator != map.end());
+
+ observer->bucketAddress = &iterator->key;
+
+ EXPECT_TRUE(observer->observedBucket == nullptr);
+ EXPECT_TRUE(map.remove(observer.get()));
+
+ // It if fine to either leave the old value intact at deletion or already set it to the deleted
+ // value.
+ // A zero would be a incorrect outcome as it would mean we nulled the bucket before an opaque
+ // call.
+ EXPECT_TRUE(observer->observedBucket == observer.get() || observer->observedBucket == RefPtr<DerefObserver>::hashTableDeletedValue());
+ EXPECT_EQ(observer->count, 0u);
+}
+
+TEST(WTF_HashMap, Ref_Key)
+{
+ {
+ HashMap<Ref<RefLogger>, int> map;
+
+ RefLogger a("a");
+ Ref<RefLogger> ref(a);
+ map.add(WTFMove(ref), 1);
+ }
+
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ HashMap<Ref<RefLogger>, int> map;
+
+ RefLogger a("a");
+ Ref<RefLogger> ref(a);
+ map.set(WTFMove(ref), 1);
+ }
+
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ HashMap<Ref<RefLogger>, int> map;
+
+ RefLogger a("a");
+ Ref<RefLogger> refA(a);
+ map.add(WTFMove(refA), 1);
+
+ Ref<RefLogger> refA2(a);
+ map.set(WTFMove(refA2), 1);
+ }
+
+ ASSERT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ HashMap<Ref<RefLogger>, int> map;
+
+ RefLogger a("a");
+ Ref<RefLogger> ref(a);
+ map.ensure(WTFMove(ref), []() {
+ return 1;
+ });
+ }
+
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ HashMap<Ref<RefLogger>, int> map;
+
+ RefLogger a("a");
+ Ref<RefLogger> ref(a);
+ map.add(WTFMove(ref), 1);
+
+ auto it = map.find(&a);
+ ASSERT_TRUE(it != map.end());
+
+ ASSERT_EQ(it->key.ptr(), &a);
+ ASSERT_EQ(it->value, 1);
+ }
+
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ HashMap<Ref<RefLogger>, int> map;
+
+ RefLogger a("a");
+ Ref<RefLogger> ref(a);
+ map.add(WTFMove(ref), 1);
+
+ map.remove(&a);
+ }
+
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ HashMap<Ref<RefLogger>, int> map;
+
+ RefLogger a("a");
+ Ref<RefLogger> ref(a);
+ map.add(WTFMove(ref), 1);
+
+ int i = map.take(&a);
+ ASSERT_EQ(i, 1);
+ }
+
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ HashMap<Ref<RefLogger>, int> map;
+ for (int i = 0; i < 64; ++i) {
+ Ref<RefLogger> ref = adoptRef(*new RefLogger("a"));
+ auto* pointer = ref.ptr();
+ map.add(WTFMove(ref), i + 1);
+ ASSERT_TRUE(map.contains(pointer));
+ }
+ }
+
+ ASSERT_STREQ("deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, Ref_Value)
+{
+ {
+ HashMap<int, Ref<RefLogger>> map;
+
+ RefLogger a("a");
+ Ref<RefLogger> ref(a);
+ map.add(1, WTFMove(ref));
+ }
+
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ HashMap<int, Ref<RefLogger>> map;
+
+ RefLogger a("a");
+ Ref<RefLogger> ref(a);
+ map.set(1, WTFMove(ref));
+ }
+
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ HashMap<int, Ref<RefLogger>> map;
+
+ RefLogger a("a");
+ Ref<RefLogger> refA(a);
+ map.add(1, WTFMove(refA));
+
+ RefLogger b("b");
+ Ref<RefLogger> refB(b);
+ map.set(1, WTFMove(refB));
+ }
+
+ ASSERT_STREQ("ref(a) ref(b) deref(a) deref(b) ", takeLogStr().c_str());
+
+ {
+ HashMap<int, Ref<RefLogger>> map;
+
+ RefLogger a("a");
+ Ref<RefLogger> ref(a);
+ map.add(1, WTFMove(ref));
+
+ auto aGet = map.get(1);
+ ASSERT_EQ(aGet, &a);
+ }
+
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ HashMap<int, Ref<RefLogger>> map;
+
+ auto emptyGet = map.get(1);
+ ASSERT_TRUE(emptyGet == nullptr);
+ }
+
+ {
+ HashMap<int, Ref<RefLogger>> map;
+
+ RefLogger a("a");
+ Ref<RefLogger> ref(a);
+ map.add(1, WTFMove(ref));
+
+ auto aOut = map.take(1);
+ ASSERT_TRUE(static_cast<bool>(aOut));
+ ASSERT_EQ(&a, aOut.value().ptr());
+ }
+
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ HashMap<int, Ref<RefLogger>> map;
+
+ auto emptyTake = map.take(1);
+ ASSERT_FALSE(static_cast<bool>(emptyTake));
+ }
+
+ {
+ HashMap<int, Ref<RefLogger>> map;
+
+ RefLogger a("a");
+ Ref<RefLogger> ref(a);
+ map.add(1, WTFMove(ref));
+ map.remove(1);
+ }
+
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ HashMap<int, Ref<RefLogger>> map;
+
+ RefLogger a("a");
+ map.ensure(1, [&]() mutable {
+ Ref<RefLogger> ref(a);
+ return ref;
+ });
+ }
+
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ HashMap<int, Ref<RefLogger>> map;
+ for (int i = 0; i < 64; ++i) {
+ Ref<RefLogger> ref = adoptRef(*new RefLogger("a"));
+ map.add(i + 1, WTFMove(ref));
+ ASSERT_TRUE(map.contains(i + 1));
+ }
+ }
+
+ ASSERT_STREQ("deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, DeletedAddressOfOperator)
+{
+ HashMap<int, DeletedAddressOfOperator> map1;
+ for (auto& value : map1.values())
+ (void)value;
+}
+
} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/HashSet.cpp b/Tools/TestWebKitAPI/Tests/WTF/HashSet.cpp
index 88e7d075f..3d25057f8 100644
--- a/Tools/TestWebKitAPI/Tests/WTF/HashSet.cpp
+++ b/Tools/TestWebKitAPI/Tests/WTF/HashSet.cpp
@@ -25,9 +25,12 @@
#include "config.h"
+#include "Counters.h"
+#include "DeletedAddressOfOperator.h"
#include "MoveOnly.h"
+#include "RefLogger.h"
#include <wtf/HashSet.h>
-
+#include <wtf/RefPtr.h>
namespace TestWebKitAPI {
@@ -43,7 +46,7 @@ void testInitialCapacity()
HashSet<int, DefaultHash<int>::Hash, InitialCapacityTestHashTraits<initialCapacity> > testSet;
// Initial capacity is null.
- ASSERT_EQ(0, testSet.capacity());
+ ASSERT_EQ(0u, testSet.capacity());
// Adding items up to size should never change the capacity.
for (size_t i = 0; i < size; ++i) {
@@ -84,7 +87,7 @@ TEST(WTF_HashSet, MoveOnly)
for (size_t i = 0; i < 100; ++i) {
MoveOnly moveOnly(i + 1);
- hashSet.add(std::move(moveOnly));
+ hashSet.add(WTFMove(moveOnly));
}
for (size_t i = 0; i < 100; ++i)
@@ -96,11 +99,354 @@ TEST(WTF_HashSet, MoveOnly)
EXPECT_TRUE(hashSet.isEmpty());
for (size_t i = 0; i < 100; ++i)
- hashSet.add(std::move(MoveOnly(i + 1)));
+ hashSet.add(MoveOnly(i + 1));
for (size_t i = 0; i < 100; ++i)
EXPECT_TRUE(hashSet.take(MoveOnly(i + 1)) == MoveOnly(i + 1));
+ EXPECT_TRUE(hashSet.isEmpty());
+
+ for (size_t i = 0; i < 100; ++i)
+ hashSet.add(MoveOnly(i + 1));
+
+ HashSet<MoveOnly> secondSet;
+
+ for (size_t i = 0; i < 100; ++i)
+ secondSet.add(hashSet.takeAny());
+
+ EXPECT_TRUE(hashSet.isEmpty());
+
+ for (size_t i = 0; i < 100; ++i)
+ EXPECT_TRUE(secondSet.contains(MoveOnly(i + 1)));
+}
+
+
+TEST(WTF_HashSet, UniquePtrKey)
+{
+ ConstructorDestructorCounter::TestingScope scope;
+
+ HashSet<std::unique_ptr<ConstructorDestructorCounter>> set;
+
+ auto uniquePtr = std::make_unique<ConstructorDestructorCounter>();
+ set.add(WTFMove(uniquePtr));
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
+
+ set.clear();
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount);
+}
+
+TEST(WTF_HashSet, UniquePtrKey_FindUsingRawPointer)
+{
+ HashSet<std::unique_ptr<int>> set;
+
+ auto uniquePtr = std::make_unique<int>(5);
+ int* ptr = uniquePtr.get();
+ set.add(WTFMove(uniquePtr));
+
+ auto it = set.find(ptr);
+ ASSERT_TRUE(it != set.end());
+ EXPECT_EQ(ptr, it->get());
+ EXPECT_EQ(5, *it->get());
+}
+
+TEST(WTF_HashSet, UniquePtrKey_ContainsUsingRawPointer)
+{
+ HashSet<std::unique_ptr<int>> set;
+
+ auto uniquePtr = std::make_unique<int>(5);
+ int* ptr = uniquePtr.get();
+ set.add(WTFMove(uniquePtr));
+
+ EXPECT_EQ(true, set.contains(ptr));
+}
+
+TEST(WTF_HashSet, UniquePtrKey_RemoveUsingRawPointer)
+{
+ ConstructorDestructorCounter::TestingScope scope;
+
+ HashSet<std::unique_ptr<ConstructorDestructorCounter>> set;
+
+ auto uniquePtr = std::make_unique<ConstructorDestructorCounter>();
+ ConstructorDestructorCounter* ptr = uniquePtr.get();
+ set.add(WTFMove(uniquePtr));
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
+
+ bool result = set.remove(ptr);
+ EXPECT_EQ(true, result);
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount);
+}
+
+TEST(WTF_HashSet, UniquePtrKey_TakeUsingRawPointer)
+{
+ ConstructorDestructorCounter::TestingScope scope;
+
+ HashSet<std::unique_ptr<ConstructorDestructorCounter>> set;
+
+ auto uniquePtr = std::make_unique<ConstructorDestructorCounter>();
+ ConstructorDestructorCounter* ptr = uniquePtr.get();
+ set.add(WTFMove(uniquePtr));
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
+
+ auto result = set.take(ptr);
+ EXPECT_EQ(ptr, result.get());
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
+
+ result = nullptr;
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount);
+}
+
+TEST(WTF_HashSet, CopyEmpty)
+{
+ {
+ HashSet<unsigned> foo;
+ HashSet<unsigned> bar(foo);
+
+ EXPECT_EQ(0u, bar.capacity());
+ EXPECT_EQ(0u, bar.size());
+ }
+ {
+ HashSet<unsigned> foo({ 1, 5, 64, 42 });
+ EXPECT_EQ(4u, foo.size());
+ foo.remove(1);
+ foo.remove(5);
+ foo.remove(42);
+ foo.remove(64);
+ HashSet<unsigned> bar(foo);
+
+ EXPECT_EQ(0u, bar.capacity());
+ EXPECT_EQ(0u, bar.size());
+ }
+}
+
+TEST(WTF_HashSet, CopyAllocateAtLeastMinimumCapacity)
+{
+ HashSet<unsigned> foo({ 42 });
+ EXPECT_EQ(1u, foo.size());
+ HashSet<unsigned> bar(foo);
+
+ EXPECT_EQ(8u, bar.capacity());
+ EXPECT_EQ(1u, bar.size());
+}
+
+TEST(WTF_HashSet, CopyCapacityIsNotOnBoundary)
+{
+ // Starting at 4 because the minimum size is 8.
+ // With a size of 8, a medium load can be up to 3.3333->3.
+ // Adding 1 to 3 would reach max load.
+ // While correct, that's not really what we care about here.
+ for (unsigned size = 4; size < 100; ++size) {
+ HashSet<unsigned> source;
+ for (unsigned i = 1; i < size + 1; ++i)
+ source.add(i);
+
+ HashSet<unsigned> copy1(source);
+ HashSet<unsigned> copy2(source);
+ HashSet<unsigned> copy3(source);
+
+ EXPECT_EQ(size, copy1.size());
+ EXPECT_EQ(size, copy2.size());
+ EXPECT_EQ(size, copy3.size());
+ for (unsigned i = 1; i < size + 1; ++i) {
+ EXPECT_TRUE(copy1.contains(i));
+ EXPECT_TRUE(copy2.contains(i));
+ EXPECT_TRUE(copy3.contains(i));
+ }
+ EXPECT_FALSE(copy1.contains(size + 2));
+ EXPECT_FALSE(copy2.contains(size + 2));
+ EXPECT_FALSE(copy3.contains(size + 2));
+
+ EXPECT_TRUE(copy2.remove(1));
+ EXPECT_EQ(copy1.capacity(), copy2.capacity());
+ EXPECT_FALSE(copy2.contains(1));
+
+ EXPECT_TRUE(copy3.add(size + 2).isNewEntry);
+ EXPECT_EQ(copy1.capacity(), copy3.capacity());
+ EXPECT_TRUE(copy3.contains(size + 2));
+ }
+}
+
+TEST(WTF_HashSet, RefPtrNotZeroedBeforeDeref)
+{
+ struct DerefObserver {
+ NEVER_INLINE void ref()
+ {
+ ++count;
+ }
+ NEVER_INLINE void deref()
+ {
+ --count;
+ observedBucket = bucketAddress->get();
+ }
+ unsigned count { 1 };
+ const RefPtr<DerefObserver>* bucketAddress { nullptr };
+ const DerefObserver* observedBucket { nullptr };
+ };
+
+ auto observer = std::make_unique<DerefObserver>();
+
+ HashSet<RefPtr<DerefObserver>> set;
+ set.add(adoptRef(observer.get()));
+
+ auto iterator = set.find(observer.get());
+ EXPECT_TRUE(iterator != set.end());
+
+ observer->bucketAddress = iterator.get();
+
+ EXPECT_TRUE(observer->observedBucket == nullptr);
+ EXPECT_TRUE(set.remove(observer.get()));
+
+ // It if fine to either leave the old value intact at deletion or already set it to the deleted
+ // value.
+ // A zero would be a incorrect outcome as it would mean we nulled the bucket before an opaque
+ // call.
+ EXPECT_TRUE(observer->observedBucket == observer.get() || observer->observedBucket == RefPtr<DerefObserver>::hashTableDeletedValue());
+ EXPECT_EQ(observer->count, 0u);
+}
+
+
+TEST(WTF_HashSet, UniquePtrNotZeroedBeforeDestructor)
+{
+ struct DestructorObserver {
+ ~DestructorObserver()
+ {
+ observe();
+ }
+ std::function<void()> observe;
+ };
+
+ const std::unique_ptr<DestructorObserver>* bucketAddress = nullptr;
+ const DestructorObserver* observedBucket = nullptr;
+ std::unique_ptr<DestructorObserver> observer(new DestructorObserver { [&]() {
+ observedBucket = bucketAddress->get();
+ }});
+
+ const DestructorObserver* observerAddress = observer.get();
+
+ HashSet<std::unique_ptr<DestructorObserver>> set;
+ auto addResult = set.add(WTFMove(observer));
+
+ EXPECT_TRUE(addResult.isNewEntry);
+ EXPECT_TRUE(observedBucket == nullptr);
+
+ bucketAddress = addResult.iterator.get();
+
+ EXPECT_TRUE(observedBucket == nullptr);
+ EXPECT_TRUE(set.remove(*addResult.iterator));
+
+ EXPECT_TRUE(observedBucket == observerAddress || observedBucket == reinterpret_cast<const DestructorObserver*>(-1));
+}
+
+TEST(WTF_HashSet, Ref)
+{
+ {
+ HashSet<Ref<RefLogger>> set;
+
+ RefLogger a("a");
+ Ref<RefLogger> ref(a);
+ set.add(WTFMove(ref));
+ }
+
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ HashSet<Ref<RefLogger>> set;
+
+ RefLogger a("a");
+ Ref<RefLogger> ref(a);
+ set.add(ref.copyRef());
+ }
+
+ ASSERT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ HashSet<Ref<RefLogger>> set;
+
+ RefLogger a("a");
+ Ref<RefLogger> ref(a);
+ set.add(WTFMove(ref));
+ set.remove(&a);
+ }
+
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ HashSet<Ref<RefLogger>> set;
+
+ RefLogger a("a");
+ Ref<RefLogger> ref(a);
+ set.add(WTFMove(ref));
+
+ auto aOut = set.take(&a);
+ ASSERT_TRUE(static_cast<bool>(aOut));
+ ASSERT_EQ(&a, aOut.value().ptr());
+ }
+
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ HashSet<Ref<RefLogger>> set;
+
+ RefLogger a("a");
+ Ref<RefLogger> ref(a);
+ set.add(WTFMove(ref));
+
+ auto aOut = set.takeAny();
+ ASSERT_TRUE(static_cast<bool>(aOut));
+ ASSERT_EQ(&a, aOut.value().ptr());
+ }
+
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ HashSet<Ref<RefLogger>> set;
+ auto emptyTake = set.takeAny();
+ ASSERT_FALSE(static_cast<bool>(emptyTake));
+ }
+
+ {
+ HashSet<Ref<RefLogger>> set;
+
+ RefLogger a("a");
+ Ref<RefLogger> ref(a);
+ set.add(WTFMove(ref));
+
+ ASSERT_TRUE(set.contains(&a));
+ }
+
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ HashSet<Ref<RefLogger>> set;
+ for (int i = 0; i < 64; ++i) {
+ Ref<RefLogger> ref = adoptRef(*new RefLogger("a"));
+ auto* pointer = ref.ptr();
+ set.add(WTFMove(ref));
+ ASSERT_TRUE(set.contains(pointer));
+ }
+ }
+ ASSERT_STREQ("deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashSet, DeletedAddressOfOperator)
+{
+ HashSet<DeletedAddressOfOperator> set1;
+ set1.add(10);
+
+ set1.remove(10);
}
} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/LEBDecoder.cpp b/Tools/TestWebKitAPI/Tests/WTF/LEBDecoder.cpp
new file mode 100644
index 000000000..2141080c4
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/LEBDecoder.cpp
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <wtf/LEBDecoder.h>
+#include <wtf/Vector.h>
+
+namespace TestWebKitAPI {
+
+static void testUInt32LEBDecode(std::initializer_list<uint8_t> data, size_t startOffset, bool expectedStatus, uint32_t expectedResult, size_t expectedOffset)
+{
+ Vector<uint8_t> vector(data);
+ uint32_t result;
+ bool status = WTF::LEBDecoder::decodeUInt32(vector.data(), vector.size(), startOffset, result);
+ EXPECT_EQ(expectedStatus, status);
+ if (expectedStatus) {
+ EXPECT_EQ(expectedResult, result);
+ EXPECT_EQ(expectedOffset, startOffset);
+ }
+}
+
+TEST(WTF, LEBDecoderUInt32)
+{
+ // Simple tests that use all the bits in the array
+ testUInt32LEBDecode({ 0x07 }, 0, true, 0x7lu, 1lu);
+ testUInt32LEBDecode({ 0x77 }, 0, true, 0x77lu, 1lu);
+ testUInt32LEBDecode({ 0x80, 0x07 }, 0, true, 0x380lu, 2lu);
+ testUInt32LEBDecode({ 0x89, 0x12 }, 0, true, 0x909lu, 2lu);
+ testUInt32LEBDecode({ 0xf3, 0x85, 0x02 }, 0, true, 0x82f3lu, 3lu);
+ testUInt32LEBDecode({ 0xf3, 0x85, 0xff, 0x74 }, 0, true, 0xe9fc2f3lu, 4lu);
+ testUInt32LEBDecode({ 0xf3, 0x85, 0xff, 0xf4, 0x7f }, 0, true, 0xfe9fc2f3lu, 5lu);
+ // Test with extra trailing numbers
+ testUInt32LEBDecode({ 0x07, 0x80 }, 0, true, 0x7lu, 1lu);
+ testUInt32LEBDecode({ 0x07, 0x75 }, 0, true, 0x7lu, 1lu);
+ testUInt32LEBDecode({ 0xf3, 0x85, 0xff, 0x74, 0x43 }, 0, true, 0xe9fc2f3lu, 4lu);
+ testUInt32LEBDecode({ 0xf3, 0x85, 0xff, 0x74, 0x80 }, 0, true, 0xe9fc2f3lu, 4lu);
+ // Test with preceeding numbers
+ testUInt32LEBDecode({ 0xf3, 0x07 }, 1, true, 0x7lu, 2lu);
+ testUInt32LEBDecode({ 0x03, 0x07 }, 1, true, 0x7lu, 2lu);
+ testUInt32LEBDecode({ 0xf2, 0x53, 0x43, 0x67, 0x79, 0x77 }, 5, true, 0x77lu, 6lu);
+ testUInt32LEBDecode({ 0xf2, 0x53, 0x43, 0xf7, 0x84, 0x77 }, 5, true, 0x77lu, 6ul);
+ testUInt32LEBDecode({ 0xf2, 0x53, 0x43, 0xf3, 0x85, 0x02 }, 3, true, 0x82f3lu, 6lu);
+ // Test in the middle
+ testUInt32LEBDecode({ 0xf3, 0x07, 0x89 }, 1, true, 0x7lu, 2lu);
+ testUInt32LEBDecode({ 0x03, 0x07, 0x23 }, 1, true, 0x7lu, 2lu);
+ testUInt32LEBDecode({ 0xf2, 0x53, 0x43, 0x67, 0x79, 0x77, 0x43 }, 5, true, 0x77lu, 6lu);
+ testUInt32LEBDecode({ 0xf2, 0x53, 0x43, 0xf7, 0x84, 0x77, 0xf9 }, 5, true, 0x77lu, 6lu);
+ testUInt32LEBDecode({ 0xf2, 0x53, 0x43, 0xf3, 0x85, 0x02, 0xa4 }, 3, true, 0x82f3lu, 6lu);
+ // Test decode too long
+ testUInt32LEBDecode({ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }, 0, false, 0x0lu, 0lu);
+ testUInt32LEBDecode({ 0x80, 0x80, 0xab, 0x8a, 0x9a, 0xa3, 0xff }, 1, false, 0x0lu, 0lu);
+ testUInt32LEBDecode({ 0x80, 0x80, 0xab, 0x8a, 0x9a, 0xa3, 0xff }, 0, false, 0x0lu, 0lu);
+ // Test decode off end of array
+ testUInt32LEBDecode({ 0x80, 0x80, 0xab, 0x8a, 0x9a, 0xa3, 0xff }, 2, false, 0x0lu, 0lu);
+}
+
+static void testUInt64LEBDecode(std::initializer_list<uint8_t> data, size_t startOffset, bool expectedStatus, uint64_t expectedResult, size_t expectedOffset)
+{
+ Vector<uint8_t> vector(data);
+ uint64_t result;
+ bool status = WTF::LEBDecoder::decodeUInt64(vector.data(), vector.size(), startOffset, result);
+ EXPECT_EQ(expectedStatus, status);
+ if (expectedStatus) {
+ EXPECT_EQ(expectedResult, result);
+ EXPECT_EQ(expectedOffset, startOffset);
+ }
+}
+
+TEST(WTF, LEBDecoderUInt64)
+{
+ // Simple tests that use all the bits in the array
+ testUInt64LEBDecode({ 0x07 }, 0, true, 0x7lu, 1lu);
+ testUInt64LEBDecode({ 0x77 }, 0, true, 0x77lu, 1lu);
+ testUInt64LEBDecode({ 0x80, 0x07 }, 0, true, 0x380lu, 2lu);
+ testUInt64LEBDecode({ 0x89, 0x12 }, 0, true, 0x909lu, 2lu);
+ testUInt64LEBDecode({ 0xf3, 0x85, 0x02 }, 0, true, 0x82f3lu, 3lu);
+ testUInt64LEBDecode({ 0xf3, 0x85, 0xff, 0x74 }, 0, true, 0xe9fc2f3lu, 4lu);
+ testUInt64LEBDecode({ 0xf3, 0x85, 0xff, 0xf4, 0x7f }, 0, true, 0x7fe9fc2f3lu, 5lu);
+ testUInt64LEBDecode({ 0xf3, 0x85, 0xff, 0xf4, 0xff, 0x4b }, 0, true, 0x25ffe9fc2f3lu, 6lu);
+ testUInt64LEBDecode({ 0xf3, 0x85, 0xff, 0xf4, 0xff, 0xcb, 0x3a }, 0, true, 0xea5ffe9fc2f3lu, 7lu);
+ testUInt64LEBDecode({ 0xf3, 0x85, 0xff, 0xf4, 0xff, 0xcb, 0xba, 0x0f }, 0, true, 0x1eea5ffe9fc2f3lu, 8lu);
+ testUInt64LEBDecode({ 0xf3, 0x85, 0xff, 0xf4, 0xff, 0xcb, 0xba, 0x8f, 0x69 }, 0, true, 0x691eea5ffe9fc2f3lu, 9lu);
+ testUInt64LEBDecode({ 0xf3, 0x85, 0xff, 0xf4, 0xff, 0xcb, 0xba, 0x8f, 0xe9, 0x01 }, 0, true, 0xe91eea5ffe9fc2f3lu, 10lu);
+ testUInt64LEBDecode({ 0xf3, 0x85, 0xff, 0xf4, 0xff, 0xcb, 0xba, 0x8f, 0xe9, 0x70 }, 0, true, 0x691eea5ffe9fc2f3lu, 10lu);
+ // Test with extra trailing numbers
+ testUInt64LEBDecode({ 0x07, 0x80 }, 0, true, 0x7lu, 1lu);
+ testUInt64LEBDecode({ 0x07, 0x75 }, 0, true, 0x7lu, 1lu);
+ testUInt64LEBDecode({ 0xf3, 0x85, 0xff, 0x74, 0x43 }, 0, true, 0xe9fc2f3lu, 4lu);
+ testUInt64LEBDecode({ 0xf3, 0x85, 0xff, 0x74, 0x80 }, 0, true, 0xe9fc2f3lu, 4lu);
+ testUInt64LEBDecode({ 0xf3, 0x85, 0xff, 0xf4, 0xff, 0xcb, 0xba, 0x8f, 0x69, 0x45 }, 0, true, 0x691eea5ffe9fc2f3lu, 9lu);
+ // Test with preceeding numbers
+ testUInt64LEBDecode({ 0xf3, 0x07 }, 1, true, 0x7lu, 2lu);
+ testUInt64LEBDecode({ 0x03, 0x07 }, 1, true, 0x7lu, 2lu);
+ testUInt64LEBDecode({ 0xf2, 0x53, 0x43, 0x67, 0x79, 0x77 }, 5, true, 0x77lu, 6lu);
+ testUInt64LEBDecode({ 0xf2, 0x53, 0x43, 0xf7, 0x84, 0x77 }, 5, true, 0x77lu, 6ul);
+ testUInt64LEBDecode({ 0xf2, 0x53, 0x43, 0xf3, 0x85, 0x02 }, 3, true, 0x82f3lu, 6lu);
+ testUInt64LEBDecode({ 0x92, 0xf3, 0x85, 0xff, 0xf4, 0xff, 0xcb, 0xba, 0x8f, 0x69 }, 1, true, 0x691eea5ffe9fc2f3lu, 10lu);
+ // Test in the middle
+ testUInt64LEBDecode({ 0xf3, 0x07, 0x89 }, 1, true, 0x7lu, 2lu);
+ testUInt64LEBDecode({ 0x03, 0x07, 0x23 }, 1, true, 0x7lu, 2lu);
+ testUInt64LEBDecode({ 0xf2, 0x53, 0x43, 0x67, 0x79, 0x77, 0x43 }, 5, true, 0x77lu, 6lu);
+ testUInt64LEBDecode({ 0xf2, 0x53, 0x43, 0xf7, 0x84, 0x77, 0xf9 }, 5, true, 0x77lu, 6lu);
+ testUInt64LEBDecode({ 0xf2, 0x53, 0x43, 0xf3, 0x85, 0x02, 0xa4 }, 3, true, 0x82f3lu, 6lu);
+ testUInt64LEBDecode({ 0x92, 0xf3, 0x85, 0xff, 0xf4, 0xff, 0xcb, 0xba, 0x8f, 0x69, 0x85, 0x75 }, 1, true, 0x691eea5ffe9fc2f3lu, 10lu);
+ testUInt64LEBDecode({ 0x92, 0x65, 0xf3, 0x85, 0xff, 0xf4, 0xff, 0xcb, 0xba, 0x8f, 0x69, 0x85, 0x75 }, 2, true, 0x691eea5ffe9fc2f3lu, 11lu);
+ // Test decode too long
+ testUInt64LEBDecode({ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }, 0, false, 0x0lu, 0lu);
+ testUInt64LEBDecode({ 0x80, 0x80, 0xab, 0x8a, 0x9a, 0xa3, 0xa3, 0x9f, 0xd2, 0xef, 0x8a, 0x4e }, 1, false, 0x0lu, 0lu);
+ testUInt64LEBDecode({ 0x80, 0x80, 0xab, 0x8a, 0x9a, 0xa3, 0xff, 0xef, 0xd8, 0xee, 0xaa, 0xbb }, 0, false, 0x0lu, 0lu);
+ testUInt64LEBDecode({ 0xf3, 0x85, 0xff, 0xf4, 0xff, 0xcb, 0xba, 0x8f, 0xa9, 0xa8, 0x05 }, 0, false, 0x0lu, 0lu);
+ // Test decode off end of array
+ testUInt64LEBDecode({ 0x80, 0x80, 0xab, 0x8a, 0x9a, 0xa3, 0xff }, 2, false, 0x0lu, 0lu);
+ testUInt64LEBDecode({ 0x80, 0x80, 0xab, 0x8a, 0x9a, 0xa3, 0xff }, 2, false, 0x0lu, 0lu);
+ testUInt64LEBDecode({ 0x92, 0xf3, 0x85, 0xff, 0xf4, 0xff, 0xcb, 0xba, 0x8f }, 1, false, 0x0lu, 0lu);
+}
+
+static void testInt32LEBDecode(std::initializer_list<uint8_t> data, size_t startOffset, bool expectedStatus, int32_t expectedResult, size_t expectedOffset)
+{
+ Vector<uint8_t> vector(data);
+ int32_t result;
+ bool status = WTF::LEBDecoder::decodeInt32(vector.data(), vector.size(), startOffset, result);
+ EXPECT_EQ(expectedStatus, status);
+ if (expectedStatus) {
+ EXPECT_EQ(expectedResult, result);
+ EXPECT_EQ(expectedOffset, startOffset);
+ }
+}
+
+TEST(WTF, LEBDecoderInt32)
+{
+ // Simple tests that use all the bits in the array
+ testInt32LEBDecode({ 0x07 }, 0, true, 0x7, 1lu);
+ testInt32LEBDecode({ 0x77 }, 0, true, -0x9, 1lu);
+ testInt32LEBDecode({ 0x80, 0x07 }, 0, true, 0x380, 2lu);
+ testInt32LEBDecode({ 0x89, 0x12 }, 0, true, 0x909, 2lu);
+ testInt32LEBDecode({ 0xf3, 0x85, 0x02 }, 0, true, 0x82f3, 3lu);
+ testInt32LEBDecode({ 0xf3, 0x85, 0xff, 0x74 }, 0, true, 0xfe9fc2f3, 4lu);
+ testInt32LEBDecode({ 0xf3, 0x85, 0xff, 0xf4, 0x7f }, 0, true, 0xfe9fc2f3, 5lu);
+ // Test with extra trailing numbers
+ testInt32LEBDecode({ 0x07, 0x80 }, 0, true, 0x7, 1lu);
+ testInt32LEBDecode({ 0x07, 0x75 }, 0, true, 0x7, 1lu);
+ testInt32LEBDecode({ 0xf3, 0x85, 0xff, 0x74, 0x43 }, 0, true, 0xfe9fc2f3, 4lu);
+ testInt32LEBDecode({ 0xf3, 0x85, 0xff, 0x74, 0x80 }, 0, true, 0xfe9fc2f3, 4lu);
+ // Test with preceeding numbers
+ testInt32LEBDecode({ 0xf3, 0x07 }, 1, true, 0x7, 2lu);
+ testInt32LEBDecode({ 0x03, 0x07 }, 1, true, 0x7, 2lu);
+ testInt32LEBDecode({ 0xf2, 0x53, 0x43, 0x67, 0x79, 0x77 }, 5, true, -0x9, 6lu);
+ testInt32LEBDecode({ 0xf2, 0x53, 0x43, 0xf7, 0x84, 0x77 }, 5, true, -0x9, 6lu);
+ testInt32LEBDecode({ 0xf2, 0x53, 0x43, 0xf3, 0x85, 0x02 }, 3, true, 0x82f3, 6lu);
+ // Test in the middle
+ testInt32LEBDecode({ 0xf3, 0x07, 0x89 }, 1, true, 0x7, 2lu);
+ testInt32LEBDecode({ 0x03, 0x07, 0x23 }, 1, true, 0x7, 2lu);
+ testInt32LEBDecode({ 0xf2, 0x53, 0x43, 0x67, 0x79, 0x77, 0x43 }, 5, true, -0x9, 6lu);
+ testInt32LEBDecode({ 0xf2, 0x53, 0x43, 0xf7, 0x84, 0x77, 0xf9 }, 5, true, -0x9, 6lu);
+ testInt32LEBDecode({ 0xf2, 0x53, 0x43, 0xf3, 0x85, 0x02, 0xa4 }, 3, true, 0x82f3, 6lu);
+ // Test decode too long
+ testInt32LEBDecode({ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }, 0, false, 0x0, 0lu);
+ testInt32LEBDecode({ 0x80, 0x80, 0xab, 0x8a, 0x9a, 0xa3, 0xff }, 1, false, 0x0, 0lu);
+ testInt32LEBDecode({ 0x80, 0x80, 0xab, 0x8a, 0x9a, 0xa3, 0xff }, 0, false, 0x0, 0lu);
+ // Test decode off end of array
+ testInt32LEBDecode({ 0x80, 0x80, 0xab, 0x8a, 0x9a, 0xa3, 0xff }, 2, false, 0x0, 0lu);
+}
+
+static void testInt64LEBDecode(std::initializer_list<uint8_t> data, size_t startOffset, bool expectedStatus, int64_t expectedResult, size_t expectedOffset)
+{
+ Vector<uint8_t> vector(data);
+ int64_t result;
+ bool status = WTF::LEBDecoder::decodeInt64(vector.data(), vector.size(), startOffset, result);
+ EXPECT_EQ(expectedStatus, status);
+ if (expectedStatus) {
+ EXPECT_EQ(expectedResult, result);
+ EXPECT_EQ(expectedOffset, startOffset);
+ }
+}
+
+TEST(WTF, LEBDecoderInt64)
+{
+ // Simple tests that use all the bits in the array
+ testInt64LEBDecode({ 0x07 }, 0, true, 0x7, 1lu);
+ testInt64LEBDecode({ 0x77 }, 0, true, -0x9, 1lu);
+ testInt64LEBDecode({ 0x80, 0x07 }, 0, true, 0x380, 2lu);
+ testInt64LEBDecode({ 0x89, 0x12 }, 0, true, 0x909, 2lu);
+ testInt64LEBDecode({ 0xf3, 0x85, 0x02 }, 0, true, 0x82f3, 3lu);
+ testInt64LEBDecode({ 0xf3, 0x85, 0xff, 0x74 }, 0, true, 0xfffffffffe9fc2f3, 4lu);
+ testInt64LEBDecode({ 0xf3, 0x85, 0xff, 0xf4, 0x7f }, 0, true, 0xfffffffffe9fc2f3, 5lu);
+ testInt64LEBDecode({ 0xf3, 0x85, 0xff, 0xf4, 0x3f }, 0, true, 0x3fe9fc2f3, 5lu);
+ testInt64LEBDecode({ 0xf3, 0x85, 0xff, 0xf4, 0x8f, 0x1a }, 0, true, 0xd0fe9fc2f3, 6lu);
+ testInt64LEBDecode({ 0xf3, 0x85, 0xff, 0xf4, 0x8f, 0x9a, 0x80, 0x2a }, 0, true, 0x5400d0fe9fc2f3, 8lu);
+ testInt64LEBDecode({ 0xf3, 0x85, 0xff, 0xf4, 0x8f, 0x9a, 0x80, 0xaa, 0x41 }, 0, true, 0xc15400d0fe9fc2f3, 9lu);
+ testInt64LEBDecode({ 0xf3, 0x85, 0xff, 0xf4, 0x8f, 0x9a, 0x80, 0xaa, 0xc1, 0x01 }, 0, true, 0xc15400d0fe9fc2f3, 10lu);
+ testInt64LEBDecode({ 0xf3, 0x85, 0xff, 0xf4, 0x8f, 0x9a, 0x80, 0xaa, 0xc1, 0x62 }, 0, true, 0x415400d0fe9fc2f3, 10lu);
+ // Test with extra trailing numbers
+ testInt64LEBDecode({ 0x07, 0x80 }, 0, true, 0x7, 1lu);
+ testInt64LEBDecode({ 0x07, 0x75 }, 0, true, 0x7, 1lu);
+ testInt64LEBDecode({ 0xf3, 0x85, 0xff, 0x74, 0x43 }, 0, true, 0xfffffffffe9fc2f3, 4lu);
+ testInt64LEBDecode({ 0xf3, 0x85, 0xff, 0x74, 0x80 }, 0, true, 0xfffffffffe9fc2f3, 4lu);
+ // Test with preceeding numbers
+ testInt64LEBDecode({ 0xf3, 0x07 }, 1, true, 0x7, 2lu);
+ testInt64LEBDecode({ 0x03, 0x07 }, 1, true, 0x7, 2lu);
+ testInt64LEBDecode({ 0xf2, 0x53, 0x43, 0x67, 0x79, 0x77 }, 5, true, -0x9, 6lu);
+ testInt64LEBDecode({ 0xf2, 0x53, 0x43, 0xf7, 0x84, 0x77 }, 5, true, -0x9, 6lu);
+ testInt64LEBDecode({ 0xf2, 0x53, 0x43, 0xf3, 0x85, 0x02 }, 3, true, 0x82f3, 6lu);
+ // Test in the middle
+ testInt64LEBDecode({ 0xf3, 0x07, 0x89 }, 1, true, 0x7, 2lu);
+ testInt64LEBDecode({ 0x03, 0x07, 0x23 }, 1, true, 0x7, 2lu);
+ testInt64LEBDecode({ 0xf2, 0x53, 0x43, 0x67, 0x79, 0x77, 0x43 }, 5, true, -0x9, 6lu);
+ testInt64LEBDecode({ 0xf2, 0x53, 0x43, 0xf7, 0x84, 0x77, 0xf9 }, 5, true, -0x9, 6lu);
+ testInt64LEBDecode({ 0xf2, 0x53, 0x43, 0xf3, 0x85, 0x02, 0xa4 }, 3, true, 0x82f3, 6lu);
+ // Test decode too long
+ testInt64LEBDecode({ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }, 0, false, 0x0, 0lu);
+ testInt64LEBDecode({ 0x80, 0x80, 0xab, 0x8a, 0x9a, 0xa3, 0xff }, 1, false, 0x0, 0lu);
+ testInt64LEBDecode({ 0x80, 0x80, 0xab, 0x8a, 0x9a, 0xa3, 0xff }, 0, false, 0x0, 0lu);
+ // Test decode off end of array
+ testInt64LEBDecode({ 0x80, 0x80, 0xab, 0x8a, 0x9a, 0xa3, 0xff }, 2, false, 0x0, 0lu);
+}
+
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/ListHashSet.cpp b/Tools/TestWebKitAPI/Tests/WTF/ListHashSet.cpp
index a550a845b..b97d866e7 100644
--- a/Tools/TestWebKitAPI/Tests/WTF/ListHashSet.cpp
+++ b/Tools/TestWebKitAPI/Tests/WTF/ListHashSet.cpp
@@ -78,7 +78,7 @@ TEST(WTF_ListHashSet, AppendOrMoveToLastNewItems)
result = list.appendOrMoveToLast(3);
ASSERT_TRUE(result.isNewEntry);
- ASSERT_EQ(list.size(), 3);
+ ASSERT_EQ(list.size(), 3u);
// The list should be in order 1, 2, 3.
ListHashSet<int>::iterator iterator = list.begin();
@@ -99,11 +99,11 @@ TEST(WTF_ListHashSet, AppendOrMoveToLastWithDuplicates)
ASSERT_TRUE(result.isNewEntry);
result = list.appendOrMoveToLast(1);
ASSERT_FALSE(result.isNewEntry);
- ASSERT_EQ(1, list.size());
+ ASSERT_EQ(1u, list.size());
list.add(2);
list.add(3);
- ASSERT_EQ(3, list.size());
+ ASSERT_EQ(3u, list.size());
// Appending 2 move it to the end.
ASSERT_EQ(3, list.last());
@@ -118,7 +118,7 @@ TEST(WTF_ListHashSet, AppendOrMoveToLastWithDuplicates)
ASSERT_FALSE(result.isNewEntry);
result = list.appendOrMoveToLast(1);
ASSERT_FALSE(result.isNewEntry);
- ASSERT_EQ(3, list.size());
+ ASSERT_EQ(3u, list.size());
ListHashSet<int>::iterator iterator = list.begin();
ASSERT_EQ(3, *iterator);
@@ -139,7 +139,7 @@ TEST(WTF_ListHashSet, PrependOrMoveToLastNewItems)
result = list.prependOrMoveToFirst(3);
ASSERT_TRUE(result.isNewEntry);
- ASSERT_EQ(list.size(), 3);
+ ASSERT_EQ(list.size(), 3u);
// The list should be in order 3, 1, 2.
ListHashSet<int>::iterator iterator = list.begin();
@@ -160,11 +160,11 @@ TEST(WTF_ListHashSet, PrependOrMoveToLastWithDuplicates)
ASSERT_TRUE(result.isNewEntry);
result = list.prependOrMoveToFirst(1);
ASSERT_FALSE(result.isNewEntry);
- ASSERT_EQ(1, list.size());
+ ASSERT_EQ(1u, list.size());
list.add(2);
list.add(3);
- ASSERT_EQ(3, list.size());
+ ASSERT_EQ(3u, list.size());
// Prepending 2 move it to the beginning.
ASSERT_EQ(1, list.first());
@@ -179,7 +179,7 @@ TEST(WTF_ListHashSet, PrependOrMoveToLastWithDuplicates)
ASSERT_FALSE(result.isNewEntry);
result = list.prependOrMoveToFirst(3);
ASSERT_FALSE(result.isNewEntry);
- ASSERT_EQ(3, list.size());
+ ASSERT_EQ(3u, list.size());
ListHashSet<int>::iterator iterator = list.begin();
ASSERT_EQ(3, *iterator);
@@ -266,4 +266,86 @@ TEST(WTF_ListHashSet, MoveOnly)
ASSERT_TRUE(list.isEmpty());
}
+TEST(WTF_ListHashSet, MoveConstructor)
+{
+ ListHashSet<int> list;
+ list.add(1);
+ list.add(2);
+ list.add(3);
+
+ ASSERT_EQ(3U, list.size());
+ auto iterator = list.begin();
+ ASSERT_EQ(1, *iterator);
+ ++iterator;
+ ASSERT_EQ(2, *iterator);
+ ++iterator;
+ ASSERT_EQ(3, *iterator);
+ ++iterator;
+
+ ListHashSet<int> list2(WTFMove(list));
+ ASSERT_EQ(3U, list2.size());
+ auto iterator2 = list2.begin();
+ ASSERT_EQ(1, *iterator2);
+ ++iterator2;
+ ASSERT_EQ(2, *iterator2);
+ ++iterator2;
+ ASSERT_EQ(3, *iterator2);
+ ++iterator2;
+
+ ASSERT_EQ(0U, list.size());
+ ASSERT_TRUE(list.begin() == list.end());
+ list.add(4);
+ list.add(5);
+ list.add(6);
+ iterator = list.begin();
+ ASSERT_EQ(4, *iterator);
+ ++iterator;
+ ASSERT_EQ(5, *iterator);
+ ++iterator;
+ ASSERT_EQ(6, *iterator);
+ ++iterator;
+}
+
+TEST(WTF_ListHashSet, MoveAssignment)
+{
+ ListHashSet<int> list;
+ list.add(1);
+ list.add(2);
+ list.add(3);
+
+ ASSERT_EQ(3U, list.size());
+ auto iterator = list.begin();
+ ASSERT_EQ(1, *iterator);
+ ++iterator;
+ ASSERT_EQ(2, *iterator);
+ ++iterator;
+ ASSERT_EQ(3, *iterator);
+ ++iterator;
+
+ ListHashSet<int> list2;
+ list2.add(10);
+ list2 = (WTFMove(list));
+ ASSERT_EQ(3U, list2.size());
+ auto iterator2 = list2.begin();
+ ASSERT_EQ(1, *iterator2);
+ ++iterator2;
+ ASSERT_EQ(2, *iterator2);
+ ++iterator2;
+ ASSERT_EQ(3, *iterator2);
+ ++iterator2;
+
+ ASSERT_EQ(0U, list.size());
+ ASSERT_TRUE(list.begin() == list.end());
+ list.add(4);
+ list.add(5);
+ list.add(6);
+ iterator = list.begin();
+ ASSERT_EQ(4, *iterator);
+ ++iterator;
+ ASSERT_EQ(5, *iterator);
+ ++iterator;
+ ASSERT_EQ(6, *iterator);
+ ++iterator;
+}
+
} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/Lock.cpp b/Tools/TestWebKitAPI/Tests/WTF/Lock.cpp
new file mode 100644
index 000000000..5576302d6
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/Lock.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include <wtf/Lock.h>
+#include <wtf/Threading.h>
+#include <wtf/ThreadingPrimitives.h>
+#include <wtf/WordLock.h>
+
+using namespace WTF;
+
+namespace TestWebKitAPI {
+
+struct LockInspector {
+ template<typename LockType>
+ static bool isFullyReset(LockType& lock)
+ {
+ return lock.isFullyReset();
+ }
+};
+
+template<typename LockType>
+void runLockTest(unsigned numThreadGroups, unsigned numThreadsPerGroup, unsigned workPerCriticalSection, unsigned numIterations)
+{
+ std::unique_ptr<LockType[]> locks = std::make_unique<LockType[]>(numThreadGroups);
+ std::unique_ptr<double[]> words = std::make_unique<double[]>(numThreadGroups);
+ std::unique_ptr<ThreadIdentifier[]> threads = std::make_unique<ThreadIdentifier[]>(numThreadGroups * numThreadsPerGroup);
+
+ for (unsigned threadGroupIndex = numThreadGroups; threadGroupIndex--;) {
+ words[threadGroupIndex] = 0;
+
+ for (unsigned threadIndex = numThreadsPerGroup; threadIndex--;) {
+ threads[threadGroupIndex * numThreadsPerGroup + threadIndex] = createThread(
+ "Lock test thread",
+ [threadGroupIndex, &locks, &words, numIterations, workPerCriticalSection] () {
+ for (unsigned i = numIterations; i--;) {
+ locks[threadGroupIndex].lock();
+ for (unsigned j = workPerCriticalSection; j--;)
+ words[threadGroupIndex]++;
+ locks[threadGroupIndex].unlock();
+ }
+ });
+ }
+ }
+
+ for (unsigned threadIndex = numThreadGroups * numThreadsPerGroup; threadIndex--;)
+ waitForThreadCompletion(threads[threadIndex]);
+
+ double expected = 0;
+ for (uint64_t i = static_cast<uint64_t>(numIterations) * workPerCriticalSection * numThreadsPerGroup; i--;)
+ expected++;
+
+ for (unsigned threadGroupIndex = numThreadGroups; threadGroupIndex--;)
+ EXPECT_EQ(expected, words[threadGroupIndex]);
+
+ // Now test that the locks correctly reset themselves. We expect that if a single thread locks
+ // each of the locks twice in a row, then the lock should be in a pristine state.
+ for (unsigned threadGroupIndex = numThreadGroups; threadGroupIndex--;) {
+ for (unsigned i = 2; i--;) {
+ locks[threadGroupIndex].lock();
+ locks[threadGroupIndex].unlock();
+ }
+
+ EXPECT_EQ(true, LockInspector::isFullyReset(locks[threadGroupIndex]));
+ }
+}
+
+bool skipSlow()
+{
+#if PLATFORM(WIN) && !defined(NDEBUG)
+ return true;
+#else
+ return false;
+#endif
+}
+
+TEST(WTF_WordLock, UncontendedShortSection)
+{
+ runLockTest<WordLock>(1, 1, 1, 10000000);
+}
+
+TEST(WTF_WordLock, UncontendedLongSection)
+{
+ runLockTest<WordLock>(1, 1, 10000, 1000);
+}
+
+TEST(WTF_WordLock, ContendedShortSection)
+{
+ if (skipSlow())
+ return;
+ runLockTest<WordLock>(1, 10, 1, 5000000);
+}
+
+TEST(WTF_WordLock, ContendedLongSection)
+{
+ if (skipSlow())
+ return;
+ runLockTest<WordLock>(1, 10, 10000, 10000);
+}
+
+TEST(WTF_WordLock, ManyContendedShortSections)
+{
+ if (skipSlow())
+ return;
+ runLockTest<WordLock>(10, 10, 1, 500000);
+}
+
+TEST(WTF_WordLock, ManyContendedLongSections)
+{
+ if (skipSlow())
+ return;
+ runLockTest<WordLock>(10, 10, 10000, 500);
+}
+
+TEST(WTF_Lock, UncontendedShortSection)
+{
+ runLockTest<Lock>(1, 1, 1, 10000000);
+}
+
+TEST(WTF_Lock, UncontendedLongSection)
+{
+ runLockTest<Lock>(1, 1, 10000, 1000);
+}
+
+TEST(WTF_Lock, ContendedShortSection)
+{
+ if (skipSlow())
+ return;
+ runLockTest<Lock>(1, 10, 1, 10000000);
+}
+
+TEST(WTF_Lock, ContendedLongSection)
+{
+ if (skipSlow())
+ return;
+ runLockTest<Lock>(1, 10, 10000, 10000);
+}
+
+TEST(WTF_Lock, ManyContendedShortSections)
+{
+ if (skipSlow())
+ return;
+ runLockTest<Lock>(10, 10, 1, 500000);
+}
+
+TEST(WTF_Lock, ManyContendedLongSections)
+{
+ if (skipSlow())
+ return;
+ runLockTest<Lock>(10, 10, 10000, 1000);
+}
+
+TEST(WTF_Lock, ManyContendedLongerSections)
+{
+ if (skipSlow())
+ return;
+ runLockTest<Lock>(10, 10, 100000, 1);
+}
+
+TEST(WTF_Lock, SectionAddressCollision)
+{
+ if (skipSlow())
+ return;
+ runLockTest<Lock>(4, 2, 10000, 2000);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/MediaTime.cpp b/Tools/TestWebKitAPI/Tests/WTF/MediaTime.cpp
index 8e9b178af..ac8bb1c3a 100644
--- a/Tools/TestWebKitAPI/Tests/WTF/MediaTime.cpp
+++ b/Tools/TestWebKitAPI/Tests/WTF/MediaTime.cpp
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -26,24 +26,14 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#define _USE_MATH_DEFINES 1
#include "config.h"
+#include <limits>
+#include <wtf/MathExtras.h>
#include <wtf/MediaTime.h>
using namespace std;
-#if COMPILER(MSVC)
-// Work around Visual Studio 2008's lack of an INFINITY or NAN definition.
-#include <limits>
-#if !defined(INFINITY)
-#define INFINITY (numeric_limits<double>::infinity())
-#endif
-#if !defined(NAN)
-#define NAN (numeric_limits<double>::quiet_NaN())
-#endif
-#endif
-
namespace WTF {
std::ostream& operator<<(std::ostream& out, const MediaTime& val)
@@ -55,6 +45,8 @@ std::ostream& operator<<(std::ostream& out, const MediaTime& val)
out << "+infinite";
else if (val.isNegativeInfinite())
out << "-infinite";
+ else if (val.hasDoubleValue())
+ out << "double: " << val.toDouble();
else
out << "value: " << val.timeValue() << ", scale: " << val.timeScale();
return out << " }";
@@ -93,6 +85,8 @@ TEST(WTF, MediaTime)
EXPECT_EQ(MediaTime(1, 1) != MediaTime(2, 1), true);
EXPECT_EQ(MediaTime(2, 1) == MediaTime(2, 1), true);
EXPECT_EQ(MediaTime(2, 1) == MediaTime(4, 2), true);
+ EXPECT_TRUE((bool)MediaTime(1, 1));
+ EXPECT_TRUE(!MediaTime(0, 1));
// Addition Operators
EXPECT_EQ(MediaTime::positiveInfiniteTime() + MediaTime::positiveInfiniteTime(), MediaTime::positiveInfiniteTime());
@@ -166,8 +160,6 @@ TEST(WTF, MediaTime)
EXPECT_EQ(abs(MediaTime::invalidTime()), MediaTime::invalidTime());
EXPECT_EQ(abs(MediaTime(1, 1)), MediaTime(1, 1));
EXPECT_EQ(abs(MediaTime(-1, 1)), MediaTime(1, 1));
- EXPECT_EQ(abs(MediaTime(-1, -1)), MediaTime(-1, -1));
- EXPECT_EQ(abs(MediaTime(1, -1)), MediaTime(-1, -1));
// Floating Point Functions
EXPECT_EQ(MediaTime::createWithFloat(1.0f), MediaTime(1, 1));
@@ -180,25 +172,42 @@ TEST(WTF, MediaTime)
EXPECT_EQ(MediaTime(3, 2).toDouble(), 1.5);
EXPECT_EQ(MediaTime(1, 1 << 16).toFloat(), 1 / pow(2.0f, 16.0f));
EXPECT_EQ(MediaTime(1, 1 << 30).toDouble(), 1 / pow(2.0, 30.0));
- EXPECT_EQ(MediaTime::createWithDouble(M_PI, 1 << 30), MediaTime(3373259426U, 1 << 30));
- EXPECT_EQ(MediaTime::createWithFloat(INFINITY), MediaTime::positiveInfiniteTime());
- EXPECT_EQ(MediaTime::createWithFloat(-INFINITY), MediaTime::negativeInfiniteTime());
- EXPECT_EQ(MediaTime::createWithFloat(NAN), MediaTime::invalidTime());
- EXPECT_EQ(MediaTime::createWithDouble(INFINITY), MediaTime::positiveInfiniteTime());
- EXPECT_EQ(MediaTime::createWithDouble(-INFINITY), MediaTime::negativeInfiniteTime());
- EXPECT_EQ(MediaTime::createWithDouble(NAN), MediaTime::invalidTime());
+ EXPECT_EQ(MediaTime::createWithDouble(piDouble, 1 << 30), MediaTime(3373259426U, 1 << 30));
+
+ EXPECT_EQ(MediaTime::createWithFloat(std::numeric_limits<float>::infinity()), MediaTime::positiveInfiniteTime());
+ EXPECT_EQ(MediaTime::createWithFloat(-std::numeric_limits<float>::infinity()), MediaTime::negativeInfiniteTime());
+ EXPECT_EQ(MediaTime::createWithFloat(std::numeric_limits<float>::quiet_NaN()), MediaTime::invalidTime());
+
+ EXPECT_EQ(MediaTime::createWithDouble(std::numeric_limits<double>::infinity()), MediaTime::positiveInfiniteTime());
+ EXPECT_EQ(MediaTime::createWithDouble(-std::numeric_limits<double>::infinity()), MediaTime::negativeInfiniteTime());
+ EXPECT_EQ(MediaTime::createWithDouble(std::numeric_limits<double>::quiet_NaN()), MediaTime::invalidTime());
+
+ // Floating Point Round Trip
+ EXPECT_EQ(10.0123456789f, MediaTime::createWithFloat(10.0123456789f).toFloat());
+ EXPECT_EQ(10.0123456789, MediaTime::createWithDouble(10.0123456789).toDouble());
+ EXPECT_EQ(MediaTime(1, 3), MediaTime::createWithDouble(MediaTime(1, 3).toDouble()));
+
+ // Floating Point Math
+ EXPECT_EQ(1.5 + 3.3, (MediaTime::createWithDouble(1.5) + MediaTime::createWithDouble(3.3)).toDouble());
+ EXPECT_EQ(1.5 - 3.3, (MediaTime::createWithDouble(1.5) - MediaTime::createWithDouble(3.3)).toDouble());
+ EXPECT_EQ(-3.3, (-MediaTime::createWithDouble(3.3)).toDouble());
+ EXPECT_EQ(3.3 * 2, (MediaTime::createWithDouble(3.3) * 2).toDouble());
+
+ // Floating Point and non-Floating Point math
+ EXPECT_EQ(2.0, (MediaTime::createWithDouble(1.5) + MediaTime(1, 2)).toDouble());
+ EXPECT_EQ(1.0, (MediaTime::createWithDouble(1.5) - MediaTime(1, 2)).toDouble());
// Overflow Behavior
EXPECT_EQ(MediaTime::createWithFloat(pow(2.0f, 64.0f)), MediaTime::positiveInfiniteTime());
EXPECT_EQ(MediaTime::createWithFloat(-pow(2.0f, 64.0f)), MediaTime::negativeInfiniteTime());
- EXPECT_EQ(MediaTime::createWithFloat(pow(2.0f, 63.0f), 2).timeScale(), 1);
- EXPECT_EQ(MediaTime::createWithFloat(pow(2.0f, 63.0f), 3).timeScale(), 1);
+ EXPECT_EQ(MediaTime::createWithFloat(pow(2.0f, 63.0f), 2).timeScale(), 1U);
+ EXPECT_EQ(MediaTime::createWithFloat(pow(2.0f, 63.0f), 3).timeScale(), 1U);
EXPECT_EQ(MediaTime::createWithDouble(pow(2.0, 64.0)), MediaTime::positiveInfiniteTime());
EXPECT_EQ(MediaTime::createWithDouble(-pow(2.0, 64.0)), MediaTime::negativeInfiniteTime());
- EXPECT_EQ(MediaTime::createWithDouble(pow(2.0, 63.0), 2).timeScale(), 1);
- EXPECT_EQ(MediaTime::createWithDouble(pow(2.0, 63.0), 3).timeScale(), 1);
- EXPECT_EQ((MediaTime(numeric_limits<int64_t>::max(), 2) + MediaTime(numeric_limits<int64_t>::max(), 2)).timeScale(), 1);
- EXPECT_EQ((MediaTime(numeric_limits<int64_t>::min(), 2) - MediaTime(numeric_limits<int64_t>::max(), 2)).timeScale(), 1);
+ EXPECT_EQ(MediaTime::createWithDouble(pow(2.0, 63.0), 2).timeScale(), 1U);
+ EXPECT_EQ(MediaTime::createWithDouble(pow(2.0, 63.0), 3).timeScale(), 1U);
+ EXPECT_EQ((MediaTime(numeric_limits<int64_t>::max(), 2) + MediaTime(numeric_limits<int64_t>::max(), 2)).timeScale(), 1U);
+ EXPECT_EQ((MediaTime(numeric_limits<int64_t>::min(), 2) - MediaTime(numeric_limits<int64_t>::max(), 2)).timeScale(), 1U);
EXPECT_EQ(MediaTime(numeric_limits<int64_t>::max(), 1) + MediaTime(numeric_limits<int64_t>::max(), 1), MediaTime::positiveInfiniteTime());
EXPECT_EQ(MediaTime(numeric_limits<int64_t>::min(), 1) + MediaTime(numeric_limits<int64_t>::min(), 1), MediaTime::negativeInfiniteTime());
EXPECT_EQ(MediaTime(numeric_limits<int64_t>::min(), 1) - MediaTime(numeric_limits<int64_t>::max(), 1), MediaTime::negativeInfiniteTime());
diff --git a/Tools/TestWebKitAPI/Tests/WTF/MetaAllocator.cpp b/Tools/TestWebKitAPI/Tests/WTF/MetaAllocator.cpp
index 61c16d1ab..59af4f849 100644
--- a/Tools/TestWebKitAPI/Tests/WTF/MetaAllocator.cpp
+++ b/Tools/TestWebKitAPI/Tests/WTF/MetaAllocator.cpp
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -31,6 +31,10 @@
#include <wtf/MetaAllocator.h>
#include <wtf/Vector.h>
+#if OS(WINDOWS)
+#undef small
+#endif
+
using namespace WTF;
namespace TestWebKitAPI {
diff --git a/Tools/TestWebKitAPI/Tests/WTF/NakedPtr.cpp b/Tools/TestWebKitAPI/Tests/WTF/NakedPtr.cpp
new file mode 100644
index 000000000..f4b4836cd
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/NakedPtr.cpp
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "RefLogger.h"
+#include <wtf/NakedPtr.h>
+
+namespace TestWebKitAPI {
+
+// For these tests, we need a base class and a derived class. For this purpose,
+// we reuse the RefLogger and DerivedRefLogger classes.
+
+TEST(WTF_NakedPtr, Basic)
+{
+ DerivedRefLogger a("a");
+
+ NakedPtr<RefLogger> empty;
+ ASSERT_EQ(nullptr, empty.get());
+
+ {
+ NakedPtr<RefLogger> ptr(&a);
+ ASSERT_EQ(&a, ptr.get());
+ ASSERT_EQ(&a, &*ptr);
+ ASSERT_EQ(&a.name, &ptr->name);
+ }
+
+ {
+ NakedPtr<RefLogger> ptr = &a;
+ ASSERT_EQ(&a, ptr.get());
+ }
+
+ {
+ NakedPtr<RefLogger> p1 = &a;
+ NakedPtr<RefLogger> p2(p1);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+
+ {
+ NakedPtr<RefLogger> p1 = &a;
+ NakedPtr<RefLogger> p2 = p1;
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+
+ {
+ NakedPtr<RefLogger> p1 = &a;
+ NakedPtr<RefLogger> p2 = WTFMove(p1);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+
+ {
+ NakedPtr<RefLogger> p1 = &a;
+ NakedPtr<RefLogger> p2(WTFMove(p1));
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+
+ {
+ NakedPtr<DerivedRefLogger> p1 = &a;
+ NakedPtr<RefLogger> p2 = p1;
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+
+ {
+ NakedPtr<DerivedRefLogger> p1 = &a;
+ NakedPtr<RefLogger> p2 = WTFMove(p1);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+
+ {
+ NakedPtr<RefLogger> ptr(&a);
+ ASSERT_EQ(&a, ptr.get());
+ ptr.clear();
+ ASSERT_EQ(nullptr, ptr.get());
+ }
+}
+
+TEST(WTF_NakedPtr, Assignment)
+{
+ DerivedRefLogger a("a");
+ RefLogger b("b");
+ DerivedRefLogger c("c");
+
+ {
+ NakedPtr<RefLogger> p1(&a);
+ NakedPtr<RefLogger> p2(&b);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&b, p2.get());
+ p1 = p2;
+ ASSERT_EQ(&b, p1.get());
+ ASSERT_EQ(&b, p2.get());
+ }
+
+ {
+ NakedPtr<RefLogger> ptr(&a);
+ ASSERT_EQ(&a, ptr.get());
+ ptr = &b;
+ ASSERT_EQ(&b, ptr.get());
+ }
+
+ {
+ NakedPtr<RefLogger> ptr(&a);
+ ASSERT_EQ(&a, ptr.get());
+ ptr = nullptr;
+ ASSERT_EQ(nullptr, ptr.get());
+ }
+
+ {
+ NakedPtr<RefLogger> p1(&a);
+ NakedPtr<RefLogger> p2(&b);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&b, p2.get());
+ p1 = WTFMove(p2);
+ ASSERT_EQ(&b, p1.get());
+ ASSERT_EQ(&b, p2.get());
+ }
+
+ {
+ NakedPtr<RefLogger> p1(&a);
+ NakedPtr<DerivedRefLogger> p2(&c);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&c, p2.get());
+ p1 = p2;
+ ASSERT_EQ(&c, p1.get());
+ ASSERT_EQ(&c, p2.get());
+ }
+
+ {
+ NakedPtr<RefLogger> ptr(&a);
+ ASSERT_EQ(&a, ptr.get());
+ ptr = &c;
+ ASSERT_EQ(&c, ptr.get());
+ }
+
+ {
+ NakedPtr<RefLogger> p1(&a);
+ NakedPtr<DerivedRefLogger> p2(&c);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&c, p2.get());
+ p1 = WTFMove(p2);
+ ASSERT_EQ(&c, p1.get());
+ ASSERT_EQ(&c, p2.get());
+ }
+
+ {
+ NakedPtr<RefLogger> ptr(&a);
+ ASSERT_EQ(&a, ptr.get());
+ ptr = ptr;
+ ASSERT_EQ(&a, ptr.get());
+ }
+
+ {
+ NakedPtr<RefLogger> ptr(&a);
+ ASSERT_EQ(&a, ptr.get());
+#if COMPILER(CLANG)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-pragmas"
+#pragma clang diagnostic ignored "-Wself-move"
+#endif
+ ptr = WTFMove(ptr);
+#if COMPILER(CLANG)
+#pragma clang diagnostic pop
+#endif
+ ASSERT_EQ(&a, ptr.get());
+ }
+}
+
+TEST(WTF_NakedPtr, Swap)
+{
+ RefLogger a("a");
+ RefLogger b("b");
+
+ {
+ NakedPtr<RefLogger> p1(&a);
+ NakedPtr<RefLogger> p2(&b);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&b, p2.get());
+ p1.swap(p2);
+ ASSERT_EQ(&b, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+
+ {
+ NakedPtr<RefLogger> p1(&a);
+ NakedPtr<RefLogger> p2(&b);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&b, p2.get());
+ std::swap(p1, p2);
+ ASSERT_EQ(&b, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+}
+
+NakedPtr<RefLogger> nakedPtrFoo(RefLogger& logger)
+{
+ return NakedPtr<RefLogger>(&logger);
+}
+
+TEST(WTF_NakedPtr, ReturnValue)
+{
+ DerivedRefLogger a("a");
+
+ {
+ auto ptr = nakedPtrFoo(a);
+ ASSERT_EQ(&a, ptr.get());
+ ASSERT_EQ(&a, &*ptr);
+ ASSERT_EQ(&a.name, &ptr->name);
+ }
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/OptionSet.cpp b/Tools/TestWebKitAPI/Tests/WTF/OptionSet.cpp
new file mode 100644
index 000000000..f0173831b
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/OptionSet.cpp
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "Test.h"
+#include <wtf/OptionSet.h>
+
+namespace TestWebKitAPI {
+
+enum class ExampleFlags : uint64_t {
+ A = 1 << 0,
+ B = 1 << 1,
+ C = 1 << 2,
+ D = 1ULL << 31,
+ E = 1ULL << 63,
+};
+
+TEST(WTF_OptionSet, EmptySet)
+{
+ OptionSet<ExampleFlags> set;
+ EXPECT_TRUE(set.isEmpty());
+ EXPECT_FALSE(set.contains(ExampleFlags::A));
+ EXPECT_FALSE(set.contains(ExampleFlags::B));
+ EXPECT_FALSE(set.contains(ExampleFlags::C));
+ EXPECT_FALSE(set.contains(ExampleFlags::D));
+ EXPECT_FALSE(set.contains(ExampleFlags::E));
+}
+
+TEST(WTF_OptionSet, ContainsOneFlag)
+{
+ OptionSet<ExampleFlags> set = ExampleFlags::A;
+ EXPECT_FALSE(set.isEmpty());
+ EXPECT_TRUE(set.contains(ExampleFlags::A));
+ EXPECT_FALSE(set.contains(ExampleFlags::B));
+ EXPECT_FALSE(set.contains(ExampleFlags::C));
+ EXPECT_FALSE(set.contains(ExampleFlags::D));
+ EXPECT_FALSE(set.contains(ExampleFlags::E));
+}
+
+TEST(WTF_OptionSet, Equal)
+{
+ OptionSet<ExampleFlags> set { ExampleFlags::A, ExampleFlags::B };
+
+ EXPECT_TRUE((set == OptionSet<ExampleFlags> { ExampleFlags::A, ExampleFlags::B }));
+ EXPECT_TRUE((set == OptionSet<ExampleFlags> { ExampleFlags::B, ExampleFlags::A }));
+ EXPECT_FALSE(set == ExampleFlags::B);
+}
+
+TEST(WTF_OptionSet, NotEqual)
+{
+ OptionSet<ExampleFlags> set = ExampleFlags::A;
+
+ EXPECT_TRUE(set != ExampleFlags::B);
+ EXPECT_FALSE(set != ExampleFlags::A);
+}
+
+TEST(WTF_OptionSet, Minus)
+{
+ OptionSet<ExampleFlags> set { ExampleFlags::A, ExampleFlags::B, ExampleFlags::C };
+
+ EXPECT_TRUE(((set - ExampleFlags::A) == OptionSet<ExampleFlags> { ExampleFlags::B, ExampleFlags::C }));
+ EXPECT_TRUE(((set - ExampleFlags::D) == OptionSet<ExampleFlags> { ExampleFlags::A, ExampleFlags::B, ExampleFlags::C }));
+ EXPECT_TRUE((set - set).isEmpty());
+}
+
+TEST(WTF_OptionSet, ContainsTwoFlags)
+{
+ OptionSet<ExampleFlags> set { ExampleFlags::A, ExampleFlags::B };
+ EXPECT_FALSE(set.isEmpty());
+ EXPECT_TRUE(set.contains(ExampleFlags::A));
+ EXPECT_TRUE(set.contains(ExampleFlags::B));
+ EXPECT_FALSE(set.contains(ExampleFlags::C));
+ EXPECT_FALSE(set.contains(ExampleFlags::D));
+ EXPECT_FALSE(set.contains(ExampleFlags::E));
+}
+
+TEST(WTF_OptionSet, ContainsTwoFlags2)
+{
+ OptionSet<ExampleFlags> set { ExampleFlags::A, ExampleFlags::D };
+ EXPECT_FALSE(set.isEmpty());
+ EXPECT_TRUE(set.contains(ExampleFlags::A));
+ EXPECT_TRUE(set.contains(ExampleFlags::D));
+ EXPECT_FALSE(set.contains(ExampleFlags::B));
+ EXPECT_FALSE(set.contains(ExampleFlags::C));
+ EXPECT_FALSE(set.contains(ExampleFlags::E));
+}
+
+TEST(WTF_OptionSet, ContainsTwoFlags3)
+{
+ OptionSet<ExampleFlags> set { ExampleFlags::D, ExampleFlags::E };
+ EXPECT_FALSE(set.isEmpty());
+ EXPECT_TRUE(set.contains(ExampleFlags::D));
+ EXPECT_TRUE(set.contains(ExampleFlags::E));
+ EXPECT_FALSE(set.contains(ExampleFlags::A));
+ EXPECT_FALSE(set.contains(ExampleFlags::B));
+ EXPECT_FALSE(set.contains(ExampleFlags::C));
+}
+
+TEST(WTF_OptionSet, OperatorBitwiseOr)
+{
+ OptionSet<ExampleFlags> set = ExampleFlags::A;
+ set |= ExampleFlags::C;
+ EXPECT_TRUE(set.contains(ExampleFlags::A));
+ EXPECT_FALSE(set.contains(ExampleFlags::B));
+ EXPECT_TRUE(set.contains(ExampleFlags::C));
+}
+
+TEST(WTF_OptionSet, EmptyOptionSetToRawValueToOptionSet)
+{
+ OptionSet<ExampleFlags> set;
+ EXPECT_TRUE(set.isEmpty());
+ EXPECT_FALSE(set.contains(ExampleFlags::A));
+ EXPECT_FALSE(set.contains(ExampleFlags::B));
+ EXPECT_FALSE(set.contains(ExampleFlags::C));
+
+ auto set2 = OptionSet<ExampleFlags>::fromRaw(set.toRaw());
+ EXPECT_TRUE(set2.isEmpty());
+ EXPECT_FALSE(set2.contains(ExampleFlags::A));
+ EXPECT_FALSE(set2.contains(ExampleFlags::B));
+ EXPECT_FALSE(set2.contains(ExampleFlags::C));
+}
+
+TEST(WTF_OptionSet, OptionSetThatContainsOneFlagToRawValueToOptionSet)
+{
+ OptionSet<ExampleFlags> set = ExampleFlags::A;
+ EXPECT_FALSE(set.isEmpty());
+ EXPECT_TRUE(set.contains(ExampleFlags::A));
+ EXPECT_FALSE(set.contains(ExampleFlags::B));
+ EXPECT_FALSE(set.contains(ExampleFlags::C));
+ EXPECT_FALSE(set.contains(ExampleFlags::D));
+ EXPECT_FALSE(set.contains(ExampleFlags::E));
+
+ auto set2 = OptionSet<ExampleFlags>::fromRaw(set.toRaw());
+ EXPECT_FALSE(set2.isEmpty());
+ EXPECT_TRUE(set2.contains(ExampleFlags::A));
+ EXPECT_FALSE(set2.contains(ExampleFlags::B));
+ EXPECT_FALSE(set2.contains(ExampleFlags::C));
+ EXPECT_FALSE(set2.contains(ExampleFlags::D));
+ EXPECT_FALSE(set2.contains(ExampleFlags::E));
+}
+
+TEST(WTF_OptionSet, OptionSetThatContainsOneFlagToRawValueToOptionSet2)
+{
+ OptionSet<ExampleFlags> set = ExampleFlags::E;
+ EXPECT_FALSE(set.isEmpty());
+ EXPECT_TRUE(set.contains(ExampleFlags::E));
+ EXPECT_FALSE(set.contains(ExampleFlags::A));
+ EXPECT_FALSE(set.contains(ExampleFlags::B));
+ EXPECT_FALSE(set.contains(ExampleFlags::C));
+ EXPECT_FALSE(set.contains(ExampleFlags::D));
+
+ auto set2 = OptionSet<ExampleFlags>::fromRaw(set.toRaw());
+ EXPECT_FALSE(set2.isEmpty());
+ EXPECT_TRUE(set2.contains(ExampleFlags::E));
+ EXPECT_FALSE(set2.contains(ExampleFlags::A));
+ EXPECT_FALSE(set2.contains(ExampleFlags::B));
+ EXPECT_FALSE(set2.contains(ExampleFlags::C));
+ EXPECT_FALSE(set2.contains(ExampleFlags::D));
+}
+
+TEST(WTF_OptionSet, OptionSetThatContainsTwoFlagsToRawValueToOptionSet)
+{
+ OptionSet<ExampleFlags> set { ExampleFlags::A, ExampleFlags::C };
+ EXPECT_FALSE(set.isEmpty());
+ EXPECT_TRUE(set.contains(ExampleFlags::A));
+ EXPECT_TRUE(set.contains(ExampleFlags::C));
+ EXPECT_FALSE(set.contains(ExampleFlags::B));
+
+ auto set2 = OptionSet<ExampleFlags>::fromRaw(set.toRaw());
+ EXPECT_FALSE(set2.isEmpty());
+ EXPECT_TRUE(set2.contains(ExampleFlags::A));
+ EXPECT_TRUE(set2.contains(ExampleFlags::C));
+ EXPECT_FALSE(set2.contains(ExampleFlags::B));
+}
+
+TEST(WTF_OptionSet, OptionSetThatContainsTwoFlagsToRawValueToOptionSet2)
+{
+ OptionSet<ExampleFlags> set { ExampleFlags::D, ExampleFlags::E };
+ EXPECT_FALSE(set.isEmpty());
+ EXPECT_TRUE(set.contains(ExampleFlags::D));
+ EXPECT_TRUE(set.contains(ExampleFlags::E));
+ EXPECT_FALSE(set.contains(ExampleFlags::A));
+ EXPECT_FALSE(set.contains(ExampleFlags::B));
+ EXPECT_FALSE(set.contains(ExampleFlags::C));
+
+ auto set2 = OptionSet<ExampleFlags>::fromRaw(set.toRaw());
+ EXPECT_FALSE(set2.isEmpty());
+ EXPECT_TRUE(set2.contains(ExampleFlags::D));
+ EXPECT_TRUE(set2.contains(ExampleFlags::E));
+ EXPECT_FALSE(set2.contains(ExampleFlags::A));
+ EXPECT_FALSE(set2.contains(ExampleFlags::B));
+ EXPECT_FALSE(set2.contains(ExampleFlags::C));
+}
+
+TEST(WTF_OptionSet, TwoIteratorsIntoSameOptionSet)
+{
+ OptionSet<ExampleFlags> set { ExampleFlags::C, ExampleFlags::B };
+ OptionSet<ExampleFlags>::iterator it1 = set.begin();
+ OptionSet<ExampleFlags>::iterator it2 = it1;
+ ++it1;
+ EXPECT_STRONG_ENUM_EQ(ExampleFlags::C, *it1);
+ EXPECT_STRONG_ENUM_EQ(ExampleFlags::B, *it2);
+}
+
+TEST(WTF_OptionSet, IterateOverOptionSetThatContainsTwoFlags)
+{
+ OptionSet<ExampleFlags> set { ExampleFlags::A, ExampleFlags::C };
+ OptionSet<ExampleFlags>::iterator it = set.begin();
+ OptionSet<ExampleFlags>::iterator end = set.end();
+ EXPECT_TRUE(it != end);
+ EXPECT_STRONG_ENUM_EQ(ExampleFlags::A, *it);
+ ++it;
+ EXPECT_STRONG_ENUM_EQ(ExampleFlags::C, *it);
+ ++it;
+ EXPECT_TRUE(it == end);
+}
+
+TEST(WTF_OptionSet, IterateOverOptionSetThatContainsFlags2)
+{
+ OptionSet<ExampleFlags> set { ExampleFlags::D, ExampleFlags::E };
+ OptionSet<ExampleFlags>::iterator it = set.begin();
+ OptionSet<ExampleFlags>::iterator end = set.end();
+ EXPECT_TRUE(it != end);
+ EXPECT_STRONG_ENUM_EQ(ExampleFlags::D, *it);
+ ++it;
+ EXPECT_STRONG_ENUM_EQ(ExampleFlags::E, *it);
+ ++it;
+ EXPECT_TRUE(it == end);
+}
+
+TEST(WTF_OptionSet, NextItemAfterLargestIn32BitFlagSet)
+{
+ enum class ThirtyTwoBitFlags : uint32_t {
+ A = 1UL << 31,
+ };
+ OptionSet<ThirtyTwoBitFlags> set { ThirtyTwoBitFlags::A };
+ OptionSet<ThirtyTwoBitFlags>::iterator it = set.begin();
+ OptionSet<ThirtyTwoBitFlags>::iterator end = set.end();
+ EXPECT_TRUE(it != end);
+ ++it;
+ EXPECT_TRUE(it == end);
+}
+
+TEST(WTF_OptionSet, NextItemAfterLargestIn64BitFlagSet)
+{
+ enum class SixtyFourBitFlags : uint64_t {
+ A = 1ULL << 63,
+ };
+ OptionSet<SixtyFourBitFlags> set { SixtyFourBitFlags::A };
+ OptionSet<SixtyFourBitFlags>::iterator it = set.begin();
+ OptionSet<SixtyFourBitFlags>::iterator end = set.end();
+ EXPECT_TRUE(it != end);
+ ++it;
+ EXPECT_TRUE(it == end);
+}
+
+TEST(WTF_OptionSet, IterationOrderTheSameRegardlessOfInsertionOrder)
+{
+ OptionSet<ExampleFlags> set1 = ExampleFlags::C;
+ set1 |= ExampleFlags::A;
+
+ OptionSet<ExampleFlags> set2 = ExampleFlags::A;
+ set2 |= ExampleFlags::C;
+
+ OptionSet<ExampleFlags>::iterator it1 = set1.begin();
+ OptionSet<ExampleFlags>::iterator it2 = set2.begin();
+
+ EXPECT_TRUE(*it1 == *it2);
+ ++it1;
+ ++it2;
+ EXPECT_TRUE(*it1 == *it2);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/Optional.cpp b/Tools/TestWebKitAPI/Tests/WTF/Optional.cpp
new file mode 100644
index 000000000..a70881f35
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/Optional.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <wtf/Optional.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF_Optional, Disengaged)
+{
+ {
+ std::optional<int> optional;
+
+ EXPECT_FALSE(static_cast<bool>(optional));
+ }
+
+ {
+ std::optional<int> optional { std::nullopt };
+
+ EXPECT_FALSE(static_cast<bool>(optional));
+ }
+}
+
+TEST(WTF_Optional, Engaged)
+{
+ std::optional<int> optional { 10 };
+
+ EXPECT_TRUE(static_cast<bool>(optional));
+ EXPECT_EQ(10, optional.value());
+}
+
+TEST(WTF_Optional, Destructor)
+{
+ static bool didCallDestructor = false;
+ struct A {
+ ~A()
+ {
+ EXPECT_FALSE(didCallDestructor);
+ didCallDestructor = true;
+ }
+ };
+
+ {
+ std::optional<A> optional { std::in_place };
+
+ EXPECT_TRUE(static_cast<bool>(optional));
+ }
+
+ EXPECT_TRUE(didCallDestructor);
+}
+
+TEST(WTF_Optional, Callback)
+{
+ bool called = false;
+ std::optional<int> a;
+ int result = valueOrCompute(a, [&] {
+ called = true;
+ return 300;
+ });
+ EXPECT_TRUE(called);
+ EXPECT_EQ(result, 300);
+
+ a = 250;
+ called = false;
+ result = valueOrCompute(a, [&] {
+ called = true;
+ return 300;
+ });
+ EXPECT_FALSE(called);
+ EXPECT_EQ(result, 250);
+}
+
+TEST(WTF_Optional, Equality)
+{
+ std::optional<int> unengaged1;
+ std::optional<int> unengaged2;
+
+ std::optional<int> engaged1 { 1 };
+ std::optional<int> engaged2 { 2 };
+ std::optional<int> engagedx2 { 2 };
+
+ EXPECT_TRUE(unengaged1 == unengaged2);
+ EXPECT_FALSE(engaged1 == engaged2);
+ EXPECT_FALSE(engaged1 == unengaged1);
+ EXPECT_TRUE(engaged2 == engagedx2);
+
+ EXPECT_TRUE(unengaged1 == std::nullopt);
+ EXPECT_FALSE(engaged1 == std::nullopt);
+ EXPECT_TRUE(std::nullopt == unengaged1);
+ EXPECT_FALSE(std::nullopt == engaged1);
+
+ EXPECT_TRUE(engaged1 == 1);
+ EXPECT_TRUE(1 == engaged1);
+ EXPECT_FALSE(unengaged1 == 1);
+ EXPECT_FALSE(1 == unengaged1);
+}
+
+TEST(WTF_Optional, Inequality)
+{
+ std::optional<int> unengaged1;
+ std::optional<int> unengaged2;
+
+ std::optional<int> engaged1 { 1 };
+ std::optional<int> engaged2 { 2 };
+ std::optional<int> engagedx2 { 2 };
+
+ EXPECT_FALSE(unengaged1 != unengaged2);
+ EXPECT_TRUE(engaged1 != engaged2);
+ EXPECT_TRUE(engaged1 != unengaged1);
+ EXPECT_FALSE(engaged2 != engagedx2);
+
+ EXPECT_FALSE(unengaged1 != std::nullopt);
+ EXPECT_TRUE(engaged1 != std::nullopt);
+ EXPECT_FALSE(std::nullopt != unengaged1);
+ EXPECT_TRUE(std::nullopt != engaged1);
+
+ EXPECT_FALSE(engaged1 != 1);
+ EXPECT_TRUE(engaged1 != 2);
+ EXPECT_FALSE(1 != engaged1);
+ EXPECT_TRUE(2 != engaged1);
+
+ EXPECT_TRUE(unengaged1 != 1);
+ EXPECT_TRUE(1 != unengaged1);
+}
+
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/ParkingLot.cpp b/Tools/TestWebKitAPI/Tests/WTF/ParkingLot.cpp
new file mode 100644
index 000000000..c67e1e081
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/ParkingLot.cpp
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include <condition_variable>
+#include <mutex>
+#include <thread>
+#include <wtf/DataLog.h>
+#include <wtf/HashSet.h>
+#include <wtf/ListDump.h>
+#include <wtf/ParkingLot.h>
+#include <wtf/Threading.h>
+#include <wtf/ThreadingPrimitives.h>
+
+using namespace WTF;
+
+namespace TestWebKitAPI {
+
+namespace {
+
+struct SingleLatchTest {
+ void initialize(unsigned numThreads)
+ {
+ // This implements a fair (FIFO) semaphore, and it starts out unavailable.
+ semaphore.store(0);
+
+ for (unsigned i = numThreads; i--;) {
+ threads.append(
+ createThread(
+ "Parking Test Thread",
+ [&] () {
+ EXPECT_NE(0u, currentThread());
+
+ down();
+
+ std::lock_guard<std::mutex> locker(lock);
+ awake.add(currentThread());
+ lastAwoken = currentThread();
+ condition.notify_one();
+ }));
+ }
+ }
+
+ void unparkOne(unsigned singleUnparkIndex)
+ {
+ EXPECT_EQ(0u, lastAwoken);
+
+ unsigned numWaitingOnAddress = 0;
+ Vector<ThreadIdentifier, 8> queue;
+ ParkingLot::forEach(
+ [&] (ThreadIdentifier threadIdentifier, const void* address) {
+ if (address != &semaphore)
+ return;
+
+ queue.append(threadIdentifier);
+
+ numWaitingOnAddress++;
+ });
+
+ EXPECT_LE(numWaitingOnAddress, threads.size() - singleUnparkIndex);
+
+ up();
+
+ {
+ std::unique_lock<std::mutex> locker(lock);
+ while (awake.size() < singleUnparkIndex + 1)
+ condition.wait(locker);
+ EXPECT_NE(0u, lastAwoken);
+ if (!queue.isEmpty() && queue[0] != lastAwoken) {
+ dataLog("Woke up wrong thread: queue = ", listDump(queue), ", last awoken = ", lastAwoken, "\n");
+ EXPECT_EQ(queue[0], lastAwoken);
+ }
+ lastAwoken = 0;
+ }
+ }
+
+ void finish(unsigned numSingleUnparks)
+ {
+ unsigned numWaitingOnAddress = 0;
+ ParkingLot::forEach(
+ [&] (ThreadIdentifier, const void* address) {
+ if (address != &semaphore)
+ return;
+
+ numWaitingOnAddress++;
+ });
+
+ EXPECT_LE(numWaitingOnAddress, threads.size() - numSingleUnparks);
+
+ semaphore.store(threads.size() - numSingleUnparks);
+ ParkingLot::unparkAll(&semaphore);
+
+ numWaitingOnAddress = 0;
+ ParkingLot::forEach(
+ [&] (ThreadIdentifier, const void* address) {
+ if (address != &semaphore)
+ return;
+
+ numWaitingOnAddress++;
+ });
+
+ EXPECT_EQ(0u, numWaitingOnAddress);
+
+ {
+ std::unique_lock<std::mutex> locker(lock);
+ while (awake.size() < threads.size())
+ condition.wait(locker);
+ }
+
+ for (ThreadIdentifier threadIdentifier : threads)
+ waitForThreadCompletion(threadIdentifier);
+ }
+
+ // Semaphore operations.
+ void down()
+ {
+ for (;;) {
+ int oldSemaphoreValue = semaphore.load();
+ int newSemaphoreValue = oldSemaphoreValue - 1;
+ if (!semaphore.compareExchangeWeak(oldSemaphoreValue, newSemaphoreValue))
+ continue;
+
+ if (oldSemaphoreValue > 0) {
+ // We acquired the semaphore. Done.
+ return;
+ }
+
+ // We need to wait.
+ if (ParkingLot::compareAndPark(&semaphore, newSemaphoreValue).wasUnparked) {
+ // We did wait, and then got woken up. This means that someone who up'd the semaphore
+ // passed ownership onto us.
+ return;
+ }
+
+ // We never parked, because the semaphore value changed. Undo our decrement and try again.
+ for (;;) {
+ int oldSemaphoreValue = semaphore.load();
+ if (semaphore.compareExchangeWeak(oldSemaphoreValue, oldSemaphoreValue + 1))
+ break;
+ }
+ }
+ }
+ void up()
+ {
+ int oldSemaphoreValue;
+ for (;;) {
+ oldSemaphoreValue = semaphore.load();
+ if (semaphore.compareExchangeWeak(oldSemaphoreValue, oldSemaphoreValue + 1))
+ break;
+ }
+
+ // Check if anyone was waiting on the semaphore. If they were, then pass ownership to them.
+ if (oldSemaphoreValue < 0)
+ ParkingLot::unparkOne(&semaphore);
+ }
+
+ Atomic<int> semaphore;
+ std::mutex lock;
+ std::condition_variable condition;
+ HashSet<ThreadIdentifier> awake;
+ Vector<ThreadIdentifier> threads;
+ ThreadIdentifier lastAwoken { 0 };
+};
+
+void runParkingTest(unsigned numLatches, unsigned delay, unsigned numThreads, unsigned numSingleUnparks)
+{
+ std::unique_ptr<SingleLatchTest[]> tests = std::make_unique<SingleLatchTest[]>(numLatches);
+
+ for (unsigned latchIndex = numLatches; latchIndex--;)
+ tests[latchIndex].initialize(numThreads);
+
+ for (unsigned unparkIndex = 0; unparkIndex < numSingleUnparks; ++unparkIndex) {
+ std::this_thread::sleep_for(std::chrono::microseconds(delay));
+ for (unsigned latchIndex = numLatches; latchIndex--;)
+ tests[latchIndex].unparkOne(unparkIndex);
+ }
+
+ for (unsigned latchIndex = numLatches; latchIndex--;)
+ tests[latchIndex].finish(numSingleUnparks);
+}
+
+void repeatParkingTest(unsigned numRepeats, unsigned numLatches, unsigned delay, unsigned numThreads, unsigned numSingleUnparks)
+{
+ while (numRepeats--)
+ runParkingTest(numLatches, delay, numThreads, numSingleUnparks);
+}
+
+} // anonymous namespace
+
+TEST(WTF_ParkingLot, UnparkAllOneFast)
+{
+ repeatParkingTest(10000, 1, 0, 1, 0);
+}
+
+TEST(WTF_ParkingLot, UnparkAllHundredFast)
+{
+ repeatParkingTest(100, 1, 0, 100, 0);
+}
+
+TEST(WTF_ParkingLot, UnparkOneOneFast)
+{
+ repeatParkingTest(1000, 1, 0, 1, 1);
+}
+
+TEST(WTF_ParkingLot, UnparkOneHundredFast)
+{
+ repeatParkingTest(20, 1, 0, 100, 100);
+}
+
+TEST(WTF_ParkingLot, UnparkOneFiftyThenFiftyAllFast)
+{
+ repeatParkingTest(50, 1, 0, 100, 50);
+}
+
+TEST(WTF_ParkingLot, UnparkAllOne)
+{
+ repeatParkingTest(100, 1, 10000, 1, 0);
+}
+
+TEST(WTF_ParkingLot, UnparkAllHundred)
+{
+ repeatParkingTest(100, 1, 10000, 100, 0);
+}
+
+TEST(WTF_ParkingLot, UnparkOneOne)
+{
+ repeatParkingTest(10, 1, 10000, 1, 1);
+}
+
+TEST(WTF_ParkingLot, UnparkOneFifty)
+{
+ repeatParkingTest(1, 1, 10000, 50, 50);
+}
+
+TEST(WTF_ParkingLot, UnparkOneFiftyThenFiftyAll)
+{
+ repeatParkingTest(2, 1, 10000, 100, 50);
+}
+
+TEST(WTF_ParkingLot, HundredUnparkAllOneFast)
+{
+ repeatParkingTest(100, 100, 0, 1, 0);
+}
+
+TEST(WTF_ParkingLot, HundredUnparkAllOne)
+{
+ repeatParkingTest(1, 100, 10000, 1, 0);
+}
+
+} // namespace TestWebKitAPI
+
diff --git a/Tools/TestWebKitAPI/Tests/WTF/RedBlackTree.cpp b/Tools/TestWebKitAPI/Tests/WTF/RedBlackTree.cpp
index 1a1c9fdfc..5e5c8adc4 100644
--- a/Tools/TestWebKitAPI/Tests/WTF/RedBlackTree.cpp
+++ b/Tools/TestWebKitAPI/Tests/WTF/RedBlackTree.cpp
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
diff --git a/Tools/TestWebKitAPI/Tests/WTF/Ref.cpp b/Tools/TestWebKitAPI/Tests/WTF/Ref.cpp
index 1b9eef67a..c35606e23 100644
--- a/Tools/TestWebKitAPI/Tests/WTF/Ref.cpp
+++ b/Tools/TestWebKitAPI/Tests/WTF/Ref.cpp
@@ -26,7 +26,6 @@
#include "config.h"
#include "RefLogger.h"
-#include <wtf/PassRef.h>
#include <wtf/Ref.h>
#include <wtf/RefPtr.h>
@@ -38,14 +37,14 @@ TEST(WTF_Ref, Basic)
{
Ref<RefLogger> ptr(a);
- ASSERT_EQ(&a, &ptr.get());
+ ASSERT_EQ(&a, ptr.ptr());
ASSERT_EQ(&a.name, &ptr->name);
}
ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
{
Ref<RefLogger> ptr(adoptRef(a));
- ASSERT_EQ(&a, &ptr.get());
+ ASSERT_EQ(&a, ptr.ptr());
ASSERT_EQ(&a.name, &ptr->name);
}
ASSERT_STREQ("deref(a) ", takeLogStr().c_str());
@@ -59,51 +58,51 @@ TEST(WTF_Ref, Assignment)
{
Ref<RefLogger> ptr(a);
- ASSERT_EQ(&a, &ptr.get());
+ ASSERT_EQ(&a, ptr.ptr());
log() << "| ";
ptr = b;
- ASSERT_EQ(&b, &ptr.get());
+ ASSERT_EQ(&b, ptr.ptr());
log() << "| ";
}
ASSERT_STREQ("ref(a) | ref(b) deref(a) | deref(b) ", takeLogStr().c_str());
{
Ref<RefLogger> ptr(a);
- ASSERT_EQ(&a, &ptr.get());
+ ASSERT_EQ(&a, ptr.ptr());
log() << "| ";
ptr = c;
- ASSERT_EQ(&c, &ptr.get());
+ ASSERT_EQ(&c, ptr.ptr());
log() << "| ";
}
ASSERT_STREQ("ref(a) | ref(c) deref(a) | deref(c) ", takeLogStr().c_str());
{
Ref<RefLogger> ptr(a);
- ASSERT_EQ(&a, &ptr.get());
+ ASSERT_EQ(&a, ptr.ptr());
log() << "| ";
ptr = adoptRef(b);
- ASSERT_EQ(&b, &ptr.get());
+ ASSERT_EQ(&b, ptr.ptr());
log() << "| ";
}
ASSERT_STREQ("ref(a) | deref(a) | deref(b) ", takeLogStr().c_str());
{
Ref<RefLogger> ptr(a);
- ASSERT_EQ(&a, &ptr.get());
+ ASSERT_EQ(&a, ptr.ptr());
log() << "| ";
ptr = adoptRef(c);
- ASSERT_EQ(&c, &ptr.get());
+ ASSERT_EQ(&c, ptr.ptr());
log() << "| ";
}
ASSERT_STREQ("ref(a) | deref(a) | deref(c) ", takeLogStr().c_str());
}
-PassRef<RefLogger> passWithPassRef(PassRef<RefLogger> reference)
+static Ref<RefLogger> passWithRef(Ref<RefLogger>&& reference)
{
- return reference;
+ return WTFMove(reference);
}
-RefPtr<RefLogger> passWithPassRefPtr(PassRefPtr<RefLogger> reference)
+static RefPtr<RefLogger> passWithPassRefPtr(PassRefPtr<RefLogger> reference)
{
return reference;
}
@@ -115,32 +114,48 @@ TEST(WTF_Ref, ReturnValue)
DerivedRefLogger c("c");
{
- Ref<RefLogger> ptr(passWithPassRef(a));
- ASSERT_EQ(&a, &ptr.get());
+ Ref<RefLogger> ptr(passWithRef(Ref<RefLogger>(a)));
+ ASSERT_EQ(&a, ptr.ptr());
}
ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
{
Ref<RefLogger> ptr(a);
- ASSERT_EQ(&a, &ptr.get());
+ ASSERT_EQ(&a, ptr.ptr());
log() << "| ";
- ptr = passWithPassRef(b);
- ASSERT_EQ(&b, &ptr.get());
+ ptr = passWithRef(b);
+ ASSERT_EQ(&b, ptr.ptr());
log() << "| ";
}
ASSERT_STREQ("ref(a) | ref(b) deref(a) | deref(b) ", takeLogStr().c_str());
{
- RefPtr<RefLogger> ptr(passWithPassRef(a));
+ RefPtr<RefLogger> ptr(passWithRef(a));
ASSERT_EQ(&a, ptr.get());
}
ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
{
- RefPtr<RefLogger> ptr(passWithPassRefPtr(passWithPassRef(a)));
+ RefPtr<RefLogger> ptr(passWithPassRefPtr(passWithRef(a)));
ASSERT_EQ(&a, ptr.get());
}
ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<DerivedRefLogger> ptr(&a);
+ RefPtr<RefLogger> ptr2(WTFMove(ptr));
+ ASSERT_EQ(nullptr, ptr.get());
+ ASSERT_EQ(&a, ptr2.get());
+ }
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ Ref<DerivedRefLogger> derivedReference(a);
+ Ref<RefLogger> baseReference(passWithRef(derivedReference.copyRef()));
+ ASSERT_EQ(&a, derivedReference.ptr());
+ ASSERT_EQ(&a, baseReference.ptr());
+ }
+ ASSERT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str());
}
} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/RefCounter.cpp b/Tools/TestWebKitAPI/Tests/WTF/RefCounter.cpp
new file mode 100644
index 000000000..4c0a14b47
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/RefCounter.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <wtf/Ref.h>
+#include <wtf/RefCounter.h>
+#include <wtf/text/WTFString.h>
+
+namespace TestWebKitAPI {
+
+static const int IncrementExpected = 0xC0FFEE1;
+static const int DecrementExpected = 0xC0FFEE2;
+static const int CallbackNotExpected = 0xDECAF;
+
+enum TestCounterType { };
+typedef RefCounter<TestCounterType> TestCounter;
+typedef TestCounter::Token TokenType;
+
+TEST(WTF, RefCounter)
+{
+ // RefCounter API is pretty simple, containing the following 4 methods to test:
+ //
+ // 1) RefCounter(std::function<void()>);
+ // 2) ~RefCounter();
+ // 3) Ref<Count> token() const;
+ // 4) unsigned value() const;
+ //
+ // We'll test:
+ // 1) Construction:
+ // 1a) with a callback
+ // 1b) without a callback
+ // 2) Destruction where the RefCounter::Count has:
+ // 2a) a non-zero reference count (Count outlives RefCounter).
+ // 2b) a zero reference count (Count is deleted by RefCounter's destructor).
+ // 3) Call count to ref/deref the Count object, where:
+ // 3a) ref with callback from 0 -> 1.
+ // 3b) ref with callback from 1 -> >1.
+ // 3c) deref with callback from >1 -> 1.
+ // 3d) deref with callback from 1 -> 0.
+ // 3d) deref with callback from 1 -> 0.
+ // 3e) ref with callback from 1 -> >1 AFTER RefCounter has been destroyed.
+ // 3f) deref with callback from >1 -> 1 AFTER RefCounter has been destroyed.
+ // 3g) deref with callback from 1 -> 0 AFTER RefCounter has been destroyed.
+ // 3h) ref without callback
+ // 3i) deref without callback
+ // 3j) ref using a Ref rather than a RefPtr (make sure there is no unnecessary reference count churn).
+ // 3k) deref using a Ref rather than a RefPtr (make sure there is no unnecessary reference count churn).
+ // 4) Test the value of the counter:
+ // 4a) at construction.
+ // 4b) as read within the callback.
+ // 4c) as read after the ref/deref.
+
+ // These values will outlive the following block.
+ int callbackValue = CallbackNotExpected;
+ TokenType incTo1Again;
+
+ {
+ // Testing (1a) - Construction with a callback.
+ TestCounter* counterPtr = nullptr;
+ TestCounter counter([&](RefCounterEvent event) {
+ // Check that the callback is called at the expected times, and the correct number of times.
+ if (RefCounterEvent::Increment == event)
+ EXPECT_EQ(callbackValue, IncrementExpected);
+ if (RefCounterEvent::Decrement == event)
+ EXPECT_EQ(callbackValue, DecrementExpected);
+ // return the value of the counter in the callback.
+ callbackValue = counterPtr->value();
+ });
+ counterPtr = &counter;
+ // Testing (4a) - after construction value() is 0.
+ EXPECT_EQ(0, static_cast<int>(counter.value()));
+
+ // Testing (3a) - ref with callback from 0 -> 1.
+ callbackValue = IncrementExpected;
+ TokenType incTo1(counter.count());
+ // Testing (4b) & (4c) - values within & after callback.
+ EXPECT_EQ(1, callbackValue);
+ EXPECT_EQ(1, static_cast<int>(counter.value()));
+
+ // Testing (3b) - ref with callback from 1 -> 2.
+ callbackValue = IncrementExpected;
+ TokenType incTo2(incTo1);
+ // Testing (4b) & (4c) - values within & after callback.
+ EXPECT_EQ(2, callbackValue);
+ EXPECT_EQ(2, static_cast<int>(counter.value()));
+
+ // Testing (3c) - deref with callback from >1 -> 1.
+ callbackValue = DecrementExpected;
+ incTo1 = nullptr;
+ // Testing (4b) & (4c) - values within & after callback.
+ EXPECT_EQ(1, callbackValue);
+ EXPECT_EQ(1, static_cast<int>(counter.value()));
+
+ {
+ // Testing (3j) - ref using a Ref rather than a RefPtr.
+ callbackValue = IncrementExpected;
+ TokenType incTo2Again(counter.count());
+ // Testing (4b) & (4c) - values within & after callback.
+ EXPECT_EQ(2, callbackValue);
+ EXPECT_EQ(2, static_cast<int>(counter.value()));
+ // Testing (3k) - deref using a Ref rather than a RefPtr.
+
+ callbackValue = DecrementExpected;
+ }
+ EXPECT_EQ(1, callbackValue);
+ EXPECT_EQ(1, static_cast<int>(counter.value()));
+ // Testing (4b) & (4c) - values within & after callback.
+
+ // Testing (3d) - deref with callback from 1 -> 0.
+ callbackValue = DecrementExpected;
+ incTo2 = nullptr;
+ // Testing (4b) & (4c) - values within & after callback.
+ EXPECT_EQ(0, callbackValue);
+ EXPECT_EQ(0, static_cast<int>(counter.value()));
+
+ // Testing (2a) - Destruction where the TestCounter::Count has a non-zero reference count.
+ callbackValue = IncrementExpected;
+ incTo1Again = counter.count();
+ EXPECT_EQ(1, callbackValue);
+ EXPECT_EQ(1, static_cast<int>(counter.value()));
+ callbackValue = CallbackNotExpected;
+ }
+
+ // Testing (3e) - ref with callback from 1 -> >1 AFTER RefCounter has been destroyed.
+ TokenType incTo2Again = incTo1Again;
+ // Testing (3f) - deref with callback from >1 -> 1 AFTER RefCounter has been destroyed.
+ incTo1Again = nullptr;
+ // Testing (3g) - deref with callback from 1 -> 0 AFTER RefCounter has been destroyed.
+ incTo2Again = nullptr;
+
+ // Testing (1b) - Construction without a callback.
+ TestCounter counter;
+ // Testing (4a) - after construction value() is 0.
+ EXPECT_EQ(0, static_cast<int>(counter.value()));
+ // Testing (3h) - ref without callback
+ TokenType incTo1(counter.count());
+ // Testing (4c) - value as read after the ref.
+ EXPECT_EQ(1, static_cast<int>(counter.value()));
+ // Testing (3i) - deref without callback
+ incTo1 = nullptr;
+ // Testing (4c) - value as read after the deref.
+ EXPECT_EQ(0, static_cast<int>(counter.value()));
+ // Testing (2b) - Destruction where the RefCounter::Count has a zero reference count.
+ // ... not a lot to test here! - we can at least ensure this code path is run & we don't crash!
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/RefLogger.cpp b/Tools/TestWebKitAPI/Tests/WTF/RefLogger.cpp
new file mode 100644
index 000000000..f468a312c
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/RefLogger.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013, 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "RefLogger.h"
+
+namespace TestWebKitAPI {
+
+std::ostringstream& log()
+{
+ static std::ostringstream log;
+ return log;
+}
+
+}
diff --git a/Tools/TestWebKitAPI/Tests/WTF/RefLogger.h b/Tools/TestWebKitAPI/Tests/WTF/RefLogger.h
index 2bb5c36fa..02547dfec 100644
--- a/Tools/TestWebKitAPI/Tests/WTF/RefLogger.h
+++ b/Tools/TestWebKitAPI/Tests/WTF/RefLogger.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,11 +27,7 @@
namespace TestWebKitAPI {
-inline std::ostringstream& log()
-{
- static std::ostringstream log;
- return log;
-}
+std::ostringstream& log();
inline std::string takeLogStr()
{
@@ -48,7 +44,7 @@ struct RefLogger {
};
struct DerivedRefLogger : RefLogger {
- DerivedRefLogger(const char* name) : RefLogger(name) { }
+ DerivedRefLogger(const char* name) : RefLogger(name) { log().str(""); }
};
}
diff --git a/Tools/TestWebKitAPI/Tests/WTF/RefPtr.cpp b/Tools/TestWebKitAPI/Tests/WTF/RefPtr.cpp
index bc1e1e484..172efa762 100644
--- a/Tools/TestWebKitAPI/Tests/WTF/RefPtr.cpp
+++ b/Tools/TestWebKitAPI/Tests/WTF/RefPtr.cpp
@@ -26,6 +26,8 @@
#include "config.h"
#include "RefLogger.h"
+#include <wtf/NeverDestroyed.h>
+#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
namespace TestWebKitAPI {
@@ -69,7 +71,7 @@ TEST(WTF_RefPtr, Basic)
{
RefPtr<RefLogger> p1 = &a;
- RefPtr<RefLogger> p2 = std::move(p1);
+ RefPtr<RefLogger> p2 = WTFMove(p1);
ASSERT_EQ(nullptr, p1.get());
ASSERT_EQ(&a, p2.get());
}
@@ -77,7 +79,7 @@ TEST(WTF_RefPtr, Basic)
{
RefPtr<RefLogger> p1 = &a;
- RefPtr<RefLogger> p2(std::move(p1));
+ RefPtr<RefLogger> p2(WTFMove(p1));
ASSERT_EQ(nullptr, p1.get());
ASSERT_EQ(&a, p2.get());
}
@@ -93,7 +95,7 @@ TEST(WTF_RefPtr, Basic)
{
RefPtr<DerivedRefLogger> p1 = &a;
- RefPtr<RefLogger> p2 = std::move(p1);
+ RefPtr<RefLogger> p2 = WTFMove(p1);
ASSERT_EQ(nullptr, p1.get());
ASSERT_EQ(&a, p2.get());
}
@@ -102,7 +104,7 @@ TEST(WTF_RefPtr, Basic)
{
RefPtr<RefLogger> ptr(&a);
ASSERT_EQ(&a, ptr.get());
- ptr.clear();
+ ptr = nullptr;
ASSERT_EQ(nullptr, ptr.get());
}
ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
@@ -120,8 +122,8 @@ TEST(WTF_RefPtr, AssignPassRefToRefPtr)
{
DerivedRefLogger a("a");
{
- PassRef<RefLogger> passRef(a);
- RefPtr<RefLogger> ptr = std::move(passRef);
+ Ref<RefLogger> passRef(a);
+ RefPtr<RefLogger> ptr = WTFMove(passRef);
ASSERT_EQ(&a, ptr.get());
ptr.release();
ASSERT_EQ(nullptr, ptr.get());
@@ -204,7 +206,7 @@ TEST(WTF_RefPtr, Assignment)
ASSERT_EQ(&a, p1.get());
ASSERT_EQ(&b, p2.get());
log() << "| ";
- p1 = std::move(p2);
+ p1 = WTFMove(p2);
ASSERT_EQ(&b, p1.get());
ASSERT_EQ(nullptr, p2.get());
log() << "| ";
@@ -250,7 +252,7 @@ TEST(WTF_RefPtr, Assignment)
ASSERT_EQ(&a, p1.get());
ASSERT_EQ(&c, p2.get());
log() << "| ";
- p1 = std::move(p2);
+ p1 = WTFMove(p2);
ASSERT_EQ(&c, p1.get());
ASSERT_EQ(nullptr, p2.get());
log() << "| ";
@@ -270,7 +272,15 @@ TEST(WTF_RefPtr, Assignment)
{
RefPtr<RefLogger> ptr(&a);
ASSERT_EQ(&a, ptr.get());
- ptr = std::move(ptr);
+#if COMPILER(CLANG)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-pragmas"
+#pragma clang diagnostic ignored "-Wself-move"
+#endif
+ ptr = WTFMove(ptr);
+#if COMPILER(CLANG)
+#pragma clang diagnostic pop
+#endif
ASSERT_EQ(&a, ptr.get());
}
ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
@@ -395,4 +405,34 @@ TEST(WTF_RefPtr, ReturnValue)
ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
}
+
+struct ConstRefCounted : RefCounted<ConstRefCounted> {
+ static Ref<ConstRefCounted> create() { return adoptRef(*new ConstRefCounted); }
+};
+
+const ConstRefCounted& returnConstRefCountedRef()
+{
+ static NeverDestroyed<ConstRefCounted> instance;
+ return instance.get();
+}
+ConstRefCounted& returnRefCountedRef()
+{
+ static NeverDestroyed<ConstRefCounted> instance;
+ return instance.get();
+}
+
+TEST(WTF_RefPtr, Const)
+{
+ // This test passes if it compiles without an error.
+ auto a = ConstRefCounted::create();
+ Ref<const ConstRefCounted> b = WTFMove(a);
+ RefPtr<const ConstRefCounted> c = b.ptr();
+ Ref<const ConstRefCounted> d = returnConstRefCountedRef();
+ RefPtr<const ConstRefCounted> e = &returnConstRefCountedRef();
+ RefPtr<ConstRefCounted> f = ConstRefCounted::create();
+ RefPtr<const ConstRefCounted> g = f;
+ RefPtr<const ConstRefCounted> h(f);
+ Ref<const ConstRefCounted> i(returnRefCountedRef());
+}
+
} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/RunLoop.cpp b/Tools/TestWebKitAPI/Tests/WTF/RunLoop.cpp
new file mode 100644
index 000000000..1dc7e938a
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/RunLoop.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "Utilities.h"
+#include <wtf/RunLoop.h>
+
+namespace TestWebKitAPI {
+
+static bool testFinished;
+static int count = 100;
+
+TEST(WTF_RunLoop, Deadlock)
+{
+ RunLoop::initializeMainRunLoop();
+
+ struct DispatchFromDestructorTester {
+ ~DispatchFromDestructorTester() {
+ RunLoop::main().dispatch([] {
+ if (!(--count))
+ testFinished = true;
+ });
+ }
+ };
+
+ for (int i = 0; i < count; ++i) {
+ auto capture = std::make_shared<DispatchFromDestructorTester>();
+ RunLoop::main().dispatch([capture] { });
+ }
+
+ Util::run(&testFinished);
+}
+
+TEST(WTF_RunLoop, NestedRunLoop)
+{
+ RunLoop::initializeMainRunLoop();
+
+ bool testFinished = false;
+ RunLoop::current().dispatch([&] {
+ RunLoop::current().dispatch([&] {
+ testFinished = true;
+ });
+ Util::run(&testFinished);
+ });
+
+ Util::run(&testFinished);
+}
+
+TEST(WTF_RunLoop, OneShotTimer)
+{
+ RunLoop::initializeMainRunLoop();
+
+ bool testFinished = false;
+
+ class DerivedTimer : public RunLoop::Timer<DerivedTimer> {
+ public:
+ DerivedTimer(bool& testFinished)
+ : RunLoop::Timer<DerivedTimer>(RunLoop::current(), this, &DerivedTimer::fired)
+ , m_testFinished(testFinished)
+ {
+ }
+
+ void fired()
+ {
+ m_testFinished = true;
+ stop();
+ }
+
+ private:
+ bool& m_testFinished;
+ };
+
+ {
+ DerivedTimer timer(testFinished);
+ timer.startOneShot(0.1);
+ Util::run(&testFinished);
+ }
+}
+
+TEST(WTF_RunLoop, RepeatingTimer)
+{
+ RunLoop::initializeMainRunLoop();
+
+ bool testFinished = false;
+
+ class DerivedTimer : public RunLoop::Timer<DerivedTimer> {
+ public:
+ DerivedTimer(bool& testFinished)
+ : RunLoop::Timer<DerivedTimer>(RunLoop::current(), this, &DerivedTimer::fired)
+ , m_testFinished(testFinished)
+ {
+ }
+
+ void fired()
+ {
+ if (++m_count == 10) {
+ m_testFinished = true;
+ stop();
+ }
+ }
+
+ private:
+ unsigned m_count { 0 };
+ bool& m_testFinished;
+ };
+
+ {
+ DerivedTimer timer(testFinished);
+ timer.startRepeating(0.01);
+ Util::run(&testFinished);
+ }
+}
+
+TEST(WTF_RunLoop, ManyTimes)
+{
+ RunLoop::initializeMainRunLoop();
+
+ class Counter {
+ public:
+ void run()
+ {
+ if (++m_count == 100000) {
+ RunLoop::current().stop();
+ return;
+ }
+ RunLoop::current().dispatch([this] {
+ run();
+ });
+ }
+
+ private:
+ unsigned m_count { 0 };
+ };
+
+ Counter counter;
+
+ RunLoop::current().dispatch([&counter] {
+ counter.run();
+ });
+ RunLoop::run();
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/Scope.cpp b/Tools/TestWebKitAPI/Tests/WTF/Scope.cpp
new file mode 100644
index 000000000..08f5ce327
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/Scope.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include <wtf/Scope.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF_Scope, ScopeExit)
+{
+ bool isCalled = false;
+ {
+ auto scopeExit = makeScopeExit([&] {
+ EXPECT_FALSE(isCalled);
+ isCalled = true;
+ });
+ EXPECT_FALSE(isCalled);
+ }
+ EXPECT_TRUE(isCalled);
+
+ isCalled = false;
+ {
+ auto scopeExit = makeScopeExit([&] {
+ isCalled = true;
+ });
+ scopeExit.release();
+ }
+ EXPECT_FALSE(isCalled);
+}
+
+}
diff --git a/Tools/TestWebKitAPI/Tests/WTF/ScopedLambda.cpp b/Tools/TestWebKitAPI/Tests/WTF/ScopedLambda.cpp
new file mode 100644
index 000000000..3dfee8671
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/ScopedLambda.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include <wtf/ScopedLambda.h>
+#include <wtf/Vector.h>
+
+using namespace WTF;
+
+namespace TestWebKitAPI {
+
+// This test relies on this module being compiled with -fno-elide-constructors
+TEST(WTF_ScopedLambda, NoRVOLivenessBug)
+{
+ Vector<int> vector;
+ for (unsigned i = 0; i < 10; ++i)
+ vector.append(i);
+
+ auto lambda = scopedLambda<int(size_t)>(
+ [=] (size_t i) -> int {
+ return vector[i];
+ });
+
+ for (unsigned i = 0; i < 10; ++i)
+ EXPECT_EQ(i, static_cast<unsigned>(lambda(i)));
+}
+
+} // namespace TestWebKitAPI
+
diff --git a/Tools/TestWebKitAPI/Tests/WTF/TemporaryChange.cpp b/Tools/TestWebKitAPI/Tests/WTF/SetForScope.cpp
index 3ba0f15bd..92e3494d6 100644
--- a/Tools/TestWebKitAPI/Tests/WTF/TemporaryChange.cpp
+++ b/Tools/TestWebKitAPI/Tests/WTF/SetForScope.cpp
@@ -25,18 +25,18 @@
#include "config.h"
-#include <wtf/TemporaryChange.h>
+#include <wtf/SetForScope.h>
namespace TestWebKitAPI {
-TEST(WTF, TemporaryChangeNested)
+TEST(WTF, SetForScopeNested)
{
bool originallyFalse = false;
{
- TemporaryChange<bool> change1OriginallyFalse(originallyFalse, true);
+ SetForScope<bool> change1OriginallyFalse(originallyFalse, true);
EXPECT_TRUE(originallyFalse);
{
- TemporaryChange<bool> change2OriginallyFalse(originallyFalse, false);
+ SetForScope<bool> change2OriginallyFalse(originallyFalse, false);
EXPECT_FALSE(originallyFalse);
}
EXPECT_TRUE(originallyFalse);
diff --git a/Tools/TestWebKitAPI/Tests/WTF/StringBuilder.cpp b/Tools/TestWebKitAPI/Tests/WTF/StringBuilder.cpp
index 9ca5d6ee8..11bf3590e 100644
--- a/Tools/TestWebKitAPI/Tests/WTF/StringBuilder.cpp
+++ b/Tools/TestWebKitAPI/Tests/WTF/StringBuilder.cpp
@@ -38,14 +38,17 @@ static void expectBuilderContent(const String& expected, const StringBuilder& bu
{
// Not using builder.toString() or builder.toStringPreserveCapacity() because they all
// change internal state of builder.
- EXPECT_EQ(expected, String(builder.deprecatedCharacters(), builder.length()));
+ if (builder.is8Bit())
+ EXPECT_EQ(expected, String(builder.characters8(), builder.length()));
+ else
+ EXPECT_EQ(expected, String(builder.characters16(), builder.length()));
}
void expectEmpty(const StringBuilder& builder)
{
EXPECT_EQ(0U, builder.length());
EXPECT_TRUE(builder.isEmpty());
- EXPECT_EQ(0, builder.deprecatedCharacters());
+ EXPECT_EQ(0, builder.characters8());
}
TEST(StringBuilderTest, DefaultConstructor)
@@ -72,20 +75,20 @@ TEST(StringBuilderTest, Append)
StringBuilder builder1;
builder.append("", 0);
expectBuilderContent("0123456789abcdefg#", builder);
- builder1.append(builder.deprecatedCharacters(), builder.length());
+ builder1.append(builder.characters8(), builder.length());
builder1.append("XYZ");
- builder.append(builder1.deprecatedCharacters(), builder1.length());
+ builder.append(builder1.characters8(), builder1.length());
expectBuilderContent("0123456789abcdefg#0123456789abcdefg#XYZ", builder);
StringBuilder builder2;
builder2.reserveCapacity(100);
builder2.append("xyz");
- const UChar* characters = builder2.deprecatedCharacters();
+ const LChar* characters = builder2.characters8();
builder2.append("0123456789");
- ASSERT_EQ(characters, builder2.deprecatedCharacters());
+ ASSERT_EQ(characters, builder2.characters8());
builder2.toStringPreserveCapacity(); // Test after reifyString with buffer preserved.
builder2.append("abcd");
- ASSERT_EQ(characters, builder2.deprecatedCharacters());
+ ASSERT_EQ(characters, builder2.characters8());
// Test appending UChar32 characters to StringBuilder.
StringBuilder builderForUChar32Append;
@@ -140,7 +143,7 @@ TEST(StringBuilderTest, ToStringPreserveCapacity)
ASSERT_EQ(capacity, builder.capacity());
ASSERT_EQ(String("0123456789"), string);
ASSERT_EQ(string.impl(), builder.toStringPreserveCapacity().impl());
- ASSERT_EQ(string.deprecatedCharacters(), builder.deprecatedCharacters());
+ ASSERT_EQ(string.characters8(), builder.characters8());
// Changing the StringBuilder should not affect the original result of toStringPreserveCapacity().
builder.append("abcdefghijklmnopqrstuvwxyz");
@@ -151,7 +154,7 @@ TEST(StringBuilderTest, ToStringPreserveCapacity)
capacity = builder.capacity();
string = builder.toStringPreserveCapacity();
ASSERT_EQ(capacity, builder.capacity());
- ASSERT_EQ(string.deprecatedCharacters(), builder.deprecatedCharacters());
+ ASSERT_EQ(string.characters8(), builder.characters8());
ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyz"), string);
builder.append("ABC");
ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyz"), string);
@@ -160,7 +163,7 @@ TEST(StringBuilderTest, ToStringPreserveCapacity)
capacity = builder.capacity();
String string1 = builder.toStringPreserveCapacity();
ASSERT_EQ(capacity, builder.capacity());
- ASSERT_EQ(string1.deprecatedCharacters(), builder.deprecatedCharacters());
+ ASSERT_EQ(string1.characters8(), builder.characters8());
ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), string1);
string1.append("DEF");
ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), builder.toStringPreserveCapacity());
@@ -170,7 +173,7 @@ TEST(StringBuilderTest, ToStringPreserveCapacity)
capacity = builder.capacity();
string1 = builder.toStringPreserveCapacity();
ASSERT_EQ(capacity, builder.capacity());
- ASSERT_EQ(string.deprecatedCharacters(), builder.deprecatedCharacters());
+ ASSERT_EQ(string.characters8(), builder.characters8());
builder.resize(10);
builder.append("###");
ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), string1);
diff --git a/Tools/TestWebKitAPI/Tests/WTF/StringConcatenate.cpp b/Tools/TestWebKitAPI/Tests/WTF/StringConcatenate.cpp
new file mode 100644
index 000000000..fc25b08f8
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/StringConcatenate.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "WTFStringUtilities.h"
+#include <wtf/text/StringConcatenate.h>
+#include <wtf/text/StringConcatenateNumbers.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF, StringConcatenate)
+{
+ EXPECT_EQ("hello world", makeString("hello", " ", "world"));
+}
+
+TEST(WTF, StringConcatenate_Int)
+{
+ EXPECT_EQ(5u, WTF::lengthOfNumberAsStringSigned(17890));
+ EXPECT_EQ("hello 17890 world", makeString("hello ", 17890 , " world"));
+
+ EXPECT_EQ(6u, WTF::lengthOfNumberAsStringSigned(-17890));
+ EXPECT_EQ("hello -17890 world", makeString("hello ", -17890 , " world"));
+
+ EXPECT_EQ(1u, WTF::lengthOfNumberAsStringSigned(0));
+ EXPECT_EQ("hello 0 world", makeString("hello ", 0 , " world"));
+}
+
+TEST(WTF, StringConcatenate_Unsigned)
+{
+ EXPECT_EQ(5u, WTF::lengthOfNumberAsStringUnsigned(17890u));
+ EXPECT_EQ("hello 17890 world", makeString("hello ", 17890u , " world"));
+
+ EXPECT_EQ(1u, WTF::lengthOfNumberAsStringSigned(0u));
+ EXPECT_EQ("hello 0 world", makeString("hello ", 0u , " world"));
+}
+
+TEST(WTF, StringConcatenate_Float)
+{
+ EXPECT_EQ("hello 17890 world", makeString("hello ", 17890.0f , " world"));
+ EXPECT_EQ("hello 17890.5 world", makeString("hello ", 17890.5f , " world"));
+
+ EXPECT_EQ("hello -17890 world", makeString("hello ", -17890.0f , " world"));
+ EXPECT_EQ("hello -17890.5 world", makeString("hello ", -17890.5f , " world"));
+
+ EXPECT_EQ("hello 0 world", makeString("hello ", 0.0f , " world"));
+}
+
+TEST(WTF, StringConcatenate_Double)
+{
+ EXPECT_EQ("hello 17890 world", makeString("hello ", 17890.0 , " world"));
+ EXPECT_EQ("hello 17890.5 world", makeString("hello ", 17890.5 , " world"));
+
+ EXPECT_EQ("hello -17890 world", makeString("hello ", -17890.0 , " world"));
+ EXPECT_EQ("hello -17890.5 world", makeString("hello ", -17890.5 , " world"));
+
+ EXPECT_EQ("hello 0 world", makeString("hello ", 0.0 , " world"));
+}
+
+TEST(WTF, StringConcatenate_FormattedDoubleFixedPrecision)
+{
+ EXPECT_EQ("hello 17890.0 world", makeString("hello ", FormattedNumber::fixedPrecision(17890.0) , " world"));
+ EXPECT_EQ("hello 1.79e+4 world", makeString("hello ", FormattedNumber::fixedPrecision(17890.0, 3) , " world"));
+ EXPECT_EQ("hello 17890.000 world", makeString("hello ", FormattedNumber::fixedPrecision(17890.0, 8) , " world"));
+ EXPECT_EQ("hello 17890 world", makeString("hello ", FormattedNumber::fixedPrecision(17890.0, 8, true) , " world"));
+
+ EXPECT_EQ("hello 17890.5 world", makeString("hello ", FormattedNumber::fixedPrecision(17890.5) , " world"));
+ EXPECT_EQ("hello 1.79e+4 world", makeString("hello ", FormattedNumber::fixedPrecision(17890.5, 3) , " world"));
+ EXPECT_EQ("hello 17890.500 world", makeString("hello ", FormattedNumber::fixedPrecision(17890.5, 8) , " world"));
+ EXPECT_EQ("hello 17890.5 world", makeString("hello ", FormattedNumber::fixedPrecision(17890.5, 8, true) , " world"));
+
+ EXPECT_EQ("hello -17890.0 world", makeString("hello ", FormattedNumber::fixedPrecision(-17890.0) , " world"));
+ EXPECT_EQ("hello -1.79e+4 world", makeString("hello ", FormattedNumber::fixedPrecision(-17890.0, 3) , " world"));
+ EXPECT_EQ("hello -17890.000 world", makeString("hello ", FormattedNumber::fixedPrecision(-17890.0, 8) , " world"));
+ EXPECT_EQ("hello -17890 world", makeString("hello ", FormattedNumber::fixedPrecision(-17890.0, 8, true) , " world"));
+
+ EXPECT_EQ("hello -17890.5 world", makeString("hello ", FormattedNumber::fixedPrecision(-17890.5) , " world"));
+ EXPECT_EQ("hello -1.79e+4 world", makeString("hello ", FormattedNumber::fixedPrecision(-17890.5, 3) , " world"));
+ EXPECT_EQ("hello -17890.500 world", makeString("hello ", FormattedNumber::fixedPrecision(-17890.5, 8) , " world"));
+ EXPECT_EQ("hello -17890.5 world", makeString("hello ", FormattedNumber::fixedPrecision(-17890.5, 8, true) , " world"));
+
+ EXPECT_EQ("hello 0.00000 world", makeString("hello ", FormattedNumber::fixedPrecision(0.0) , " world"));
+ EXPECT_EQ("hello 0.00 world", makeString("hello ", FormattedNumber::fixedPrecision(0.0, 3) , " world"));
+ EXPECT_EQ("hello 0.0000000 world", makeString("hello ", FormattedNumber::fixedPrecision(0.0, 8) , " world"));
+ EXPECT_EQ("hello 0 world", makeString("hello ", FormattedNumber::fixedPrecision(0.0, 8, true) , " world"));
+}
+
+TEST(WTF, StringConcatenate_FormattedDoubleFixedWidth)
+{
+ EXPECT_EQ("hello 17890.000 world", makeString("hello ", FormattedNumber::fixedWidth(17890.0, 3) , " world"));
+ EXPECT_EQ("hello 17890.500 world", makeString("hello ", FormattedNumber::fixedWidth(17890.5, 3) , " world"));
+
+ EXPECT_EQ("hello -17890.000 world", makeString("hello ", FormattedNumber::fixedWidth(-17890.0, 3) , " world"));
+ EXPECT_EQ("hello -17890.500 world", makeString("hello ", FormattedNumber::fixedWidth(-17890.5, 3) , " world"));
+
+ EXPECT_EQ("hello 0.000 world", makeString("hello ", FormattedNumber::fixedWidth(0.0, 3) , " world"));
+}
+
+}
diff --git a/Tools/TestWebKitAPI/Tests/WTF/StringHasher.cpp b/Tools/TestWebKitAPI/Tests/WTF/StringHasher.cpp
index a4d223c99..5985b026a 100644
--- a/Tools/TestWebKitAPI/Tests/WTF/StringHasher.cpp
+++ b/Tools/TestWebKitAPI/Tests/WTF/StringHasher.cpp
@@ -25,7 +25,7 @@
#include "config.h"
-#include <wtf/StringHasher.h>
+#include <wtf/Hasher.h>
namespace TestWebKitAPI {
@@ -264,6 +264,43 @@ TEST(WTF, StringHasher_addCharacters)
hasher.addCharacters(testBUChars + 3);
ASSERT_EQ(testBHash5, hasher.hash());
ASSERT_EQ(testBHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+
+ // Hashing zero characters after hashing other characters.
+ hasher = StringHasher();
+ hasher.addCharacters(nullLChars, 0);
+ hasher.addCharacters(nullLChars, 0);
+ ASSERT_EQ(emptyStringHash, hasher.hash());
+ ASSERT_EQ(emptyStringHash & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+
+ hasher = StringHasher();
+ hasher.addCharacters(testALChars, 1);
+ hasher.addCharacters(nullLChars, 0);
+ ASSERT_EQ(testAHash1, hasher.hash());
+ ASSERT_EQ(testAHash1 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+
+ hasher = StringHasher();
+ hasher.addCharacters(testALChars, 2);
+ hasher.addCharacters(nullLChars, 0);
+ ASSERT_EQ(testAHash2, hasher.hash());
+ ASSERT_EQ(testAHash2 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+
+ hasher = StringHasher();
+ hasher.addCharacters(testAUChars, 3);
+ hasher.addCharacters(nullLChars, 0);
+ ASSERT_EQ(testAHash3, hasher.hash());
+ ASSERT_EQ(testAHash3 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+
+ hasher = StringHasher();
+ hasher.addCharacters(testALChars, 4);
+ hasher.addCharacters(nullLChars, 0);
+ ASSERT_EQ(testAHash4, hasher.hash());
+ ASSERT_EQ(testAHash4 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+
+ hasher = StringHasher();
+ hasher.addCharacters(testALChars, 5);
+ hasher.addCharacters(nullLChars, 0);
+ ASSERT_EQ(testAHash5, hasher.hash());
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
}
TEST(WTF, StringHasher_addCharactersAssumingAligned)
@@ -427,18 +464,18 @@ TEST(WTF, StringHasher_computeHashAndMaskTop8Bits)
TEST(WTF, StringHasher_hashMemory)
{
- ASSERT_EQ(emptyStringHash & 0xFFFFFF, StringHasher::hashMemory(0, 0));
- ASSERT_EQ(emptyStringHash & 0xFFFFFF, StringHasher::hashMemory(nullUChars, 0));
- ASSERT_EQ(emptyStringHash & 0xFFFFFF, StringHasher::hashMemory<0>(0));
- ASSERT_EQ(emptyStringHash & 0xFFFFFF, StringHasher::hashMemory<0>(nullUChars));
-
- ASSERT_EQ(singleNullCharacterHash & 0xFFFFFF, StringHasher::hashMemory(nullUChars, 2));
- ASSERT_EQ(singleNullCharacterHash & 0xFFFFFF, StringHasher::hashMemory<2>(nullUChars));
-
- ASSERT_EQ(testAHash5 & 0xFFFFFF, StringHasher::hashMemory(testAUChars, 10));
- ASSERT_EQ(testAHash5 & 0xFFFFFF, StringHasher::hashMemory<10>(testAUChars));
- ASSERT_EQ(testBHash5 & 0xFFFFFF, StringHasher::hashMemory(testBUChars, 10));
- ASSERT_EQ(testBHash5 & 0xFFFFFF, StringHasher::hashMemory<10>(testBUChars));
+ ASSERT_EQ(emptyStringHash, StringHasher::hashMemory(0, 0));
+ ASSERT_EQ(emptyStringHash, StringHasher::hashMemory(nullUChars, 0));
+ ASSERT_EQ(emptyStringHash, StringHasher::hashMemory<0>(0));
+ ASSERT_EQ(emptyStringHash, StringHasher::hashMemory<0>(nullUChars));
+
+ ASSERT_EQ(singleNullCharacterHash, StringHasher::hashMemory(nullUChars, 2));
+ ASSERT_EQ(singleNullCharacterHash, StringHasher::hashMemory<2>(nullUChars));
+
+ ASSERT_EQ(testAHash5, StringHasher::hashMemory(testAUChars, 10));
+ ASSERT_EQ(testAHash5, StringHasher::hashMemory<10>(testAUChars));
+ ASSERT_EQ(testBHash5, StringHasher::hashMemory(testBUChars, 10));
+ ASSERT_EQ(testBHash5, StringHasher::hashMemory<10>(testBUChars));
}
} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/StringImpl.cpp b/Tools/TestWebKitAPI/Tests/WTF/StringImpl.cpp
index d5804f6b4..fdb701c90 100644
--- a/Tools/TestWebKitAPI/Tests/WTF/StringImpl.cpp
+++ b/Tools/TestWebKitAPI/Tests/WTF/StringImpl.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,7 +25,8 @@
#include "config.h"
-#include <wtf/text/StringImpl.h>
+#include <wtf/Hasher.h>
+#include <wtf/text/SymbolImpl.h>
#include <wtf/text/WTFString.h>
namespace TestWebKitAPI {
@@ -33,14 +34,14 @@ namespace TestWebKitAPI {
TEST(WTF, StringImplCreationFromLiteral)
{
// Constructor using the template to determine the size.
- RefPtr<StringImpl> stringWithTemplate = StringImpl::createFromLiteral("Template Literal");
+ auto stringWithTemplate = StringImpl::createFromLiteral("Template Literal");
ASSERT_EQ(strlen("Template Literal"), stringWithTemplate->length());
ASSERT_TRUE(equal(stringWithTemplate.get(), "Template Literal"));
ASSERT_TRUE(stringWithTemplate->is8Bit());
// Constructor taking the size explicitely.
const char* programmaticStringData = "Explicit Size Literal";
- RefPtr<StringImpl> programmaticString = StringImpl::createFromLiteral(programmaticStringData, strlen(programmaticStringData));
+ auto programmaticString = StringImpl::createFromLiteral(programmaticStringData, strlen(programmaticStringData));
ASSERT_EQ(strlen(programmaticStringData), programmaticString->length());
ASSERT_TRUE(equal(programmaticString.get(), programmaticStringData));
ASSERT_EQ(programmaticStringData, reinterpret_cast<const char*>(programmaticString->characters8()));
@@ -48,27 +49,16 @@ TEST(WTF, StringImplCreationFromLiteral)
// Constructor without explicit size.
const char* stringWithoutLengthLiteral = "No Size Literal";
- RefPtr<StringImpl> programmaticStringNoLength = StringImpl::createFromLiteral(stringWithoutLengthLiteral);
+ auto programmaticStringNoLength = StringImpl::createFromLiteral(stringWithoutLengthLiteral);
ASSERT_EQ(strlen(stringWithoutLengthLiteral), programmaticStringNoLength->length());
ASSERT_TRUE(equal(programmaticStringNoLength.get(), stringWithoutLengthLiteral));
ASSERT_EQ(stringWithoutLengthLiteral, reinterpret_cast<const char*>(programmaticStringNoLength->characters8()));
ASSERT_TRUE(programmaticStringNoLength->is8Bit());
}
-TEST(WTF, StringImplFromLiteralLoop16BitConversion)
-{
- RefPtr<StringImpl> controlString = StringImpl::create("Template Literal");
- for (size_t i = 0; i < 10; ++i) {
- RefPtr<StringImpl> string = StringImpl::createFromLiteral("Template Literal");
-
- ASSERT_EQ(0, memcmp(controlString->deprecatedCharacters(), string->deprecatedCharacters(), controlString->length() * sizeof(UChar)));
- ASSERT_TRUE(string->has16BitShadow());
- }
-}
-
TEST(WTF, StringImplReplaceWithLiteral)
{
- RefPtr<StringImpl> testStringImpl = StringImpl::createFromLiteral("1224");
+ auto testStringImpl = StringImpl::createFromLiteral("1224");
ASSERT_TRUE(testStringImpl->is8Bit());
// Cases for 8Bit source.
@@ -110,4 +100,530 @@ TEST(WTF, StringImplReplaceWithLiteral)
ASSERT_TRUE(equal(testStringImpl.get(), "r555sum555"));
}
+TEST(WTF, StringImplEqualIgnoringASCIICaseBasic)
+{
+ auto a = StringImpl::createFromLiteral("aBcDeFG");
+ auto b = StringImpl::createFromLiteral("ABCDEFG");
+ auto c = StringImpl::createFromLiteral("abcdefg");
+ const char d[] = "aBcDeFG";
+ auto empty = StringImpl::create(reinterpret_cast<const LChar*>(""));
+ auto shorter = StringImpl::createFromLiteral("abcdef");
+ auto different = StringImpl::createFromLiteral("abcrefg");
+
+ // Identity.
+ ASSERT_TRUE(equalIgnoringASCIICase(a.ptr(), a.ptr()));
+ ASSERT_TRUE(equalIgnoringASCIICase(b.ptr(), b.ptr()));
+ ASSERT_TRUE(equalIgnoringASCIICase(c.ptr(), c.ptr()));
+ ASSERT_TRUE(equalIgnoringASCIICase(a.ptr(), d));
+ ASSERT_TRUE(equalIgnoringASCIICase(b.ptr(), d));
+ ASSERT_TRUE(equalIgnoringASCIICase(c.ptr(), d));
+
+ // Transitivity.
+ ASSERT_TRUE(equalIgnoringASCIICase(a.ptr(), b.ptr()));
+ ASSERT_TRUE(equalIgnoringASCIICase(b.ptr(), c.ptr()));
+ ASSERT_TRUE(equalIgnoringASCIICase(a.ptr(), c.ptr()));
+
+ // Negative cases.
+ ASSERT_FALSE(equalIgnoringASCIICase(a.ptr(), empty.ptr()));
+ ASSERT_FALSE(equalIgnoringASCIICase(b.ptr(), empty.ptr()));
+ ASSERT_FALSE(equalIgnoringASCIICase(c.ptr(), empty.ptr()));
+ ASSERT_FALSE(equalIgnoringASCIICase(a.ptr(), shorter.ptr()));
+ ASSERT_FALSE(equalIgnoringASCIICase(b.ptr(), shorter.ptr()));
+ ASSERT_FALSE(equalIgnoringASCIICase(c.ptr(), shorter.ptr()));
+ ASSERT_FALSE(equalIgnoringASCIICase(a.ptr(), different.ptr()));
+ ASSERT_FALSE(equalIgnoringASCIICase(b.ptr(), different.ptr()));
+ ASSERT_FALSE(equalIgnoringASCIICase(c.ptr(), different.ptr()));
+ ASSERT_FALSE(equalIgnoringASCIICase(empty.ptr(), d));
+ ASSERT_FALSE(equalIgnoringASCIICase(shorter.ptr(), d));
+ ASSERT_FALSE(equalIgnoringASCIICase(different.ptr(), d));
+}
+
+TEST(WTF, StringImplEqualIgnoringASCIICaseWithNull)
+{
+ auto reference = StringImpl::createFromLiteral("aBcDeFG");
+ StringImpl* nullStringImpl = nullptr;
+ ASSERT_FALSE(equalIgnoringASCIICase(nullStringImpl, reference.ptr()));
+ ASSERT_FALSE(equalIgnoringASCIICase(reference.ptr(), nullStringImpl));
+ ASSERT_TRUE(equalIgnoringASCIICase(nullStringImpl, nullStringImpl));
+}
+
+TEST(WTF, StringImplEqualIgnoringASCIICaseWithEmpty)
+{
+ auto a = StringImpl::create(reinterpret_cast<const LChar*>(""));
+ auto b = StringImpl::create(reinterpret_cast<const LChar*>(""));
+ ASSERT_TRUE(equalIgnoringASCIICase(a.ptr(), b.ptr()));
+ ASSERT_TRUE(equalIgnoringASCIICase(b.ptr(), a.ptr()));
+}
+
+static Ref<StringImpl> stringFromUTF8(const char* characters)
+{
+ return String::fromUTF8(characters).releaseImpl().releaseNonNull();
+}
+
+TEST(WTF, StringImplEqualIgnoringASCIICaseWithLatin1Characters)
+{
+ auto a = stringFromUTF8("aBcéeFG");
+ auto b = stringFromUTF8("ABCÉEFG");
+ auto c = stringFromUTF8("ABCéEFG");
+ auto d = stringFromUTF8("abcéefg");
+ const char e[] = "aBcéeFG";
+
+ // Identity.
+ ASSERT_TRUE(equalIgnoringASCIICase(a.ptr(), a.ptr()));
+ ASSERT_TRUE(equalIgnoringASCIICase(b.ptr(), b.ptr()));
+ ASSERT_TRUE(equalIgnoringASCIICase(c.ptr(), c.ptr()));
+ ASSERT_TRUE(equalIgnoringASCIICase(d.ptr(), d.ptr()));
+
+ // All combination.
+ ASSERT_FALSE(equalIgnoringASCIICase(a.ptr(), b.ptr()));
+ ASSERT_TRUE(equalIgnoringASCIICase(a.ptr(), c.ptr()));
+ ASSERT_TRUE(equalIgnoringASCIICase(a.ptr(), d.ptr()));
+ ASSERT_FALSE(equalIgnoringASCIICase(b.ptr(), c.ptr()));
+ ASSERT_FALSE(equalIgnoringASCIICase(b.ptr(), d.ptr()));
+ ASSERT_TRUE(equalIgnoringASCIICase(c.ptr(), d.ptr()));
+ ASSERT_FALSE(equalIgnoringASCIICase(a.ptr(), e));
+ ASSERT_FALSE(equalIgnoringASCIICase(b.ptr(), e));
+ ASSERT_FALSE(equalIgnoringASCIICase(c.ptr(), e));
+ ASSERT_FALSE(equalIgnoringASCIICase(d.ptr(), e));
+}
+
+TEST(WTF, StringImplFindIgnoringASCIICaseBasic)
+{
+ auto referenceA = stringFromUTF8("aBcéeFG");
+ auto referenceB = stringFromUTF8("ABCÉEFG");
+
+ // Search the exact string.
+ EXPECT_EQ(static_cast<size_t>(0), referenceA->findIgnoringASCIICase(referenceA.ptr()));
+ EXPECT_EQ(static_cast<size_t>(0), referenceB->findIgnoringASCIICase(referenceB.ptr()));
+
+ // A and B are distinct by the non-ascii character é/É.
+ EXPECT_EQ(static_cast<size_t>(notFound), referenceA->findIgnoringASCIICase(referenceB.ptr()));
+ EXPECT_EQ(static_cast<size_t>(notFound), referenceB->findIgnoringASCIICase(referenceA.ptr()));
+
+ // Find the prefix.
+ EXPECT_EQ(static_cast<size_t>(0), referenceA->findIgnoringASCIICase(StringImpl::createFromLiteral("a").ptr()));
+ EXPECT_EQ(static_cast<size_t>(0), referenceA->findIgnoringASCIICase(stringFromUTF8("abcé").ptr()));
+ EXPECT_EQ(static_cast<size_t>(0), referenceA->findIgnoringASCIICase(StringImpl::createFromLiteral("A").ptr()));
+ EXPECT_EQ(static_cast<size_t>(0), referenceA->findIgnoringASCIICase(stringFromUTF8("ABCé").ptr()));
+ EXPECT_EQ(static_cast<size_t>(0), referenceB->findIgnoringASCIICase(StringImpl::createFromLiteral("a").ptr()));
+ EXPECT_EQ(static_cast<size_t>(0), referenceB->findIgnoringASCIICase(stringFromUTF8("abcÉ").ptr()));
+ EXPECT_EQ(static_cast<size_t>(0), referenceB->findIgnoringASCIICase(StringImpl::createFromLiteral("A").ptr()));
+ EXPECT_EQ(static_cast<size_t>(0), referenceB->findIgnoringASCIICase(stringFromUTF8("ABCÉ").ptr()));
+
+ // Not a prefix.
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(StringImpl::createFromLiteral("x").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("accé").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("abcÉ").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(StringImpl::createFromLiteral("X").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("ABDé").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("ABCÉ").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(StringImpl::createFromLiteral("y").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("accÉ").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("abcé").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(StringImpl::createFromLiteral("Y").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("ABdÉ").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("ABCé").ptr()));
+
+ // Find the infix.
+ EXPECT_EQ(static_cast<size_t>(2), referenceA->findIgnoringASCIICase(stringFromUTF8("cée").ptr()));
+ EXPECT_EQ(static_cast<size_t>(3), referenceA->findIgnoringASCIICase(stringFromUTF8("ée").ptr()));
+ EXPECT_EQ(static_cast<size_t>(2), referenceA->findIgnoringASCIICase(stringFromUTF8("cé").ptr()));
+ EXPECT_EQ(static_cast<size_t>(2), referenceA->findIgnoringASCIICase(stringFromUTF8("c").ptr()));
+ EXPECT_EQ(static_cast<size_t>(3), referenceA->findIgnoringASCIICase(stringFromUTF8("é").ptr()));
+ EXPECT_EQ(static_cast<size_t>(2), referenceA->findIgnoringASCIICase(stringFromUTF8("Cée").ptr()));
+ EXPECT_EQ(static_cast<size_t>(3), referenceA->findIgnoringASCIICase(stringFromUTF8("éE").ptr()));
+ EXPECT_EQ(static_cast<size_t>(2), referenceA->findIgnoringASCIICase(stringFromUTF8("Cé").ptr()));
+ EXPECT_EQ(static_cast<size_t>(2), referenceA->findIgnoringASCIICase(stringFromUTF8("C").ptr()));
+
+ EXPECT_EQ(static_cast<size_t>(2), referenceB->findIgnoringASCIICase(stringFromUTF8("cÉe").ptr()));
+ EXPECT_EQ(static_cast<size_t>(3), referenceB->findIgnoringASCIICase(stringFromUTF8("Ée").ptr()));
+ EXPECT_EQ(static_cast<size_t>(2), referenceB->findIgnoringASCIICase(stringFromUTF8("cÉ").ptr()));
+ EXPECT_EQ(static_cast<size_t>(2), referenceB->findIgnoringASCIICase(stringFromUTF8("c").ptr()));
+ EXPECT_EQ(static_cast<size_t>(3), referenceB->findIgnoringASCIICase(stringFromUTF8("É").ptr()));
+ EXPECT_EQ(static_cast<size_t>(2), referenceB->findIgnoringASCIICase(stringFromUTF8("CÉe").ptr()));
+ EXPECT_EQ(static_cast<size_t>(3), referenceB->findIgnoringASCIICase(stringFromUTF8("ÉE").ptr()));
+ EXPECT_EQ(static_cast<size_t>(2), referenceB->findIgnoringASCIICase(stringFromUTF8("CÉ").ptr()));
+ EXPECT_EQ(static_cast<size_t>(2), referenceB->findIgnoringASCIICase(stringFromUTF8("C").ptr()));
+
+ // Not an infix.
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("céd").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("Ée").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("bé").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("x").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("É").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("CÉe").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("éd").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("CÉ").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("Y").ptr()));
+
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("cée").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("Éc").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("cé").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("W").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("é").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("bÉe").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("éE").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("BÉ").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("z").ptr()));
+
+ // Find the suffix.
+ EXPECT_EQ(static_cast<size_t>(6), referenceA->findIgnoringASCIICase(StringImpl::createFromLiteral("g").ptr()));
+ EXPECT_EQ(static_cast<size_t>(4), referenceA->findIgnoringASCIICase(stringFromUTF8("efg").ptr()));
+ EXPECT_EQ(static_cast<size_t>(3), referenceA->findIgnoringASCIICase(stringFromUTF8("éefg").ptr()));
+ EXPECT_EQ(static_cast<size_t>(6), referenceA->findIgnoringASCIICase(StringImpl::createFromLiteral("G").ptr()));
+ EXPECT_EQ(static_cast<size_t>(4), referenceA->findIgnoringASCIICase(stringFromUTF8("EFG").ptr()));
+ EXPECT_EQ(static_cast<size_t>(3), referenceA->findIgnoringASCIICase(stringFromUTF8("éEFG").ptr()));
+
+ EXPECT_EQ(static_cast<size_t>(6), referenceB->findIgnoringASCIICase(StringImpl::createFromLiteral("g").ptr()));
+ EXPECT_EQ(static_cast<size_t>(4), referenceB->findIgnoringASCIICase(stringFromUTF8("efg").ptr()));
+ EXPECT_EQ(static_cast<size_t>(3), referenceB->findIgnoringASCIICase(stringFromUTF8("Éefg").ptr()));
+ EXPECT_EQ(static_cast<size_t>(6), referenceB->findIgnoringASCIICase(StringImpl::createFromLiteral("G").ptr()));
+ EXPECT_EQ(static_cast<size_t>(4), referenceB->findIgnoringASCIICase(stringFromUTF8("EFG").ptr()));
+ EXPECT_EQ(static_cast<size_t>(3), referenceB->findIgnoringASCIICase(stringFromUTF8("ÉEFG").ptr()));
+
+ // Not a suffix.
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(StringImpl::createFromLiteral("X").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("edg").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("Éefg").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(StringImpl::createFromLiteral("w").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("dFG").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("ÉEFG").ptr()));
+
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(StringImpl::createFromLiteral("Z").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("ffg").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("éefg").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(StringImpl::createFromLiteral("r").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("EgG").ptr()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("éEFG").ptr()));
+}
+
+TEST(WTF, StringImplFindIgnoringASCIICaseWithValidOffset)
+{
+ auto reference = stringFromUTF8("ABCÉEFGaBcéeFG");
+ EXPECT_EQ(static_cast<size_t>(0), reference->findIgnoringASCIICase(stringFromUTF8("ABC").ptr(), 0));
+ EXPECT_EQ(static_cast<size_t>(7), reference->findIgnoringASCIICase(stringFromUTF8("ABC").ptr(), 1));
+ EXPECT_EQ(static_cast<size_t>(0), reference->findIgnoringASCIICase(stringFromUTF8("ABCÉ").ptr(), 0));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(stringFromUTF8("ABCÉ").ptr(), 1));
+ EXPECT_EQ(static_cast<size_t>(7), reference->findIgnoringASCIICase(stringFromUTF8("ABCé").ptr(), 0));
+ EXPECT_EQ(static_cast<size_t>(7), reference->findIgnoringASCIICase(stringFromUTF8("ABCé").ptr(), 1));
+}
+
+TEST(WTF, StringImplFindIgnoringASCIICaseWithInvalidOffset)
+{
+ auto reference = stringFromUTF8("ABCÉEFGaBcéeFG");
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(stringFromUTF8("ABC").ptr(), 15));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(stringFromUTF8("ABC").ptr(), 16));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(stringFromUTF8("ABCÉ").ptr(), 17));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(stringFromUTF8("ABCÉ").ptr(), 42));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(stringFromUTF8("ABCÉ").ptr(), std::numeric_limits<unsigned>::max()));
+}
+
+TEST(WTF, StringImplFindIgnoringASCIICaseOnNull)
+{
+ auto reference = stringFromUTF8("ABCÉEFG");
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(nullptr));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(nullptr, 0));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(nullptr, 3));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(nullptr, 7));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(nullptr, 8));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(nullptr, 42));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(nullptr, std::numeric_limits<unsigned>::max()));
+}
+
+TEST(WTF, StringImplFindIgnoringASCIICaseOnEmpty)
+{
+ auto reference = stringFromUTF8("ABCÉEFG");
+ auto empty = StringImpl::create(reinterpret_cast<const LChar*>(""));
+ EXPECT_EQ(static_cast<size_t>(0), reference->findIgnoringASCIICase(empty.ptr()));
+ EXPECT_EQ(static_cast<size_t>(0), reference->findIgnoringASCIICase(empty.ptr(), 0));
+ EXPECT_EQ(static_cast<size_t>(3), reference->findIgnoringASCIICase(empty.ptr(), 3));
+ EXPECT_EQ(static_cast<size_t>(7), reference->findIgnoringASCIICase(empty.ptr(), 7));
+ EXPECT_EQ(static_cast<size_t>(7), reference->findIgnoringASCIICase(empty.ptr(), 8));
+ EXPECT_EQ(static_cast<size_t>(7), reference->findIgnoringASCIICase(empty.ptr(), 42));
+ EXPECT_EQ(static_cast<size_t>(7), reference->findIgnoringASCIICase(empty.ptr(), std::numeric_limits<unsigned>::max()));
+}
+
+TEST(WTF, StringImplFindIgnoringASCIICaseWithPatternLongerThanReference)
+{
+ auto reference = stringFromUTF8("ABCÉEFG");
+ auto pattern = stringFromUTF8("XABCÉEFG");
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(pattern.ptr()));
+ EXPECT_EQ(static_cast<size_t>(1), pattern->findIgnoringASCIICase(reference.ptr()));
+}
+
+TEST(WTF, StringImplStartsWithIgnoringASCIICaseBasic)
+{
+ auto reference = stringFromUTF8("aBcéX");
+ auto referenceEquivalent = stringFromUTF8("AbCéx");
+
+ // Identity.
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(reference.ptr()));
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*reference.ptr()));
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(referenceEquivalent.ptr()));
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*referenceEquivalent.ptr()));
+ ASSERT_TRUE(referenceEquivalent->startsWithIgnoringASCIICase(reference.ptr()));
+ ASSERT_TRUE(referenceEquivalent->startsWithIgnoringASCIICase(*reference.ptr()));
+ ASSERT_TRUE(referenceEquivalent->startsWithIgnoringASCIICase(referenceEquivalent.ptr()));
+ ASSERT_TRUE(referenceEquivalent->startsWithIgnoringASCIICase(*referenceEquivalent.ptr()));
+
+ // Proper prefixes.
+ auto aLower = StringImpl::createFromLiteral("a");
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(aLower.ptr()));
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*aLower.ptr()));
+ auto aUpper = StringImpl::createFromLiteral("A");
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(aUpper.ptr()));
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*aUpper.ptr()));
+
+ auto abcLower = StringImpl::createFromLiteral("abc");
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(abcLower.ptr()));
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*abcLower.ptr()));
+ auto abcUpper = StringImpl::createFromLiteral("ABC");
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(abcUpper.ptr()));
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*abcUpper.ptr()));
+
+ auto abcAccentLower = stringFromUTF8("abcé");
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(abcAccentLower.ptr()));
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*abcAccentLower.ptr()));
+ auto abcAccentUpper = stringFromUTF8("ABCé");
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(abcAccentUpper.ptr()));
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*abcAccentUpper.ptr()));
+
+ // Negative cases.
+ auto differentFirstChar = stringFromUTF8("bBcéX");
+ auto differentFirstCharProperPrefix = stringFromUTF8("CBcé");
+ ASSERT_FALSE(reference->startsWithIgnoringASCIICase(differentFirstChar.ptr()));
+ ASSERT_FALSE(reference->startsWithIgnoringASCIICase(*differentFirstChar.ptr()));
+ ASSERT_FALSE(reference->startsWithIgnoringASCIICase(differentFirstCharProperPrefix.ptr()));
+ ASSERT_FALSE(reference->startsWithIgnoringASCIICase(*differentFirstCharProperPrefix.ptr()));
+
+ auto uppercaseAccent = stringFromUTF8("aBcÉX");
+ auto uppercaseAccentProperPrefix = stringFromUTF8("aBcÉX");
+ ASSERT_FALSE(reference->startsWithIgnoringASCIICase(uppercaseAccent.ptr()));
+ ASSERT_FALSE(reference->startsWithIgnoringASCIICase(*uppercaseAccent.ptr()));
+ ASSERT_FALSE(reference->startsWithIgnoringASCIICase(uppercaseAccentProperPrefix.ptr()));
+ ASSERT_FALSE(reference->startsWithIgnoringASCIICase(*uppercaseAccentProperPrefix.ptr()));
+}
+
+TEST(WTF, StringImplStartsWithIgnoringASCIICaseWithNull)
+{
+ auto reference = StringImpl::createFromLiteral("aBcDeFG");
+ ASSERT_FALSE(reference->startsWithIgnoringASCIICase(nullptr));
+
+ auto empty = StringImpl::create(reinterpret_cast<const LChar*>(""));
+ ASSERT_FALSE(empty->startsWithIgnoringASCIICase(nullptr));
+}
+
+TEST(WTF, StringImplStartsWithIgnoringASCIICaseWithEmpty)
+{
+ auto reference = StringImpl::createFromLiteral("aBcDeFG");
+ auto empty = StringImpl::create(reinterpret_cast<const LChar*>(""));
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(empty.ptr()));
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*empty.ptr()));
+ ASSERT_TRUE(empty->startsWithIgnoringASCIICase(empty.ptr()));
+ ASSERT_TRUE(empty->startsWithIgnoringASCIICase(*empty.ptr()));
+ ASSERT_FALSE(empty->startsWithIgnoringASCIICase(reference.ptr()));
+ ASSERT_FALSE(empty->startsWithIgnoringASCIICase(*reference.ptr()));
+}
+
+TEST(WTF, StartsWithLettersIgnoringASCIICase)
+{
+ String string("Test tEST");
+ ASSERT_TRUE(startsWithLettersIgnoringASCIICase(string, "test t"));
+ ASSERT_TRUE(startsWithLettersIgnoringASCIICase(string, "test te"));
+ ASSERT_TRUE(startsWithLettersIgnoringASCIICase(string, "test test"));
+ ASSERT_FALSE(startsWithLettersIgnoringASCIICase(string, "test tex"));
+
+ ASSERT_TRUE(startsWithLettersIgnoringASCIICase(string, ""));
+ ASSERT_TRUE(startsWithLettersIgnoringASCIICase(String(""), ""));
+
+ ASSERT_FALSE(startsWithLettersIgnoringASCIICase(String(), "t"));
+ ASSERT_FALSE(startsWithLettersIgnoringASCIICase(String(), ""));
+}
+
+TEST(WTF, StringImplEndsWithIgnoringASCIICaseBasic)
+{
+ auto reference = stringFromUTF8("XÉCbA");
+ auto referenceEquivalent = stringFromUTF8("xÉcBa");
+
+ // Identity.
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(reference.ptr()));
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*reference.ptr()));
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(referenceEquivalent.ptr()));
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*referenceEquivalent.ptr()));
+ ASSERT_TRUE(referenceEquivalent->endsWithIgnoringASCIICase(reference.ptr()));
+ ASSERT_TRUE(referenceEquivalent->endsWithIgnoringASCIICase(*reference.ptr()));
+ ASSERT_TRUE(referenceEquivalent->endsWithIgnoringASCIICase(referenceEquivalent.ptr()));
+ ASSERT_TRUE(referenceEquivalent->endsWithIgnoringASCIICase(*referenceEquivalent.ptr()));
+
+ // Proper suffixes.
+ auto aLower = StringImpl::createFromLiteral("a");
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(aLower.ptr()));
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*aLower.ptr()));
+ auto aUpper = StringImpl::createFromLiteral("a");
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(aUpper.ptr()));
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*aUpper.ptr()));
+
+ auto abcLower = StringImpl::createFromLiteral("cba");
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(abcLower.ptr()));
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*abcLower.ptr()));
+ auto abcUpper = StringImpl::createFromLiteral("CBA");
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(abcUpper.ptr()));
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*abcUpper.ptr()));
+
+ auto abcAccentLower = stringFromUTF8("Écba");
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(abcAccentLower.ptr()));
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*abcAccentLower.ptr()));
+ auto abcAccentUpper = stringFromUTF8("ÉCBA");
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(abcAccentUpper.ptr()));
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*abcAccentUpper.ptr()));
+
+ // Negative cases.
+ auto differentLastChar = stringFromUTF8("XÉCbB");
+ auto differentLastCharProperSuffix = stringFromUTF8("ÉCbb");
+ ASSERT_FALSE(reference->endsWithIgnoringASCIICase(differentLastChar.ptr()));
+ ASSERT_FALSE(reference->endsWithIgnoringASCIICase(*differentLastChar.ptr()));
+ ASSERT_FALSE(reference->endsWithIgnoringASCIICase(differentLastCharProperSuffix.ptr()));
+ ASSERT_FALSE(reference->endsWithIgnoringASCIICase(*differentLastCharProperSuffix.ptr()));
+
+ auto lowercaseAccent = stringFromUTF8("aBcéX");
+ auto loweraseAccentProperSuffix = stringFromUTF8("aBcéX");
+ ASSERT_FALSE(reference->endsWithIgnoringASCIICase(lowercaseAccent.ptr()));
+ ASSERT_FALSE(reference->endsWithIgnoringASCIICase(*lowercaseAccent.ptr()));
+ ASSERT_FALSE(reference->endsWithIgnoringASCIICase(loweraseAccentProperSuffix.ptr()));
+ ASSERT_FALSE(reference->endsWithIgnoringASCIICase(*loweraseAccentProperSuffix.ptr()));
+}
+
+TEST(WTF, StringImplEndsWithIgnoringASCIICaseWithNull)
+{
+ auto reference = StringImpl::createFromLiteral("aBcDeFG");
+ ASSERT_FALSE(reference->endsWithIgnoringASCIICase(nullptr));
+
+ auto empty = StringImpl::create(reinterpret_cast<const LChar*>(""));
+ ASSERT_FALSE(empty->endsWithIgnoringASCIICase(nullptr));
+}
+
+TEST(WTF, StringImplEndsWithIgnoringASCIICaseWithEmpty)
+{
+ auto reference = StringImpl::createFromLiteral("aBcDeFG");
+ auto empty = StringImpl::create(reinterpret_cast<const LChar*>(""));
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(empty.ptr()));
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*empty.ptr()));
+ ASSERT_TRUE(empty->endsWithIgnoringASCIICase(empty.ptr()));
+ ASSERT_TRUE(empty->endsWithIgnoringASCIICase(*empty.ptr()));
+ ASSERT_FALSE(empty->endsWithIgnoringASCIICase(reference.ptr()));
+ ASSERT_FALSE(empty->endsWithIgnoringASCIICase(*reference.ptr()));
+}
+
+TEST(WTF, StringImplCreateNullSymbol)
+{
+ auto reference = SymbolImpl::createNullSymbol();
+ ASSERT_TRUE(reference->isSymbol());
+ ASSERT_TRUE(reference->isNullSymbol());
+ ASSERT_FALSE(reference->isAtomic());
+ ASSERT_EQ(0u, reference->length());
+ ASSERT_TRUE(equal(reference.ptr(), ""));
+}
+
+TEST(WTF, StringImplCreateSymbol)
+{
+ auto original = stringFromUTF8("original");
+ auto reference = SymbolImpl::create(original);
+ ASSERT_TRUE(reference->isSymbol());
+ ASSERT_FALSE(reference->isNullSymbol());
+ ASSERT_FALSE(reference->isAtomic());
+ ASSERT_FALSE(original->isSymbol());
+ ASSERT_FALSE(original->isAtomic());
+ ASSERT_EQ(original->length(), reference->length());
+ ASSERT_TRUE(equal(reference.ptr(), "original"));
+
+ auto empty = stringFromUTF8("");
+ auto emptyReference = SymbolImpl::create(empty);
+ ASSERT_TRUE(emptyReference->isSymbol());
+ ASSERT_FALSE(emptyReference->isNullSymbol());
+ ASSERT_FALSE(emptyReference->isAtomic());
+ ASSERT_FALSE(empty->isSymbol());
+ ASSERT_TRUE(empty->isAtomic());
+ ASSERT_EQ(empty->length(), emptyReference->length());
+ ASSERT_TRUE(equal(emptyReference.ptr(), ""));
+}
+
+TEST(WTF, StringImplSymbolToAtomicString)
+{
+ auto original = stringFromUTF8("original");
+ auto reference = SymbolImpl::create(original);
+ ASSERT_TRUE(reference->isSymbol());
+ ASSERT_FALSE(reference->isAtomic());
+
+ auto result = AtomicStringImpl::lookUp(reference.ptr());
+ ASSERT_FALSE(result);
+
+ auto atomic = AtomicStringImpl::add(reference.ptr());
+ ASSERT_TRUE(atomic->isAtomic());
+ ASSERT_FALSE(atomic->isSymbol());
+ ASSERT_TRUE(reference->isSymbol());
+ ASSERT_FALSE(reference->isAtomic());
+
+ auto result2 = AtomicStringImpl::lookUp(reference.ptr());
+ ASSERT_TRUE(result2);
+}
+
+TEST(WTF, StringImplNullSymbolToAtomicString)
+{
+ auto reference = SymbolImpl::createNullSymbol();
+ ASSERT_TRUE(reference->isSymbol());
+ ASSERT_FALSE(reference->isAtomic());
+
+ // Because the substring of the reference is the empty string which is already interned.
+ auto result = AtomicStringImpl::lookUp(reference.ptr());
+ ASSERT_TRUE(result);
+
+ auto atomic = AtomicStringImpl::add(reference.ptr());
+ ASSERT_TRUE(atomic->isAtomic());
+ ASSERT_FALSE(atomic->isSymbol());
+ ASSERT_TRUE(reference->isSymbol());
+ ASSERT_FALSE(reference->isAtomic());
+ ASSERT_EQ(atomic.get(), StringImpl::empty());
+
+ auto result2 = AtomicStringImpl::lookUp(reference.ptr());
+ ASSERT_TRUE(result2);
+}
+
+static StringImpl::StaticStringImpl staticString {"Cocoa"};
+
+TEST(WTF, StringImplStaticToAtomicString)
+{
+ StringImpl& original = staticString;
+ ASSERT_FALSE(original.isSymbol());
+ ASSERT_FALSE(original.isAtomic());
+ ASSERT_TRUE(original.isStatic());
+
+ auto result = AtomicStringImpl::lookUp(&original);
+ ASSERT_FALSE(result);
+
+ auto atomic = AtomicStringImpl::add(&original);
+ ASSERT_TRUE(atomic->isAtomic());
+ ASSERT_FALSE(atomic->isSymbol());
+ ASSERT_FALSE(atomic->isStatic());
+ ASSERT_FALSE(original.isSymbol());
+ ASSERT_FALSE(original.isAtomic());
+ ASSERT_TRUE(original.isStatic());
+
+ auto result2 = AtomicStringImpl::lookUp(&original);
+ ASSERT_TRUE(result2);
+}
+
+TEST(WTF, StringImplConstexprHasher)
+{
+ ASSERT_EQ(stringFromUTF8("")->hash(), StringHasher::computeLiteralHashAndMaskTop8Bits(""));
+ ASSERT_EQ(stringFromUTF8("A")->hash(), StringHasher::computeLiteralHashAndMaskTop8Bits("A"));
+ ASSERT_EQ(stringFromUTF8("AA")->hash(), StringHasher::computeLiteralHashAndMaskTop8Bits("AA"));
+ ASSERT_EQ(stringFromUTF8("Cocoa")->hash(), StringHasher::computeLiteralHashAndMaskTop8Bits("Cocoa"));
+ ASSERT_EQ(stringFromUTF8("Cappuccino")->hash(), StringHasher::computeLiteralHashAndMaskTop8Bits("Cappuccino"));
+}
+
+TEST(WTF, StringImplEmpty)
+{
+ ASSERT_FALSE(StringImpl::empty()->length());
+}
+
} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/StringOperators.cpp b/Tools/TestWebKitAPI/Tests/WTF/StringOperators.cpp
index 149b85b21..7a1d9297f 100644
--- a/Tools/TestWebKitAPI/Tests/WTF/StringOperators.cpp
+++ b/Tools/TestWebKitAPI/Tests/WTF/StringOperators.cpp
@@ -184,4 +184,20 @@ TEST(WTF, StringOperators)
#endif
}
+TEST(WTF, ConcatenateCharacterArrayAndEmptyString)
+{
+ String emptyString;
+ EXPECT_EQ(static_cast<unsigned>(0), emptyString.length());
+
+ UChar ucharArray[] = { 't', 'e', 's', 't', '\0' };
+ String concatenation16 = ucharArray + emptyString;
+ ASSERT_EQ(static_cast<unsigned>(4), concatenation16.length());
+ ASSERT_TRUE(concatenation16 == String(ucharArray));
+
+ LChar lcharArray[] = { 't', 'e', 's', 't', '\0' };
+ String concatenation8 = lcharArray + emptyString;
+ ASSERT_EQ(static_cast<unsigned>(4), concatenation8.length());
+ ASSERT_TRUE(concatenation8 == String(lcharArray));
+}
+
} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/StringView.cpp b/Tools/TestWebKitAPI/Tests/WTF/StringView.cpp
new file mode 100644
index 000000000..93592834a
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/StringView.cpp
@@ -0,0 +1,928 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/StringView.h>
+
+namespace TestWebKitAPI {
+
+StringView stringViewFromLiteral(const char* characters)
+{
+ return StringView(reinterpret_cast<const LChar*>(characters), strlen(characters));
+}
+
+StringView stringViewFromUTF8(String &ref, const char* characters)
+{
+ ref = String::fromUTF8(characters);
+ return ref;
+}
+
+TEST(WTF, StringViewEmptyVsNull)
+{
+ StringView nullView;
+ EXPECT_TRUE(nullView.isNull());
+ EXPECT_TRUE(nullView.isEmpty());
+
+ // Test in a boolean context to test operator bool().
+ if (nullView)
+ FAIL();
+ else
+ SUCCEED();
+
+ if (!nullView)
+ SUCCEED();
+ else
+ FAIL();
+
+ StringView emptyView = StringView::empty();
+ EXPECT_FALSE(emptyView.isNull());
+ EXPECT_TRUE(emptyView.isEmpty());
+
+ // Test in a boolean context to test operator bool().
+ if (emptyView)
+ SUCCEED();
+ else
+ FAIL();
+
+ if (!emptyView)
+ FAIL();
+ else
+ SUCCEED();
+
+ StringView viewWithCharacters(String("hello"));
+ EXPECT_FALSE(viewWithCharacters.isNull());
+ EXPECT_FALSE(viewWithCharacters.isEmpty());
+
+ // Test in a boolean context to test operator bool().
+ if (viewWithCharacters)
+ SUCCEED();
+ else
+ FAIL();
+
+ if (!viewWithCharacters)
+ FAIL();
+ else
+ SUCCEED();
+}
+
+bool compareLoopIterations(StringView::GraphemeClusters graphemeClusters, std::vector<StringView> expected)
+{
+ std::vector<StringView> actual;
+ for (auto graphemeCluster : graphemeClusters)
+ actual.push_back(graphemeCluster);
+ return actual == expected;
+}
+
+bool compareLoopIterations(StringView::CodePoints codePoints, std::vector<UChar32> expected)
+{
+ std::vector<UChar32> actual;
+ for (auto codePoint : codePoints)
+ actual.push_back(codePoint);
+ return actual == expected;
+}
+
+static bool compareLoopIterations(StringView::CodeUnits codeUnits, std::vector<UChar> expected)
+{
+ std::vector<UChar> actual;
+ for (auto codeUnit : codeUnits)
+ actual.push_back(codeUnit);
+ return actual == expected;
+}
+
+static void build(StringBuilder& builder, std::vector<UChar> input)
+{
+ builder.clear();
+ for (auto codeUnit : input)
+ builder.append(codeUnit);
+}
+
+TEST(WTF, StringViewIterators)
+{
+ EXPECT_TRUE(compareLoopIterations(StringView().codePoints(), { }));
+ EXPECT_TRUE(compareLoopIterations(StringView().codeUnits(), { }));
+ EXPECT_TRUE(compareLoopIterations(StringView().graphemeClusters(), { }));
+
+ EXPECT_TRUE(compareLoopIterations(StringView::empty().codePoints(), { }));
+ EXPECT_TRUE(compareLoopIterations(StringView::empty().codeUnits(), { }));
+ EXPECT_TRUE(compareLoopIterations(StringView::empty().graphemeClusters(), { }));
+
+ String helo("helo");
+ StringView heloView(helo);
+
+ auto codePoints = heloView.codePoints();
+ auto codePointsIterator = codePoints.begin();
+ EXPECT_EQ(*codePointsIterator, 'h');
+ EXPECT_EQ(*codePointsIterator, 'h');
+ ++codePointsIterator;
+ ++codePointsIterator;
+ EXPECT_EQ(*codePointsIterator, 'l');
+ auto savedIterator = codePointsIterator;
+ codePointsIterator = codePoints.begin();
+ EXPECT_EQ(*codePointsIterator, 'h');
+ codePointsIterator = savedIterator;
+ EXPECT_EQ(*codePointsIterator, 'l');
+ String webkit("webkit");
+ auto webkitCodePoints = StringView(webkit).codePoints();
+ codePointsIterator = webkitCodePoints.begin();
+ ++codePointsIterator;
+ ++codePointsIterator;
+ EXPECT_EQ(*codePointsIterator, 'b');
+ while (codePointsIterator != webkitCodePoints.end())
+ ++codePointsIterator;
+
+ EXPECT_TRUE(compareLoopIterations(heloView.codePoints(), {'h', 'e', 'l', 'o'}));
+ EXPECT_TRUE(compareLoopIterations(heloView.codeUnits(), {'h', 'e', 'l', 'o'}));
+ EXPECT_TRUE(compareLoopIterations(heloView.graphemeClusters(), {
+ StringView(heloView.characters8(), 1),
+ StringView(heloView.characters8() + 1, 1),
+ StringView(heloView.characters8() + 2, 1),
+ StringView(heloView.characters8() + 3, 1)}));
+
+ StringBuilder b;
+ build(b, {0xD800, 0xDD55}); // Surrogates for unicode code point U+10155
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0x10155}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0xD800, 0xDD55}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).graphemeClusters(), {StringView(b.toString())}));
+
+ build(b, {0xD800}); // Leading surrogate only
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0xD800}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0xD800}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).graphemeClusters(), {StringView(b.toString())}));
+
+ build(b, {0xD800, 0xD801}); // Two leading surrogates
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0xD800, 0xD801}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0xD800, 0xD801}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).graphemeClusters(), {StringView(b.characters16(), 1), StringView(b.characters16() + 1, 1)}));
+
+ build(b, {0xDD55}); // Trailing surrogate only
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0xDD55}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0xDD55}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).graphemeClusters(), {StringView(b.toString())}));
+
+ build(b, {0xD800, 'h'}); // Leading surrogate followed by non-surrogate
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0xD800, 'h'}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0xD800, 'h'}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).graphemeClusters(), {StringView(b.characters16(), 1), StringView(b.characters16() + 1, 1)}));
+
+ build(b, {0x0306}); // "COMBINING BREVE"
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0x0306}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0x0306}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).graphemeClusters(), {StringView(b.toString())}));
+
+ build(b, {0x0306, 0xD800, 0xDD55, 'h', 'e', 'l', 'o'}); // Mix of single code unit and multi code unit code points
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0x0306, 0x10155, 'h', 'e', 'l', 'o'}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0x0306, 0xD800, 0xDD55, 'h', 'e', 'l', 'o'}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).graphemeClusters(), {
+ StringView(b.characters16(), 1),
+ StringView(b.characters16() + 1, 2),
+ StringView(b.characters16() + 3, 1),
+ StringView(b.characters16() + 4, 1),
+ StringView(b.characters16() + 5, 1),
+ StringView(b.characters16() + 6, 1)}));
+
+ build(b, {'e', 0x0301}); // "COMBINING ACUTE"
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {'e', 0x0301}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {'e', 0x0301}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).graphemeClusters(), {StringView(b.toString())}));
+
+ build(b, {'e', 0x0301, 0x0306, 'a'}); // "COMBINING ACUTE" "COMBINING BREVE"
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {'e', 0x0301, 0x0306, 'a'}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {'e', 0x0301, 0x0306, 'a'}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).graphemeClusters(), {
+ StringView(b.characters16(), 3),
+ StringView(b.characters16() + 3, 1),
+ }));
+
+ build(b, {0x1112, 0x116f, 0x11b6, 0x1107, 0x1161, 0x11B8}); // Korean combining Jamo
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0x1112, 0x116f, 0x11b6, 0x1107, 0x1161, 0x11B8}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0x1112, 0x116f, 0x11b6, 0x1107, 0x1161, 0x11B8}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).graphemeClusters(), {
+ StringView(b.characters16(), 3),
+ StringView(b.characters16() + 3, 3)}));
+}
+
+static Vector<String> vectorFromSplitResult(const StringView::SplitResult& substrings)
+{
+ Vector<String> result;
+ for (StringView substring : substrings)
+ result.append(substring.toString());
+ return result;
+}
+
+TEST(WTF, StringViewSplitEmptyAndNullStrings)
+{
+ StringView a = emptyString();
+ auto splitResult = a.split('b');
+ EXPECT_TRUE(splitResult.begin() == splitResult.end());
+
+ a = { String { } };
+ splitResult = a.split('b');
+ EXPECT_TRUE(splitResult.begin() == splitResult.end());
+
+ a = { };
+ splitResult = a.split('b');
+ EXPECT_TRUE(splitResult.begin() == splitResult.end());
+}
+
+TEST(WTF, StringViewSplitBasic)
+{
+ String referenceHolder;
+ StringView a = stringViewFromUTF8(referenceHolder, "This is a sentence.");
+
+ // Simple
+ Vector<String> actual = vectorFromSplitResult(a.split('T'));
+ Vector<String> expected({ "his is a sentence." });
+ ASSERT_EQ(expected.size(), actual.size());
+ for (size_t i = 0; i < actual.size(); ++i)
+ EXPECT_STREQ(expected[i].utf8().data(), actual[i].utf8().data()) << "Vectors differ at index " << i;
+
+ actual = vectorFromSplitResult(a.split('.'));
+ expected = { "This is a sentence" };
+ ASSERT_EQ(expected.size(), actual.size());
+ for (size_t i = 0; i < actual.size(); ++i)
+ EXPECT_STREQ(expected[i].utf8().data(), actual[i].utf8().data()) << "Vectors differ at index " << i;
+
+ actual = vectorFromSplitResult(a.split('a'));
+ expected = { "This is ", " sentence." };
+ ASSERT_EQ(expected.size(), actual.size());
+ for (size_t i = 0; i < actual.size(); ++i)
+ EXPECT_STREQ(expected[i].utf8().data(), actual[i].utf8().data()) << "Vectors differ at index " << i;
+
+ actual = vectorFromSplitResult(a.split(' '));
+ expected = { "This", "is", "a", "sentence." };
+ ASSERT_EQ(expected.size(), actual.size());
+ for (size_t i = 0; i < actual.size(); ++i)
+ EXPECT_STREQ(expected[i].utf8().data(), actual[i].utf8().data()) << "Vectors differ at index " << i;
+
+ // Non-existent separator
+ actual = vectorFromSplitResult(a.split('z'));
+ expected = { "This is a sentence." };
+ ASSERT_EQ(expected.size(), actual.size());
+ for (size_t i = 0; i < actual.size(); ++i)
+ EXPECT_STREQ(expected[i].utf8().data(), actual[i].utf8().data()) << "Vectors differ at index " << i;
+}
+
+TEST(WTF, StringViewSplitWithConsecutiveSeparators)
+{
+ String referenceHolder;
+ StringView a = stringViewFromUTF8(referenceHolder, "This is a sentence.");
+
+ Vector<String> actual = vectorFromSplitResult(a.split(' '));
+ Vector<String> expected({ "This", "is", "a", "sentence." });
+ ASSERT_EQ(expected.size(), actual.size());
+ for (size_t i = 0; i < actual.size(); ++i)
+ EXPECT_STREQ(expected[i].utf8().data(), actual[i].utf8().data()) << "Vectors differ at index " << i;
+}
+
+TEST(WTF, StringViewEqualIgnoringASCIICaseBasic)
+{
+ RefPtr<StringImpl> a = StringImpl::createFromLiteral("aBcDeFG");
+ RefPtr<StringImpl> b = StringImpl::createFromLiteral("ABCDEFG");
+ RefPtr<StringImpl> c = StringImpl::createFromLiteral("abcdefg");
+ const char d[] = "aBcDeFG";
+ RefPtr<StringImpl> empty = StringImpl::create(reinterpret_cast<const LChar*>(""));
+ RefPtr<StringImpl> shorter = StringImpl::createFromLiteral("abcdef");
+ RefPtr<StringImpl> different = StringImpl::createFromLiteral("abcrefg");
+
+ StringView stringViewA(*a.get());
+ StringView stringViewB(*b.get());
+ StringView stringViewC(*c.get());
+ StringView emptyStringView(*empty.get());
+ StringView shorterStringView(*shorter.get());
+ StringView differentStringView(*different.get());
+
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewA, stringViewB));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewB, stringViewC));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewB, stringViewC));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewA, d));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewB, d));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewC, d));
+
+ // Identity.
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewA, stringViewA));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewB, stringViewB));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewC, stringViewC));
+
+ // Transitivity.
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewA, stringViewB));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewB, stringViewC));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewA, stringViewC));
+
+ // Negative cases.
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewA, emptyStringView));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewB, emptyStringView));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewC, emptyStringView));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewA, shorterStringView));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewB, shorterStringView));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewC, shorterStringView));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewA, differentStringView));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewB, differentStringView));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewC, differentStringView));
+ ASSERT_FALSE(equalIgnoringASCIICase(emptyStringView, d));
+ ASSERT_FALSE(equalIgnoringASCIICase(shorterStringView, d));
+ ASSERT_FALSE(equalIgnoringASCIICase(differentStringView, d));
+}
+
+TEST(WTF, StringViewEqualIgnoringASCIICaseWithEmpty)
+{
+ RefPtr<StringImpl> a = StringImpl::create(reinterpret_cast<const LChar*>(""));
+ RefPtr<StringImpl> b = StringImpl::create(reinterpret_cast<const LChar*>(""));
+ StringView stringViewA(*a.get());
+ StringView stringViewB(*b.get());
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewA, stringViewB));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewB, stringViewA));
+}
+
+TEST(WTF, StringViewEqualIgnoringASCIICaseWithLatin1Characters)
+{
+ RefPtr<StringImpl> a = StringImpl::create(reinterpret_cast<const LChar*>("aBcéeFG"));
+ RefPtr<StringImpl> b = StringImpl::create(reinterpret_cast<const LChar*>("ABCÉEFG"));
+ RefPtr<StringImpl> c = StringImpl::create(reinterpret_cast<const LChar*>("ABCéEFG"));
+ RefPtr<StringImpl> d = StringImpl::create(reinterpret_cast<const LChar*>("abcéefg"));
+ const char e[] = "aBcéeFG";
+ StringView stringViewA(*a.get());
+ StringView stringViewB(*b.get());
+ StringView stringViewC(*c.get());
+ StringView stringViewD(*d.get());
+
+ // Identity.
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewA, stringViewA));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewB, stringViewB));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewC, stringViewC));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewD, stringViewD));
+
+ // All combination.
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewA, stringViewB));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewA, stringViewC));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewA, stringViewD));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewB, stringViewC));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewB, stringViewD));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewC, stringViewD));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewA, e));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewB, e));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewC, e));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewD, e));
+}
+
+TEST(WTF, StringViewFindIgnoringASCIICaseBasic)
+{
+ String referenceAHolder;
+ StringView referenceA = stringViewFromUTF8(referenceAHolder, "aBcéeFG");
+ String referenceBHolder;
+ StringView referenceB = stringViewFromUTF8(referenceBHolder, "ABCÉEFG");
+
+ // Search the exact string.
+ EXPECT_EQ(static_cast<size_t>(0), referenceA.findIgnoringASCIICase(referenceA));
+ EXPECT_EQ(static_cast<size_t>(0), referenceB.findIgnoringASCIICase(referenceB));
+
+ // A and B are distinct by the non-ascii character é/É.
+ EXPECT_EQ(static_cast<size_t>(notFound), referenceA.findIgnoringASCIICase(referenceB));
+ EXPECT_EQ(static_cast<size_t>(notFound), referenceB.findIgnoringASCIICase(referenceA));
+
+ String tempStringHolder;
+ // Find the prefix.
+ EXPECT_EQ(static_cast<size_t>(0), referenceA.findIgnoringASCIICase(stringViewFromLiteral("a")));
+ EXPECT_EQ(static_cast<size_t>(0), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "abcé")));
+ EXPECT_EQ(static_cast<size_t>(0), referenceA.findIgnoringASCIICase(stringViewFromLiteral("A")));
+ EXPECT_EQ(static_cast<size_t>(0), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCé")));
+ EXPECT_EQ(static_cast<size_t>(0), referenceB.findIgnoringASCIICase(stringViewFromLiteral("a")));
+ EXPECT_EQ(static_cast<size_t>(0), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "abcÉ")));
+ EXPECT_EQ(static_cast<size_t>(0), referenceB.findIgnoringASCIICase(stringViewFromLiteral("A")));
+ EXPECT_EQ(static_cast<size_t>(0), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCÉ")));
+
+ // Not a prefix.
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromLiteral("x")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "accé")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "abcÉ")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromLiteral("X")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABDé")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCÉ")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromLiteral("y")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "accÉ")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "abcé")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromLiteral("Y")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABdÉ")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCé")));
+
+ // Find the infix.
+ EXPECT_EQ(static_cast<size_t>(2), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "cée")));
+ EXPECT_EQ(static_cast<size_t>(3), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ée")));
+ EXPECT_EQ(static_cast<size_t>(2), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "cé")));
+ EXPECT_EQ(static_cast<size_t>(2), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "c")));
+ EXPECT_EQ(static_cast<size_t>(3), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "é")));
+ EXPECT_EQ(static_cast<size_t>(2), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "Cée")));
+ EXPECT_EQ(static_cast<size_t>(3), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "éE")));
+ EXPECT_EQ(static_cast<size_t>(2), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "Cé")));
+ EXPECT_EQ(static_cast<size_t>(2), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "C")));
+
+ EXPECT_EQ(static_cast<size_t>(2), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "cÉe")));
+ EXPECT_EQ(static_cast<size_t>(3), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "Ée")));
+ EXPECT_EQ(static_cast<size_t>(2), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "cÉ")));
+ EXPECT_EQ(static_cast<size_t>(2), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "c")));
+ EXPECT_EQ(static_cast<size_t>(3), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "É")));
+ EXPECT_EQ(static_cast<size_t>(2), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "CÉe")));
+ EXPECT_EQ(static_cast<size_t>(3), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ÉE")));
+ EXPECT_EQ(static_cast<size_t>(2), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "CÉ")));
+ EXPECT_EQ(static_cast<size_t>(2), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "C")));
+
+ // Not an infix.
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "céd")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "Ée")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "bé")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "x")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "É")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "CÉe")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "éd")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "CÉ")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "Y")));
+
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "cée")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "Éc")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "cé")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "W")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "é")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "bÉe")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "éE")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "BÉ")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "z")));
+
+ // Find the suffix.
+ EXPECT_EQ(static_cast<size_t>(6), referenceA.findIgnoringASCIICase(stringViewFromLiteral("g")));
+ EXPECT_EQ(static_cast<size_t>(4), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "efg")));
+ EXPECT_EQ(static_cast<size_t>(3), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "éefg")));
+ EXPECT_EQ(static_cast<size_t>(6), referenceA.findIgnoringASCIICase(stringViewFromLiteral("G")));
+ EXPECT_EQ(static_cast<size_t>(4), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "EFG")));
+ EXPECT_EQ(static_cast<size_t>(3), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "éEFG")));
+
+ EXPECT_EQ(static_cast<size_t>(6), referenceB.findIgnoringASCIICase(stringViewFromLiteral("g")));
+ EXPECT_EQ(static_cast<size_t>(4), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "efg")));
+ EXPECT_EQ(static_cast<size_t>(3), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "Éefg")));
+ EXPECT_EQ(static_cast<size_t>(6), referenceB.findIgnoringASCIICase(stringViewFromLiteral("G")));
+ EXPECT_EQ(static_cast<size_t>(4), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "EFG")));
+ EXPECT_EQ(static_cast<size_t>(3), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ÉEFG")));
+
+ // Not a suffix.
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromLiteral("X")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "edg")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "Éefg")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromLiteral("w")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "dFG")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ÉEFG")));
+
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromLiteral("Z")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ffg")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "éefg")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromLiteral("r")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "EgG")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "éEFG")));
+}
+
+TEST(WTF, StringViewFindIgnoringASCIICaseWithValidOffset)
+{
+ String referenceHolder;
+ StringView reference = stringViewFromUTF8(referenceHolder, "ABCÉEFGaBcéeFG");
+ String tempStringHolder;
+
+ EXPECT_EQ(static_cast<size_t>(0), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABC"), 0));
+ EXPECT_EQ(static_cast<size_t>(7), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABC"), 1));
+ EXPECT_EQ(static_cast<size_t>(0), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCÉ"), 0));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCÉ"), 1));
+ EXPECT_EQ(static_cast<size_t>(7), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCé"), 0));
+ EXPECT_EQ(static_cast<size_t>(7), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCé"), 1));
+}
+
+TEST(WTF, StringViewFindIgnoringASCIICaseWithInvalidOffset)
+{
+ String referenceHolder;
+ StringView reference = stringViewFromUTF8(referenceHolder, "ABCÉEFGaBcéeFG");
+ String tempStringHolder;
+
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABC"), 15));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABC"), 16));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCÉ"), 17));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCÉ"), 42));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCÉ"), std::numeric_limits<unsigned>::max()));
+}
+
+TEST(WTF, StringViewFindIgnoringASCIICaseOnEmpty)
+{
+ String referenceHolder;
+ StringView reference = stringViewFromUTF8(referenceHolder, "ABCÉEFG");
+ StringView empty = stringViewFromLiteral("");
+ EXPECT_EQ(static_cast<size_t>(0), reference.findIgnoringASCIICase(empty));
+ EXPECT_EQ(static_cast<size_t>(0), reference.findIgnoringASCIICase(empty, 0));
+ EXPECT_EQ(static_cast<size_t>(3), reference.findIgnoringASCIICase(empty, 3));
+ EXPECT_EQ(static_cast<size_t>(7), reference.findIgnoringASCIICase(empty, 7));
+ EXPECT_EQ(static_cast<size_t>(7), reference.findIgnoringASCIICase(empty, 8));
+ EXPECT_EQ(static_cast<size_t>(7), reference.findIgnoringASCIICase(empty, 42));
+ EXPECT_EQ(static_cast<size_t>(7), reference.findIgnoringASCIICase(empty, std::numeric_limits<unsigned>::max()));
+}
+
+TEST(WTF, StringViewFindIgnoringASCIICaseWithPatternLongerThanReference)
+{
+ String referenceHolder;
+ StringView reference = stringViewFromUTF8(referenceHolder, "ABCÉEFG");
+ String patternHolder;
+ StringView pattern = stringViewFromUTF8(patternHolder, "ABCÉEFGA");
+
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference.findIgnoringASCIICase(pattern));
+ EXPECT_EQ(static_cast<size_t>(0), pattern.findIgnoringASCIICase(reference));
+}
+
+TEST(WTF, StringViewStartsWithBasic)
+{
+ StringView reference = stringViewFromLiteral("abcdefg");
+ String referenceUTF8Ref;
+ StringView referenceUTF8 = stringViewFromUTF8(referenceUTF8Ref, "àîûèô");
+
+ StringView oneLetterPrefix = stringViewFromLiteral("a");
+ StringView shortPrefix = stringViewFromLiteral("abc");
+ StringView longPrefix = stringViewFromLiteral("abcdef");
+ StringView upperCasePrefix = stringViewFromLiteral("ABC");
+ StringView empty = stringViewFromLiteral("");
+ StringView notPrefix = stringViewFromLiteral("bc");
+
+ String oneLetterPrefixUTF8Ref;
+ StringView oneLetterPrefixUTF8 = stringViewFromUTF8(oneLetterPrefixUTF8Ref, "à");
+ String shortPrefixUTF8Ref;
+ StringView shortPrefixUTF8 = stringViewFromUTF8(shortPrefixUTF8Ref, "àî");
+ String longPrefixUTF8Ref;
+ StringView longPrefixUTF8 = stringViewFromUTF8(longPrefixUTF8Ref, "àîûè");
+ String upperCasePrefixUTF8Ref;
+ StringView upperCasePrefixUTF8 = stringViewFromUTF8(upperCasePrefixUTF8Ref, "ÀÎ");
+ String notPrefixUTF8Ref;
+ StringView notPrefixUTF8 = stringViewFromUTF8(notPrefixUTF8Ref, "îû");
+
+ EXPECT_TRUE(reference.startsWith(reference));
+ EXPECT_TRUE(reference.startsWith(oneLetterPrefix));
+ EXPECT_TRUE(reference.startsWith(shortPrefix));
+ EXPECT_TRUE(reference.startsWith(longPrefix));
+ EXPECT_TRUE(reference.startsWith(empty));
+
+ EXPECT_TRUE(referenceUTF8.startsWith(referenceUTF8));
+ EXPECT_TRUE(referenceUTF8.startsWith(oneLetterPrefixUTF8));
+ EXPECT_TRUE(referenceUTF8.startsWith(shortPrefixUTF8));
+ EXPECT_TRUE(referenceUTF8.startsWith(longPrefixUTF8));
+ EXPECT_TRUE(referenceUTF8.startsWith(empty));
+
+ EXPECT_FALSE(reference.startsWith(notPrefix));
+ EXPECT_FALSE(reference.startsWith(upperCasePrefix));
+ EXPECT_FALSE(reference.startsWith(notPrefixUTF8));
+ EXPECT_FALSE(reference.startsWith(upperCasePrefixUTF8));
+ EXPECT_FALSE(referenceUTF8.startsWith(notPrefix));
+ EXPECT_FALSE(referenceUTF8.startsWith(upperCasePrefix));
+ EXPECT_FALSE(referenceUTF8.startsWith(notPrefixUTF8));
+ EXPECT_FALSE(referenceUTF8.startsWith(upperCasePrefixUTF8));
+}
+
+TEST(WTF, StringViewStartsWithEmpty)
+{
+ StringView a = stringViewFromLiteral("");
+ String refB;
+ StringView b = stringViewFromUTF8(refB, "");
+
+ EXPECT_TRUE(a.startsWith(a));
+ EXPECT_TRUE(a.startsWith(b));
+ EXPECT_TRUE(b.startsWith(a));
+ EXPECT_TRUE(b.startsWith(b));
+}
+
+TEST(WTF, StringViewStartsWithIgnoringASCIICaseBasic)
+{
+ StringView reference = stringViewFromLiteral("abcdefg");
+
+ String referenceUTF8Ref;
+ StringView referenceUTF8 = stringViewFromUTF8(referenceUTF8Ref, "àîûèô");
+
+ StringView oneLetterPrefix = stringViewFromLiteral("a");
+ StringView shortPrefix = stringViewFromLiteral("abc");
+ StringView longPrefix = stringViewFromLiteral("abcdef");
+ StringView upperCasePrefix = stringViewFromLiteral("ABC");
+ StringView mixedCasePrefix = stringViewFromLiteral("aBcDe");
+ StringView empty = stringViewFromLiteral("");
+ StringView notPrefix = stringViewFromLiteral("bc");
+
+ String oneLetterPrefixUTF8Ref;
+ StringView oneLetterPrefixUTF8 = stringViewFromUTF8(oneLetterPrefixUTF8Ref, "à");
+ String shortPrefixUTF8Ref;
+ StringView shortPrefixUTF8 = stringViewFromUTF8(shortPrefixUTF8Ref, "àî");
+ String longPrefixUTF8Ref;
+ StringView longPrefixUTF8 = stringViewFromUTF8(longPrefixUTF8Ref, "àîûè");
+ String upperCasePrefixUTF8Ref;
+ StringView upperCasePrefixUTF8 = stringViewFromUTF8(upperCasePrefixUTF8Ref, "ÀÎ");
+ String notPrefixUTF8Ref;
+ StringView notPrefixUTF8 = stringViewFromUTF8(notPrefixUTF8Ref, "îû");
+
+ EXPECT_TRUE(reference.startsWithIgnoringASCIICase(reference));
+ EXPECT_TRUE(reference.startsWithIgnoringASCIICase(oneLetterPrefix));
+ EXPECT_TRUE(reference.startsWithIgnoringASCIICase(shortPrefix));
+ EXPECT_TRUE(reference.startsWithIgnoringASCIICase(longPrefix));
+ EXPECT_TRUE(reference.startsWithIgnoringASCIICase(empty));
+ EXPECT_TRUE(reference.startsWithIgnoringASCIICase(upperCasePrefix));
+ EXPECT_TRUE(reference.startsWithIgnoringASCIICase(mixedCasePrefix));
+
+ EXPECT_TRUE(referenceUTF8.startsWithIgnoringASCIICase(referenceUTF8));
+ EXPECT_TRUE(referenceUTF8.startsWithIgnoringASCIICase(oneLetterPrefixUTF8));
+ EXPECT_TRUE(referenceUTF8.startsWithIgnoringASCIICase(shortPrefixUTF8));
+ EXPECT_TRUE(referenceUTF8.startsWithIgnoringASCIICase(longPrefixUTF8));
+ EXPECT_TRUE(referenceUTF8.startsWithIgnoringASCIICase(empty));
+
+ EXPECT_FALSE(reference.startsWithIgnoringASCIICase(notPrefix));
+ EXPECT_FALSE(reference.startsWithIgnoringASCIICase(notPrefixUTF8));
+ EXPECT_FALSE(reference.startsWithIgnoringASCIICase(upperCasePrefixUTF8));
+ EXPECT_FALSE(referenceUTF8.startsWithIgnoringASCIICase(notPrefix));
+ EXPECT_FALSE(referenceUTF8.startsWithIgnoringASCIICase(notPrefixUTF8));
+ EXPECT_FALSE(referenceUTF8.startsWithIgnoringASCIICase(upperCasePrefix));
+ EXPECT_FALSE(referenceUTF8.startsWithIgnoringASCIICase(upperCasePrefixUTF8));
+}
+
+
+TEST(WTF, StringViewStartsWithIgnoringASCIICaseEmpty)
+{
+ StringView a = stringViewFromLiteral("");
+ String refB;
+ StringView b = stringViewFromUTF8(refB, "");
+
+ EXPECT_TRUE(a.startsWithIgnoringASCIICase(a));
+ EXPECT_TRUE(a.startsWithIgnoringASCIICase(b));
+ EXPECT_TRUE(b.startsWithIgnoringASCIICase(a));
+ EXPECT_TRUE(b.startsWithIgnoringASCIICase(b));
+}
+
+TEST(WTF, StringViewStartsWithIgnoringASCIICaseWithLatin1Characters)
+{
+ StringView reference = stringViewFromLiteral("aBcéeFG");
+ String referenceUTF8Ref;
+ StringView referenceUTF8 = stringViewFromUTF8(referenceUTF8Ref, "aBcéeFG");
+
+ StringView a = stringViewFromLiteral("aBcéeF");
+ StringView b = stringViewFromLiteral("ABCéEF");
+ StringView c = stringViewFromLiteral("abcéef");
+ StringView d = stringViewFromLiteral("Abcéef");
+
+ String refE;
+ StringView e = stringViewFromUTF8(refE, "aBcéeF");
+ String refF;
+ StringView f = stringViewFromUTF8(refF, "ABCéEF");
+ String refG;
+ StringView g = stringViewFromUTF8(refG, "abcéef");
+ String refH;
+ StringView h = stringViewFromUTF8(refH, "Abcéef");
+
+ EXPECT_TRUE(reference.startsWithIgnoringASCIICase(a));
+ EXPECT_TRUE(reference.startsWithIgnoringASCIICase(b));
+ EXPECT_TRUE(reference.startsWithIgnoringASCIICase(c));
+ EXPECT_TRUE(reference.startsWithIgnoringASCIICase(d));
+
+ EXPECT_TRUE(referenceUTF8.startsWithIgnoringASCIICase(e));
+ EXPECT_TRUE(referenceUTF8.startsWithIgnoringASCIICase(f));
+ EXPECT_TRUE(referenceUTF8.startsWithIgnoringASCIICase(g));
+ EXPECT_TRUE(referenceUTF8.startsWithIgnoringASCIICase(h));
+
+ EXPECT_FALSE(reference.endsWithIgnoringASCIICase(referenceUTF8));
+ EXPECT_FALSE(referenceUTF8.endsWithIgnoringASCIICase(reference));
+}
+
+TEST(WTF, StringViewEndsWithBasic)
+{
+ StringView reference = stringViewFromLiteral("abcdefg");
+ String referenceUTF8Ref;
+ StringView referenceUTF8 = stringViewFromUTF8(referenceUTF8Ref, "àîûèô");
+
+ StringView oneLetterSuffix = stringViewFromLiteral("g");
+ StringView shortSuffix = stringViewFromLiteral("efg");
+ StringView longSuffix = stringViewFromLiteral("cdefg");
+ StringView upperCaseSuffix = stringViewFromLiteral("EFG");
+ StringView empty = stringViewFromLiteral("");
+ StringView notSuffix = stringViewFromLiteral("bc");
+
+ String oneLetterSuffixUTF8Ref;
+ StringView oneLetterSuffixUTF8 = stringViewFromUTF8(oneLetterSuffixUTF8Ref, "ô");
+ String shortSuffixUTF8Ref;
+ StringView shortSuffixUTF8 = stringViewFromUTF8(shortSuffixUTF8Ref, "èô");
+ String longSuffixUTF8Ref;
+ StringView longSuffixUTF8 = stringViewFromUTF8(longSuffixUTF8Ref, "îûèô");
+ String upperCaseSuffixUTF8Ref;
+ StringView upperCaseSuffixUTF8 = stringViewFromUTF8(upperCaseSuffixUTF8Ref, "ÈÔ");
+ String notSuffixUTF8Ref;
+ StringView notSuffixUTF8 = stringViewFromUTF8(notSuffixUTF8Ref, "îû");
+
+ EXPECT_TRUE(reference.endsWith(reference));
+ EXPECT_TRUE(reference.endsWith(oneLetterSuffix));
+ EXPECT_TRUE(reference.endsWith(shortSuffix));
+ EXPECT_TRUE(reference.endsWith(longSuffix));
+ EXPECT_TRUE(reference.endsWith(empty));
+
+ EXPECT_TRUE(referenceUTF8.endsWith(referenceUTF8));
+ EXPECT_TRUE(referenceUTF8.endsWith(oneLetterSuffixUTF8));
+ EXPECT_TRUE(referenceUTF8.endsWith(shortSuffixUTF8));
+ EXPECT_TRUE(referenceUTF8.endsWith(longSuffixUTF8));
+ EXPECT_TRUE(referenceUTF8.endsWith(empty));
+
+ EXPECT_FALSE(reference.endsWith(notSuffix));
+ EXPECT_FALSE(reference.endsWith(upperCaseSuffix));
+ EXPECT_FALSE(reference.endsWith(notSuffixUTF8));
+ EXPECT_FALSE(reference.endsWith(upperCaseSuffixUTF8));
+ EXPECT_FALSE(referenceUTF8.endsWith(notSuffix));
+ EXPECT_FALSE(referenceUTF8.endsWith(upperCaseSuffix));
+ EXPECT_FALSE(referenceUTF8.endsWith(notSuffixUTF8));
+ EXPECT_FALSE(referenceUTF8.endsWith(upperCaseSuffixUTF8));
+}
+
+TEST(WTF, StringViewEndsWithEmpty)
+{
+ StringView a = stringViewFromLiteral("");
+ String refB;
+ StringView b = stringViewFromUTF8(refB, "");
+
+ EXPECT_TRUE(a.endsWith(a));
+ EXPECT_TRUE(a.endsWith(b));
+ EXPECT_TRUE(b.endsWith(a));
+ EXPECT_TRUE(b.endsWith(b));
+}
+
+TEST(WTF, StringViewEndsWithIgnoringASCIICaseBasic)
+{
+ StringView reference = stringViewFromLiteral("abcdefg");
+ String referenceUTF8Ref;
+ StringView referenceUTF8 = stringViewFromUTF8(referenceUTF8Ref, "àîûèô");
+
+ StringView oneLetterSuffix = stringViewFromLiteral("g");
+ StringView shortSuffix = stringViewFromLiteral("efg");
+ StringView longSuffix = stringViewFromLiteral("bcdefg");
+ StringView upperCaseSuffix = stringViewFromLiteral("EFG");
+ StringView mixedCaseSuffix = stringViewFromLiteral("bCdeFg");
+ StringView empty = stringViewFromLiteral("");
+ StringView notSuffix = stringViewFromLiteral("bc");
+
+ String oneLetterSuffixUTF8Ref;
+ StringView oneLetterSuffixUTF8 = stringViewFromUTF8(oneLetterSuffixUTF8Ref, "ô");
+ String shortSuffixUTF8Ref;
+ StringView shortSuffixUTF8 = stringViewFromUTF8(shortSuffixUTF8Ref, "èô");
+ String longSuffixUTF8Ref;
+ StringView longSuffixUTF8 = stringViewFromUTF8(longSuffixUTF8Ref, "îûèô");
+ String upperCaseSuffixUTF8Ref;
+ StringView upperCaseSuffixUTF8 = stringViewFromUTF8(upperCaseSuffixUTF8Ref, "ÈÔ");
+ String notSuffixUTF8Ref;
+ StringView notSuffixUTF8 = stringViewFromUTF8(notSuffixUTF8Ref, "îû");
+
+ EXPECT_TRUE(reference.endsWithIgnoringASCIICase(reference));
+ EXPECT_TRUE(reference.endsWithIgnoringASCIICase(oneLetterSuffix));
+ EXPECT_TRUE(reference.endsWithIgnoringASCIICase(shortSuffix));
+ EXPECT_TRUE(reference.endsWithIgnoringASCIICase(longSuffix));
+ EXPECT_TRUE(reference.endsWithIgnoringASCIICase(empty));
+ EXPECT_TRUE(reference.endsWithIgnoringASCIICase(upperCaseSuffix));
+ EXPECT_TRUE(reference.endsWithIgnoringASCIICase(mixedCaseSuffix));
+
+ EXPECT_TRUE(referenceUTF8.endsWithIgnoringASCIICase(referenceUTF8));
+ EXPECT_TRUE(referenceUTF8.endsWithIgnoringASCIICase(oneLetterSuffixUTF8));
+ EXPECT_TRUE(referenceUTF8.endsWithIgnoringASCIICase(shortSuffixUTF8));
+ EXPECT_TRUE(referenceUTF8.endsWithIgnoringASCIICase(longSuffixUTF8));
+ EXPECT_TRUE(referenceUTF8.endsWithIgnoringASCIICase(empty));
+
+ EXPECT_FALSE(reference.endsWithIgnoringASCIICase(notSuffix));
+ EXPECT_FALSE(reference.endsWithIgnoringASCIICase(notSuffixUTF8));
+ EXPECT_FALSE(reference.endsWithIgnoringASCIICase(upperCaseSuffixUTF8));
+ EXPECT_FALSE(referenceUTF8.endsWithIgnoringASCIICase(notSuffix));
+ EXPECT_FALSE(referenceUTF8.endsWithIgnoringASCIICase(notSuffixUTF8));
+ EXPECT_FALSE(referenceUTF8.endsWithIgnoringASCIICase(upperCaseSuffix));
+ EXPECT_FALSE(referenceUTF8.endsWithIgnoringASCIICase(upperCaseSuffixUTF8));
+}
+
+TEST(WTF, StringViewEndsWithIgnoringASCIICaseEmpty)
+{
+ StringView a = stringViewFromLiteral("");
+ String refB;
+ StringView b = stringViewFromUTF8(refB, "");
+
+ EXPECT_TRUE(a.endsWithIgnoringASCIICase(a));
+ EXPECT_TRUE(a.endsWithIgnoringASCIICase(b));
+ EXPECT_TRUE(b.endsWithIgnoringASCIICase(a));
+ EXPECT_TRUE(b.endsWithIgnoringASCIICase(b));
+}
+
+TEST(WTF, StringViewEndsWithIgnoringASCIICaseWithLatin1Characters)
+{
+ StringView reference = stringViewFromLiteral("aBcéeFG");
+ String referenceUTF8Ref;
+ StringView referenceUTF8 = stringViewFromUTF8(referenceUTF8Ref, "aBcéeFG");
+
+ StringView a = stringViewFromLiteral("BcéeFG");
+ StringView b = stringViewFromLiteral("BCéEFG");
+ StringView c = stringViewFromLiteral("bcéefG");
+ StringView d = stringViewFromLiteral("bcéefg");
+
+ String refE;
+ StringView e = stringViewFromUTF8(refE, "bcéefG");
+ String refF;
+ StringView f = stringViewFromUTF8(refF, "BCéEFG");
+ String refG;
+ StringView g = stringViewFromUTF8(refG, "bcéefG");
+ String refH;
+ StringView h = stringViewFromUTF8(refH, "bcéefg");
+
+ EXPECT_TRUE(reference.endsWithIgnoringASCIICase(a));
+ EXPECT_TRUE(reference.endsWithIgnoringASCIICase(b));
+ EXPECT_TRUE(reference.endsWithIgnoringASCIICase(c));
+ EXPECT_TRUE(reference.endsWithIgnoringASCIICase(d));
+
+ EXPECT_TRUE(referenceUTF8.endsWithIgnoringASCIICase(e));
+ EXPECT_TRUE(referenceUTF8.endsWithIgnoringASCIICase(f));
+ EXPECT_TRUE(referenceUTF8.endsWithIgnoringASCIICase(g));
+ EXPECT_TRUE(referenceUTF8.endsWithIgnoringASCIICase(h));
+
+ EXPECT_FALSE(reference.endsWithIgnoringASCIICase(referenceUTF8));
+ EXPECT_FALSE(referenceUTF8.endsWithIgnoringASCIICase(reference));
+}
+
+TEST(WTF, StringView8Bit)
+{
+ StringView nullView;
+ EXPECT_TRUE(StringView().is8Bit());
+ EXPECT_TRUE(StringView::empty().is8Bit());
+
+ LChar* lcharPtr = nullptr;
+ UChar* ucharPtr = nullptr;
+ EXPECT_TRUE(StringView(lcharPtr, 0).is8Bit());
+ EXPECT_FALSE(StringView(ucharPtr, 0).is8Bit());
+
+ EXPECT_TRUE(StringView(String(lcharPtr, 0)).is8Bit());
+ EXPECT_TRUE(StringView(String(ucharPtr, 0)).is8Bit());
+
+ EXPECT_TRUE(StringView(String().impl()).is8Bit());
+ EXPECT_TRUE(StringView(emptyString().impl()).is8Bit());
+}
+
+TEST(WTF, StringViewRightBasic)
+{
+ auto reference = stringViewFromLiteral("Cappuccino");
+ EXPECT_TRUE(reference.right(0) == stringViewFromLiteral(""));
+ EXPECT_TRUE(reference.right(1) == stringViewFromLiteral("o"));
+ EXPECT_TRUE(reference.right(2) == stringViewFromLiteral("no"));
+ EXPECT_TRUE(reference.right(3) == stringViewFromLiteral("ino"));
+ EXPECT_TRUE(reference.right(4) == stringViewFromLiteral("cino"));
+ EXPECT_TRUE(reference.right(5) == stringViewFromLiteral("ccino"));
+ EXPECT_TRUE(reference.right(6) == stringViewFromLiteral("uccino"));
+ EXPECT_TRUE(reference.right(7) == stringViewFromLiteral("puccino"));
+ EXPECT_TRUE(reference.right(8) == stringViewFromLiteral("ppuccino"));
+ EXPECT_TRUE(reference.right(9) == stringViewFromLiteral("appuccino"));
+ EXPECT_TRUE(reference.right(10) == stringViewFromLiteral("Cappuccino"));
+}
+
+TEST(WTF, StringViewLeftBasic)
+{
+ auto reference = stringViewFromLiteral("Cappuccino");
+ EXPECT_TRUE(reference.left(0) == stringViewFromLiteral(""));
+ EXPECT_TRUE(reference.left(1) == stringViewFromLiteral("C"));
+ EXPECT_TRUE(reference.left(2) == stringViewFromLiteral("Ca"));
+ EXPECT_TRUE(reference.left(3) == stringViewFromLiteral("Cap"));
+ EXPECT_TRUE(reference.left(4) == stringViewFromLiteral("Capp"));
+ EXPECT_TRUE(reference.left(5) == stringViewFromLiteral("Cappu"));
+ EXPECT_TRUE(reference.left(6) == stringViewFromLiteral("Cappuc"));
+ EXPECT_TRUE(reference.left(7) == stringViewFromLiteral("Cappucc"));
+ EXPECT_TRUE(reference.left(8) == stringViewFromLiteral("Cappucci"));
+ EXPECT_TRUE(reference.left(9) == stringViewFromLiteral("Cappuccin"));
+ EXPECT_TRUE(reference.left(10) == stringViewFromLiteral("Cappuccino"));
+}
+
+TEST(WTF, StringViewReverseFindBasic)
+{
+ auto reference = stringViewFromLiteral("Cappuccino");
+ EXPECT_EQ(reference.reverseFind('o'), 9U);
+ EXPECT_EQ(reference.reverseFind('n'), 8U);
+ EXPECT_EQ(reference.reverseFind('c'), 6U);
+ EXPECT_EQ(reference.reverseFind('p'), 3U);
+ EXPECT_EQ(reference.reverseFind('k'), notFound);
+
+ EXPECT_EQ(reference.reverseFind('o', 8), notFound);
+ EXPECT_EQ(reference.reverseFind('c', 8), 6U);
+ EXPECT_EQ(reference.reverseFind('c', 6), 6U);
+ EXPECT_EQ(reference.reverseFind('c', 5), 5U);
+ EXPECT_EQ(reference.reverseFind('c', 4), notFound);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/SynchronizedFixedQueue.cpp b/Tools/TestWebKitAPI/Tests/WTF/SynchronizedFixedQueue.cpp
new file mode 100644
index 000000000..31436bc22
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/SynchronizedFixedQueue.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <chrono>
+#include <thread>
+
+#include <wtf/ASCIICType.h>
+#include <wtf/SynchronizedFixedQueue.h>
+#include <wtf/WorkQueue.h>
+#include <wtf/text/CString.h>
+#include <wtf/threads/BinarySemaphore.h>
+
+namespace TestWebKitAPI {
+
+static char const* textItem(size_t index)
+{
+ static char const* items[] = { "first", "second", "third", "fourth", "fifth", "sixth" };
+ return index < sizeof(items) / sizeof(items[0]) ? items[index] : nullptr;
+}
+
+static CString toUpper(const CString& lower)
+{
+ CString upper = lower;
+
+ for (char* buffer = upper.mutableData(); *buffer; ++buffer)
+ *buffer = toASCIIUpper(*buffer);
+
+ return upper;
+}
+
+template <size_t BufferSize>
+class ToUpperConverter {
+public:
+ ToUpperConverter()
+ {
+ }
+
+ WorkQueue* produceQueue()
+ {
+ if (!m_produceQueue)
+ m_produceQueue = WorkQueue::create("org.webkit.Produce");
+ return m_produceQueue.get();
+ }
+
+ WorkQueue* consumeQueue()
+ {
+ if (!m_consumeQueue)
+ m_consumeQueue = WorkQueue::create("org.webkit.Consume");
+ return m_consumeQueue.get();
+ }
+
+ void startProducing()
+ {
+ if (isProducing())
+ return;
+
+ produceQueue()->dispatch([this] {
+ CString lower;
+ while (m_lowerQueue.dequeue(lower)) {
+ m_upperQueue.enqueue(toUpper(lower));
+ EXPECT_TRUE(lower == textItem(m_produceCount++));
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+ m_produceCloseSemaphore.signal();
+ });
+ }
+
+ void startConsuming()
+ {
+ if (isConsuming())
+ return;
+
+ consumeQueue()->dispatch([this] {
+ CString upper;
+ while (m_upperQueue.dequeue(upper)) {
+ EXPECT_TRUE(upper == toUpper(textItem(m_consumeCount++)));
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+ }
+ m_consumeCloseSemaphore.signal();
+ });
+ }
+
+ void start()
+ {
+ startProducing();
+ startConsuming();
+ }
+
+ void stopProducing()
+ {
+ if (!isProducing())
+ return;
+
+ m_lowerQueue.close();
+ m_produceCloseSemaphore.wait(WallTime::infinity());
+ m_produceQueue = nullptr;
+ }
+
+ void stopConsuming()
+ {
+ if (!isConsuming())
+ return;
+
+ m_upperQueue.close();
+ m_consumeCloseSemaphore.wait(WallTime::infinity());
+ m_consumeQueue = nullptr;
+ }
+
+ void stop()
+ {
+ stopProducing();
+ stopConsuming();
+ }
+
+ void enqueueLower(const CString& lower)
+ {
+ m_lowerQueue.enqueue(lower);
+ }
+
+ bool isProducing() { return m_produceQueue; }
+ bool isConsuming() { return m_consumeQueue; }
+
+ size_t produceCount() const { return m_produceCount; }
+ size_t consumeCount() const { return m_consumeCount; }
+
+private:
+ SynchronizedFixedQueue<CString, BufferSize> m_lowerQueue;
+ SynchronizedFixedQueue<CString, BufferSize> m_upperQueue;
+ RefPtr<WorkQueue> m_produceQueue;
+ RefPtr<WorkQueue> m_consumeQueue;
+ BinarySemaphore m_produceCloseSemaphore;
+ BinarySemaphore m_consumeCloseSemaphore;
+ size_t m_produceCount { 0 };
+ size_t m_consumeCount { 0 };
+};
+
+TEST(WTF_SynchronizedFixedQueue, Basic)
+{
+ ToUpperConverter<4U> converter;
+
+ converter.start();
+ EXPECT_TRUE(converter.isProducing() && converter.isConsuming());
+
+ converter.stop();
+ EXPECT_FALSE(converter.isProducing() || converter.isConsuming());
+
+ EXPECT_EQ(converter.produceCount(), 0U);
+ EXPECT_EQ(converter.consumeCount(), 0U);
+}
+
+TEST(WTF_SynchronizedFixedQueue, ProduceOnly)
+{
+ ToUpperConverter<4U> converter;
+
+ converter.startProducing();
+ EXPECT_TRUE(converter.isProducing() && !converter.isConsuming());
+
+ size_t count = 0;
+ while (char const* item = textItem(count)) {
+ converter.enqueueLower(item);
+ ++count;
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ }
+
+ converter.stop();
+ EXPECT_FALSE(converter.isProducing() || converter.isConsuming());
+}
+
+TEST(WTF_SynchronizedFixedQueue, ConsumeOnly)
+{
+ ToUpperConverter<4U> converter;
+
+ converter.startConsuming();
+ EXPECT_TRUE(!converter.isProducing() && converter.isConsuming());
+
+ converter.stop();
+ EXPECT_FALSE(converter.isProducing() || converter.isConsuming());
+}
+
+TEST(WTF_SynchronizedFixedQueue, Limits)
+{
+ ToUpperConverter<4U> converter;
+
+ converter.start();
+ EXPECT_TRUE(converter.isProducing() && converter.isConsuming());
+
+ size_t count = 0;
+ while (char const* item = textItem(count)) {
+ converter.enqueueLower(item);
+ ++count;
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ }
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(400));
+
+ converter.stop();
+ EXPECT_FALSE(converter.isProducing() || converter.isConsuming());
+
+ EXPECT_EQ(converter.produceCount(), count);
+ EXPECT_EQ(converter.consumeCount(), count);
+}
+
+}
diff --git a/Tools/TestWebKitAPI/Tests/WTF/TextBreakIterator.cpp b/Tools/TestWebKitAPI/Tests/WTF/TextBreakIterator.cpp
new file mode 100644
index 000000000..c2f84e3d7
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/TextBreakIterator.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <wtf/text/TextBreakIterator.h>
+
+namespace TestWebKitAPI {
+
+static String makeUTF16(std::vector<UChar> input)
+{
+ return { input.data(), static_cast<unsigned>(input.size()) };
+}
+
+TEST(WTF, TextBreakIteratorNumGraphemeClusters)
+{
+ EXPECT_EQ(0U, numGraphemeClusters(StringView { }));
+ EXPECT_EQ(0U, numGraphemeClusters(StringView { "" }));
+ EXPECT_EQ(0U, numGraphemeClusters(makeUTF16({ })));
+
+ EXPECT_EQ(1U, numGraphemeClusters(StringView { "a" }));
+ EXPECT_EQ(1U, numGraphemeClusters(makeUTF16({ 'a' })));
+ EXPECT_EQ(1U, numGraphemeClusters(StringView { "\r\n" }));
+ EXPECT_EQ(1U, numGraphemeClusters(StringView { "\n" }));
+ EXPECT_EQ(1U, numGraphemeClusters(StringView { "\r" }));
+ EXPECT_EQ(1U, numGraphemeClusters(makeUTF16({ '\r', '\n' })));
+ EXPECT_EQ(1U, numGraphemeClusters(makeUTF16({ '\n' })));
+ EXPECT_EQ(1U, numGraphemeClusters(makeUTF16({ '\r' })));
+
+ EXPECT_EQ(2U, numGraphemeClusters(StringView { "\n\r" }));
+ EXPECT_EQ(2U, numGraphemeClusters(makeUTF16({ '\n', '\r' })));
+
+ EXPECT_EQ(2U, numGraphemeClusters(StringView { "\r\n\r" }));
+ EXPECT_EQ(2U, numGraphemeClusters(makeUTF16({ '\r', '\n', '\r' })));
+
+ EXPECT_EQ(1U, numGraphemeClusters(makeUTF16({ 'g', 0x308 })));
+ EXPECT_EQ(1U, numGraphemeClusters(makeUTF16({ 0x1100, 0x1161, 0x11A8 })));
+ EXPECT_EQ(1U, numGraphemeClusters(makeUTF16({ 0x0BA8, 0x0BBF })));
+
+ EXPECT_EQ(2U, numGraphemeClusters(makeUTF16({ 0x308, 'g' })));
+
+ EXPECT_EQ(3U, numGraphemeClusters(StringView { "\r\nbc" }));
+ EXPECT_EQ(3U, numGraphemeClusters(makeUTF16({ 'g', 0x308, 'b', 'c' })));
+}
+
+TEST(WTF, TextBreakIteratorNumCharactersInGraphemeClusters)
+{
+ EXPECT_EQ(0U, numCharactersInGraphemeClusters(StringView { }, 0));
+ EXPECT_EQ(0U, numCharactersInGraphemeClusters(StringView { }, 1));
+
+ EXPECT_EQ(0U, numCharactersInGraphemeClusters(StringView { "" }, 0));
+ EXPECT_EQ(0U, numCharactersInGraphemeClusters(StringView { "" }, 1));
+
+ EXPECT_EQ(0U, numCharactersInGraphemeClusters(makeUTF16({ }), 0));
+ EXPECT_EQ(0U, numCharactersInGraphemeClusters(makeUTF16({ }), 1));
+
+ EXPECT_EQ(1U, numCharactersInGraphemeClusters(StringView { "a" }, 1));
+ EXPECT_EQ(1U, numCharactersInGraphemeClusters(makeUTF16({ 'a' }), 1));
+ EXPECT_EQ(1U, numCharactersInGraphemeClusters(StringView { "\n" }, 1));
+ EXPECT_EQ(1U, numCharactersInGraphemeClusters(StringView { "\r" }, 1));
+ EXPECT_EQ(1U, numCharactersInGraphemeClusters(makeUTF16({ '\n' }), 1));
+ EXPECT_EQ(1U, numCharactersInGraphemeClusters(makeUTF16({ '\r' }), 1));
+
+ EXPECT_EQ(0U, numCharactersInGraphemeClusters(StringView { "abc" }, 0));
+ EXPECT_EQ(1U, numCharactersInGraphemeClusters(StringView { "abc" }, 1));
+ EXPECT_EQ(2U, numCharactersInGraphemeClusters(StringView { "abc" }, 2));
+ EXPECT_EQ(3U, numCharactersInGraphemeClusters(StringView { "abc" }, 3));
+ EXPECT_EQ(3U, numCharactersInGraphemeClusters(StringView { "abc" }, 4));
+
+ EXPECT_EQ(0U, numCharactersInGraphemeClusters(makeUTF16({ 'a', 'b', 'c' }), 0));
+ EXPECT_EQ(1U, numCharactersInGraphemeClusters(makeUTF16({ 'a', 'b', 'c' }), 1));
+ EXPECT_EQ(2U, numCharactersInGraphemeClusters(makeUTF16({ 'a', 'b', 'c' }), 2));
+ EXPECT_EQ(3U, numCharactersInGraphemeClusters(makeUTF16({ 'a', 'b', 'c' }), 3));
+ EXPECT_EQ(3U, numCharactersInGraphemeClusters(makeUTF16({ 'a', 'b', 'c' }), 4));
+
+ EXPECT_EQ(0U, numCharactersInGraphemeClusters(StringView { "\r\n" }, 0));
+ EXPECT_EQ(2U, numCharactersInGraphemeClusters(StringView { "\r\n" }, 1));
+ EXPECT_EQ(2U, numCharactersInGraphemeClusters(StringView { "\r\n" }, 2));
+ EXPECT_EQ(2U, numCharactersInGraphemeClusters(StringView { "\r\n" }, 3));
+
+ EXPECT_EQ(0U, numCharactersInGraphemeClusters(makeUTF16({ '\r', '\n' }), 0));
+ EXPECT_EQ(2U, numCharactersInGraphemeClusters(makeUTF16({ '\r', '\n' }), 1));
+ EXPECT_EQ(2U, numCharactersInGraphemeClusters(makeUTF16({ '\r', '\n' }), 2));
+ EXPECT_EQ(2U, numCharactersInGraphemeClusters(makeUTF16({ '\r', '\n' }), 3));
+
+ EXPECT_EQ(0U, numCharactersInGraphemeClusters(StringView { "\n\r" }, 0));
+ EXPECT_EQ(1U, numCharactersInGraphemeClusters(StringView { "\n\r" }, 1));
+ EXPECT_EQ(2U, numCharactersInGraphemeClusters(StringView { "\n\r" }, 2));
+
+ EXPECT_EQ(1U, numCharactersInGraphemeClusters(makeUTF16({ '\n', '\r' }), 1));
+ EXPECT_EQ(2U, numCharactersInGraphemeClusters(makeUTF16({ '\n', '\r' }), 2));
+
+ EXPECT_EQ(0U, numCharactersInGraphemeClusters(StringView { "\r\n\r" }, 0));
+ EXPECT_EQ(2U, numCharactersInGraphemeClusters(StringView { "\r\n\r" }, 1));
+ EXPECT_EQ(3U, numCharactersInGraphemeClusters(StringView { "\r\n\r" }, 2));
+ EXPECT_EQ(3U, numCharactersInGraphemeClusters(StringView { "\r\n\r" }, 3));
+
+ EXPECT_EQ(0U, numCharactersInGraphemeClusters(makeUTF16({ '\r', '\n', '\r' }), 0));
+ EXPECT_EQ(2U, numCharactersInGraphemeClusters(makeUTF16({ '\r', '\n', '\r' }), 1));
+ EXPECT_EQ(3U, numCharactersInGraphemeClusters(makeUTF16({ '\r', '\n', '\r' }), 2));
+ EXPECT_EQ(3U, numCharactersInGraphemeClusters(makeUTF16({ '\r', '\n', '\r' }), 3));
+
+ EXPECT_EQ(2U, numCharactersInGraphemeClusters(makeUTF16({ 'g', 0x308 }), 1));
+ EXPECT_EQ(3U, numCharactersInGraphemeClusters(makeUTF16({ 0x1100, 0x1161, 0x11A8 }), 1));
+ EXPECT_EQ(2U, numCharactersInGraphemeClusters(makeUTF16({ 0x0BA8, 0x0BBF }), 1));
+
+ EXPECT_EQ(1U, numCharactersInGraphemeClusters(makeUTF16({ 0x308, 'g' }), 1));
+
+ EXPECT_EQ(0U, numCharactersInGraphemeClusters(StringView { "\r\nbc" }, 0));
+ EXPECT_EQ(2U, numCharactersInGraphemeClusters(StringView { "\r\nbc" }, 1));
+ EXPECT_EQ(3U, numCharactersInGraphemeClusters(StringView { "\r\nbc" }, 2));
+ EXPECT_EQ(4U, numCharactersInGraphemeClusters(StringView { "\r\nbc" }, 3));
+ EXPECT_EQ(4U, numCharactersInGraphemeClusters(StringView { "\r\nbc" }, 4));
+ EXPECT_EQ(4U, numCharactersInGraphemeClusters(StringView { "\r\nbc" }, 5));
+
+ EXPECT_EQ(0U, numCharactersInGraphemeClusters(makeUTF16({ 'g', 0x308, 'b', 'c' }), 0));
+ EXPECT_EQ(2U, numCharactersInGraphemeClusters(makeUTF16({ 'g', 0x308, 'b', 'c' }), 1));
+ EXPECT_EQ(3U, numCharactersInGraphemeClusters(makeUTF16({ 'g', 0x308, 'b', 'c' }), 2));
+ EXPECT_EQ(4U, numCharactersInGraphemeClusters(makeUTF16({ 'g', 0x308, 'b', 'c' }), 3));
+ EXPECT_EQ(4U, numCharactersInGraphemeClusters(makeUTF16({ 'g', 0x308, 'b', 'c' }), 4));
+ EXPECT_EQ(4U, numCharactersInGraphemeClusters(makeUTF16({ 'g', 0x308, 'b', 'c' }), 5));
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/Time.cpp b/Tools/TestWebKitAPI/Tests/WTF/Time.cpp
new file mode 100644
index 000000000..52e71494b
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/Time.cpp
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include <wtf/ClockType.h>
+#include <wtf/MonotonicTime.h>
+#include <wtf/Seconds.h>
+#include <wtf/StringPrintStream.h>
+#include <wtf/TimeWithDynamicClockType.h>
+#include <wtf/WallTime.h>
+
+namespace WTF {
+
+std::basic_ostream<char>& operator<<(std::basic_ostream<char>& out, Seconds value)
+{
+ out << toCString(value).data();
+ return out;
+}
+
+std::basic_ostream<char>& operator<<(std::basic_ostream<char>& out, WallTime value)
+{
+ out << toCString(value).data();
+ return out;
+}
+
+std::basic_ostream<char>& operator<<(std::basic_ostream<char>& out, MonotonicTime value)
+{
+ out << toCString(value).data();
+ return out;
+}
+
+std::basic_ostream<char>& operator<<(std::basic_ostream<char>& out, TimeWithDynamicClockType value)
+{
+ out << toCString(value).data();
+ return out;
+}
+
+} // namespace WTF
+
+using namespace WTF;
+
+namespace TestWebKitAPI {
+
+namespace {
+
+Seconds s(double value)
+{
+ return Seconds(value);
+}
+
+WallTime wt(double value)
+{
+ return WallTime::fromRawSeconds(value);
+}
+
+MonotonicTime mt(double value)
+{
+ return MonotonicTime::fromRawSeconds(value);
+}
+
+TimeWithDynamicClockType dt(double value, ClockType type)
+{
+ return TimeWithDynamicClockType::fromRawSeconds(value, type);
+}
+
+TimeWithDynamicClockType dtw(double value)
+{
+ return dt(value, ClockType::Wall);
+}
+
+TimeWithDynamicClockType dtm(double value)
+{
+ return dt(value, ClockType::Monotonic);
+}
+
+} // anonymous namespace
+
+TEST(WTF_Time, units)
+{
+ EXPECT_EQ(s(60), Seconds::fromMinutes(1));
+ EXPECT_EQ(s(0.001), Seconds::fromMilliseconds(1));
+ EXPECT_EQ(s(0.000001), Seconds::fromMicroseconds(1));
+ EXPECT_EQ(s(0.0000005), Seconds::fromNanoseconds(500));
+
+ EXPECT_EQ(s(120).minutes(), 2);
+ EXPECT_EQ(s(2).seconds(), 2);
+ EXPECT_EQ(s(2).milliseconds(), 2000);
+ EXPECT_EQ(s(2).microseconds(), 2000000);
+ EXPECT_EQ(s(2).nanoseconds(), 2000000000);
+}
+
+TEST(WTF_Time, plus)
+{
+ EXPECT_EQ(s(6), s(1) + s(5));
+ EXPECT_EQ(s(6), s(5) + s(1));
+ EXPECT_EQ(wt(6), s(1) + wt(5));
+ EXPECT_EQ(wt(6), s(5) + wt(1));
+ EXPECT_EQ(wt(6), wt(1) + s(5));
+ EXPECT_EQ(wt(6), wt(5) + s(1));
+ EXPECT_EQ(mt(6), s(1) + mt(5));
+ EXPECT_EQ(mt(6), s(5) + mt(1));
+ EXPECT_EQ(mt(6), mt(1) + s(5));
+ EXPECT_EQ(mt(6), mt(5) + s(1));
+ EXPECT_EQ(dtw(6), s(1) + dtw(5));
+ EXPECT_EQ(dtw(6), s(5) + dtw(1));
+ EXPECT_EQ(dtw(6), dtw(1) + s(5));
+ EXPECT_EQ(dtw(6), dtw(5) + s(1));
+ EXPECT_EQ(dtm(6), s(1) + dtm(5));
+ EXPECT_EQ(dtm(6), s(5) + dtm(1));
+ EXPECT_EQ(dtm(6), dtm(1) + s(5));
+ EXPECT_EQ(dtm(6), dtm(5) + s(1));
+}
+
+TEST(WTF_Time, minus)
+{
+ EXPECT_EQ(s(-4), s(1) - s(5));
+ EXPECT_EQ(s(4), s(5) - s(1));
+ EXPECT_EQ(wt(-4), s(1) - wt(5));
+ EXPECT_EQ(wt(4), s(5) - wt(1));
+ EXPECT_EQ(wt(-4), wt(1) - s(5));
+ EXPECT_EQ(wt(4), wt(5) - s(1));
+ EXPECT_EQ(mt(-4), s(1) - mt(5));
+ EXPECT_EQ(mt(4), s(5) - mt(1));
+ EXPECT_EQ(mt(-4), mt(1) - s(5));
+ EXPECT_EQ(mt(4), mt(5) - s(1));
+ EXPECT_EQ(dtw(-4), s(1) - dtw(5));
+ EXPECT_EQ(dtw(4), s(5) - dtw(1));
+ EXPECT_EQ(dtw(-4), dtw(1) - s(5));
+ EXPECT_EQ(dtw(4), dtw(5) - s(1));
+ EXPECT_EQ(dtm(-4), s(1) - dtm(5));
+ EXPECT_EQ(dtm(4), s(5) - dtm(1));
+ EXPECT_EQ(dtm(-4), dtm(1) - s(5));
+ EXPECT_EQ(dtm(4), dtm(5) - s(1));
+}
+
+TEST(WTF_Time, negate)
+{
+ EXPECT_EQ(s(-7), -s(7));
+ EXPECT_EQ(s(7), -s(-7));
+ EXPECT_EQ(wt(-7), -wt(7));
+ EXPECT_EQ(wt(7), -wt(-7));
+ EXPECT_EQ(mt(-7), -mt(7));
+ EXPECT_EQ(mt(7), -mt(-7));
+ EXPECT_EQ(dtw(-7), -dtw(7));
+ EXPECT_EQ(dtw(7), -dtw(-7));
+ EXPECT_EQ(dtm(-7), -dtm(7));
+ EXPECT_EQ(dtm(7), -dtm(-7));
+}
+
+TEST(WTF_Time, times)
+{
+ EXPECT_EQ(s(15), s(3) * 5);
+}
+
+TEST(WTF_Time, divide)
+{
+ EXPECT_EQ(s(3), s(15) / 5);
+}
+
+TEST(WTF_Time, less)
+{
+ EXPECT_FALSE(s(2) < s(1));
+ EXPECT_FALSE(s(2) < s(2));
+ EXPECT_TRUE(s(2) < s(3));
+ EXPECT_FALSE(wt(2) < wt(1));
+ EXPECT_FALSE(wt(2) < wt(2));
+ EXPECT_TRUE(wt(2) < wt(3));
+ EXPECT_FALSE(mt(2) < mt(1));
+ EXPECT_FALSE(mt(2) < mt(2));
+ EXPECT_TRUE(mt(2) < mt(3));
+ EXPECT_FALSE(dtw(2) < dtw(1));
+ EXPECT_FALSE(dtw(2) < dtw(2));
+ EXPECT_TRUE(dtw(2) < dtw(3));
+ EXPECT_FALSE(dtm(2) < dtm(1));
+ EXPECT_FALSE(dtm(2) < dtm(2));
+ EXPECT_TRUE(dtm(2) < dtm(3));
+}
+
+TEST(WTF_Time, lessEqual)
+{
+ EXPECT_FALSE(s(2) <= s(1));
+ EXPECT_TRUE(s(2) <= s(2));
+ EXPECT_TRUE(s(2) <= s(3));
+ EXPECT_FALSE(wt(2) <= wt(1));
+ EXPECT_TRUE(wt(2) <= wt(2));
+ EXPECT_TRUE(wt(2) <= wt(3));
+ EXPECT_FALSE(mt(2) <= mt(1));
+ EXPECT_TRUE(mt(2) <= mt(2));
+ EXPECT_TRUE(mt(2) <= mt(3));
+ EXPECT_FALSE(dtw(2) <= dtw(1));
+ EXPECT_TRUE(dtw(2) <= dtw(2));
+ EXPECT_TRUE(dtw(2) <= dtw(3));
+ EXPECT_FALSE(dtm(2) <= dtm(1));
+ EXPECT_TRUE(dtm(2) <= dtm(2));
+ EXPECT_TRUE(dtm(2) <= dtm(3));
+}
+
+TEST(WTF_Time, greater)
+{
+ EXPECT_TRUE(s(2) > s(1));
+ EXPECT_FALSE(s(2) > s(2));
+ EXPECT_FALSE(s(2) > s(3));
+ EXPECT_TRUE(wt(2) > wt(1));
+ EXPECT_FALSE(wt(2) > wt(2));
+ EXPECT_FALSE(wt(2) > wt(3));
+ EXPECT_TRUE(mt(2) > mt(1));
+ EXPECT_FALSE(mt(2) > mt(2));
+ EXPECT_FALSE(mt(2) > mt(3));
+ EXPECT_TRUE(dtw(2) > dtw(1));
+ EXPECT_FALSE(dtw(2) > dtw(2));
+ EXPECT_FALSE(dtw(2) > dtw(3));
+ EXPECT_TRUE(dtm(2) > dtm(1));
+ EXPECT_FALSE(dtm(2) > dtm(2));
+ EXPECT_FALSE(dtm(2) > dtm(3));
+}
+
+TEST(WTF_Time, greaterEqual)
+{
+ EXPECT_TRUE(s(2) >= s(1));
+ EXPECT_TRUE(s(2) >= s(2));
+ EXPECT_FALSE(s(2) >= s(3));
+ EXPECT_TRUE(wt(2) >= wt(1));
+ EXPECT_TRUE(wt(2) >= wt(2));
+ EXPECT_FALSE(wt(2) >= wt(3));
+ EXPECT_TRUE(mt(2) >= mt(1));
+ EXPECT_TRUE(mt(2) >= mt(2));
+ EXPECT_FALSE(mt(2) >= mt(3));
+ EXPECT_TRUE(dtw(2) >= dtw(1));
+ EXPECT_TRUE(dtw(2) >= dtw(2));
+ EXPECT_FALSE(dtw(2) >= dtw(3));
+ EXPECT_TRUE(dtm(2) >= dtm(1));
+ EXPECT_TRUE(dtm(2) >= dtm(2));
+ EXPECT_FALSE(dtm(2) >= dtm(3));
+}
+
+TEST(WTF_Time, equal)
+{
+ EXPECT_FALSE(s(2) == s(1));
+ EXPECT_TRUE(s(2) == s(2));
+ EXPECT_FALSE(s(2) == s(3));
+ EXPECT_FALSE(wt(2) == wt(1));
+ EXPECT_TRUE(wt(2) == wt(2));
+ EXPECT_FALSE(wt(2) == wt(3));
+ EXPECT_FALSE(mt(2) == mt(1));
+ EXPECT_TRUE(mt(2) == mt(2));
+ EXPECT_FALSE(mt(2) == mt(3));
+ EXPECT_FALSE(dtw(2) == dtw(1));
+ EXPECT_TRUE(dtw(2) == dtw(2));
+ EXPECT_FALSE(dtw(2) == dtw(3));
+ EXPECT_FALSE(dtm(2) == dtm(1));
+ EXPECT_TRUE(dtm(2) == dtm(2));
+ EXPECT_FALSE(dtm(2) == dtm(3));
+}
+
+TEST(WTF_Time, notEqual)
+{
+ EXPECT_TRUE(s(2) != s(1));
+ EXPECT_FALSE(s(2) != s(2));
+ EXPECT_TRUE(s(2) != s(3));
+ EXPECT_TRUE(wt(2) != wt(1));
+ EXPECT_FALSE(wt(2) != wt(2));
+ EXPECT_TRUE(wt(2) != wt(3));
+ EXPECT_TRUE(mt(2) != mt(1));
+ EXPECT_FALSE(mt(2) != mt(2));
+ EXPECT_TRUE(mt(2) != mt(3));
+ EXPECT_TRUE(dtw(2) != dtw(1));
+ EXPECT_FALSE(dtw(2) != dtw(2));
+ EXPECT_TRUE(dtw(2) != dtw(3));
+ EXPECT_TRUE(dtm(2) != dtm(1));
+ EXPECT_FALSE(dtm(2) != dtm(2));
+ EXPECT_TRUE(dtm(2) != dtm(3));
+}
+
+TEST(WTF_Time, literals)
+{
+ EXPECT_TRUE(s(120) == 2_min);
+ EXPECT_TRUE(s(2) == 2_s);
+ EXPECT_TRUE(s(2) == 2000_ms);
+ EXPECT_TRUE(s(2) - 1000_ms == s(1));
+ EXPECT_TRUE(2_s - s(1) == 1000_ms);
+
+ EXPECT_TRUE(Seconds::fromMinutes(2) == 2_min);
+ EXPECT_TRUE(Seconds(2) == 2_s);
+ EXPECT_TRUE(Seconds::fromMilliseconds(2) == 2_ms);
+ EXPECT_TRUE(Seconds::fromMicroseconds(2) == 2_us);
+ EXPECT_TRUE(Seconds::fromNanoseconds(2) == 2_ns);
+
+ EXPECT_TRUE(Seconds::fromMinutes(2.5) == 2.5_min);
+ EXPECT_TRUE(Seconds(2.5) == 2.5_s);
+ EXPECT_TRUE(Seconds::fromMilliseconds(2.5) == 2.5_ms);
+ EXPECT_TRUE(Seconds::fromMicroseconds(2.5) == 2.5_us);
+ EXPECT_TRUE(Seconds::fromNanoseconds(2.5) == 2.5_ns);
+}
+
+} // namespace TestWebKitAPI
+
diff --git a/Tools/TestWebKitAPI/Tests/WTF/UniqueRef.cpp b/Tools/TestWebKitAPI/Tests/WTF/UniqueRef.cpp
new file mode 100644
index 000000000..4d2b22aa5
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/UniqueRef.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <wtf/UniqueRef.h>
+#include <wtf/Vector.h>
+
+namespace TestWebKitAPI {
+
+class A { };
+class B {
+public:
+ B(int a, int b, int c)
+ : a(a)
+ , b(b)
+ , c(c)
+ { };
+ int a;
+ int b;
+ int c;
+};
+class C {
+public:
+ C(UniqueRef<A>&& a)
+ : a(WTFMove(a))
+ { }
+ UniqueRef<A> a;
+};
+class D : public A { };
+
+void function(const UniqueRef<A> a)
+{
+ const A& b = a.get();
+ const A* c = &a;
+ UNUSED_PARAM(b);
+ UNUSED_PARAM(c);
+}
+
+TEST(WTF, UniqueRef)
+{
+ UniqueRef<A> a = makeUniqueRef<A>();
+ UniqueRef<B> b = makeUniqueRef<B>(1, 2, 3);
+ B& c = b.get();
+ const B& d = b.get();
+ B* e = &b;
+ const B* f = &b;
+ UniqueRef<A> j = WTFMove(a);
+
+ Vector<UniqueRef<B>> v;
+ v.append(makeUniqueRef<B>(4, 5, 6));
+ v.append(makeUniqueRef<B>(7, 8, 9));
+ UniqueRef<B> g = v.takeLast();
+ ASSERT_EQ(g->b, 8);
+ ASSERT_EQ(v.last()->b, 5);
+
+ C h(makeUniqueRef<A>());
+ C i(makeUniqueRef<D>());
+
+ UNUSED_PARAM(b);
+ UNUSED_PARAM(c);
+ UNUSED_PARAM(d);
+ UNUSED_PARAM(e);
+ UNUSED_PARAM(f);
+ UNUSED_PARAM(g);
+ UNUSED_PARAM(h);
+ UNUSED_PARAM(i);
+ UNUSED_PARAM(j);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/Variant.cpp b/Tools/TestWebKitAPI/Tests/WTF/Variant.cpp
new file mode 100644
index 000000000..b68156179
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/Variant.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "Counters.h"
+#include "RefLogger.h"
+#include <wtf/Ref.h>
+#include <wtf/RefPtr.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/Variant.h>
+#include <wtf/text/WTFString.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF_Variant, Initial)
+{
+ Variant<int, double> v1;
+ EXPECT_TRUE(v1.index() == 0);
+ EXPECT_TRUE(WTF::get<int>(v1) == 0);
+
+ struct T {
+ T() : value(15) { }
+ int value;
+ };
+
+ Variant<T, int> v2;
+ EXPECT_TRUE(v2.index() == 0);
+ EXPECT_TRUE(WTF::get<T>(v2).value == 15);
+}
+
+TEST(WTF_Variant, Basic)
+{
+ Variant<int, double> variant = 1;
+ EXPECT_TRUE(variant.index() == 0);
+ EXPECT_TRUE(WTF::get<int>(variant) == 1);
+ EXPECT_TRUE(*WTF::get_if<int>(variant) == 1);
+ EXPECT_TRUE(WTF::get_if<double>(variant) == nullptr);
+ EXPECT_TRUE(WTF::holds_alternative<int>(variant));
+ EXPECT_FALSE(WTF::holds_alternative<double>(variant));
+
+ variant = 1.0;
+ EXPECT_TRUE(variant.index() == 1);
+ EXPECT_TRUE(WTF::get<double>(variant) == 1);
+ EXPECT_TRUE(*WTF::get_if<double>(variant) == 1.0);
+ EXPECT_TRUE(WTF::get_if<int>(variant) == nullptr);
+ EXPECT_TRUE(WTF::holds_alternative<double>(variant));
+ EXPECT_FALSE(WTF::holds_alternative<int>(variant));
+}
+
+TEST(WTF_Variant, BasicVisitor)
+{
+ enum class Type {
+ None,
+ Int,
+ Float,
+ String,
+ };
+
+ struct Visitor {
+ Visitor(Type& t)
+ : type(t)
+ {
+ }
+
+ Type& type;
+
+ void operator()(int) const { type = Type::Int; }
+ void operator()(float) const { type = Type::Float; }
+ void operator()(String) const { type = Type::String; }
+ };
+
+ Type type = Type::None;
+
+ Variant<int, float, String> variant = 8;
+ WTF::visit(Visitor(type), variant);
+ EXPECT_TRUE(Type::Int == type);
+
+
+ variant = 1.0f;
+ WTF::visit(Visitor(type), variant);
+ EXPECT_TRUE(Type::Float == type);
+
+
+ variant = "hello";
+ WTF::visit(Visitor(type), variant);
+ EXPECT_TRUE(Type::String == type);
+}
+
+TEST(WTF_Variant, VisitorUsingMakeVisitor)
+{
+ enum class Type {
+ None,
+ Int,
+ Float,
+ String,
+ };
+
+ Type type = Type::None;
+
+ auto visitor = WTF::makeVisitor(
+ [&](int) { type = Type::Int; },
+ [&](float) { type = Type::Float; },
+ [&](String) { type = Type::String; }
+ );
+
+ Variant<int, float, String> variant = 8;
+ WTF::visit(visitor, variant);
+ EXPECT_TRUE(Type::Int == type);
+
+
+ variant = 1.0f;
+ WTF::visit(visitor, variant);
+ EXPECT_TRUE(Type::Float == type);
+
+
+ variant = "hello";
+ WTF::visit(visitor, variant);
+ EXPECT_TRUE(Type::String == type);
+}
+
+TEST(WTF_Variant, VisitorUsingSwitchOn)
+{
+ enum class Type {
+ None,
+ Int,
+ Float,
+ String,
+ };
+
+ Type type = Type::None;
+
+ Variant<int, float, String> variant = 8;
+ type = WTF::switchOn(variant,
+ [](int) { return Type::Int; },
+ [](float) { return Type::Float; },
+ [](String) { return Type::String; }
+ );
+ EXPECT_TRUE(Type::Int == type);
+
+
+ variant = 1.0f;
+ type = WTF::switchOn(variant,
+ [](int) { return Type::Int; },
+ [](float) { return Type::Float; },
+ [](String) { return Type::String; }
+ );
+ EXPECT_TRUE(Type::Float == type);
+
+
+ variant = "hello";
+ type = WTF::switchOn(variant,
+ [](int) { return Type::Int; },
+ [](float) { return Type::Float; },
+ [](String) { return Type::String; }
+ );
+ EXPECT_TRUE(Type::String == type);
+}
+
+TEST(WTF_Variant, ConstructorDestructor)
+{
+ ConstructorDestructorCounter::TestingScope scope;
+
+ {
+ auto uniquePtr = std::make_unique<ConstructorDestructorCounter>();
+ Variant<std::unique_ptr<ConstructorDestructorCounter>, int> v = WTFMove(uniquePtr);
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
+ }
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount);
+}
+
+TEST(WTF_Variant, RefPtr)
+{
+ {
+ RefLogger a("a");
+ RefPtr<RefLogger> ref(&a);
+ Variant<RefPtr<RefLogger>, int> v = ref;
+ }
+
+ ASSERT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefLogger a("a");
+ RefPtr<RefLogger> ref(&a);
+ Variant<RefPtr<RefLogger>, int> v = WTFMove(ref);
+ }
+
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_Variant, Ref)
+{
+ {
+ RefLogger a("a");
+ Ref<RefLogger> ref(a);
+ Variant<Ref<RefLogger>, int> v = WTFMove(ref);
+ }
+
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+}
diff --git a/Tools/TestWebKitAPI/Tests/WTF/Vector.cpp b/Tools/TestWebKitAPI/Tests/WTF/Vector.cpp
index 2278784c4..48235b1fc 100644
--- a/Tools/TestWebKitAPI/Tests/WTF/Vector.cpp
+++ b/Tools/TestWebKitAPI/Tests/WTF/Vector.cpp
@@ -27,6 +27,7 @@
#include "MoveOnly.h"
#include <wtf/Vector.h>
+#include <wtf/text/CString.h>
namespace TestWebKitAPI {
@@ -34,8 +35,8 @@ TEST(WTF_Vector, Basic)
{
Vector<int> intVector;
EXPECT_TRUE(intVector.isEmpty());
- EXPECT_EQ(0ul, intVector.size());
- EXPECT_EQ(0ul, intVector.capacity());
+ EXPECT_EQ(0U, intVector.size());
+ EXPECT_EQ(0U, intVector.capacity());
}
TEST(WTF_Vector, Iterator)
@@ -66,7 +67,7 @@ TEST(WTF_Vector, OverloadedOperatorAmpersand)
{
struct Test {
private:
- Test* operator&();
+ Test* operator&() = delete;
};
Vector<Test> vector;
@@ -94,6 +95,103 @@ TEST(WTF_Vector, InitializerList)
EXPECT_EQ(4, vector[3]);
}
+TEST(WTF_Vector, InitializeFromOtherInitialCapacity)
+{
+ Vector<int, 3> vector = { 1, 3, 2, 4 };
+ Vector<int, 5> vectorCopy(vector);
+ EXPECT_EQ(4U, vector.size());
+ EXPECT_EQ(4U, vectorCopy.size());
+ EXPECT_EQ(5U, vectorCopy.capacity());
+
+ EXPECT_EQ(1, vectorCopy[0]);
+ EXPECT_EQ(3, vectorCopy[1]);
+ EXPECT_EQ(2, vectorCopy[2]);
+ EXPECT_EQ(4, vectorCopy[3]);
+}
+
+TEST(WTF_Vector, CopyFromOtherInitialCapacity)
+{
+ Vector<int, 3> vector = { 1, 3, 2, 4 };
+ Vector<int, 5> vectorCopy { 0 };
+ EXPECT_EQ(4U, vector.size());
+ EXPECT_EQ(1U, vectorCopy.size());
+
+ vectorCopy = vector;
+
+ EXPECT_EQ(4U, vector.size());
+ EXPECT_EQ(4U, vectorCopy.size());
+ EXPECT_EQ(5U, vectorCopy.capacity());
+
+ EXPECT_EQ(1, vectorCopy[0]);
+ EXPECT_EQ(3, vectorCopy[1]);
+ EXPECT_EQ(2, vectorCopy[2]);
+ EXPECT_EQ(4, vectorCopy[3]);
+}
+
+TEST(WTF_Vector, InitializeFromOtherOverflowBehavior)
+{
+ Vector<int, 7, WTF::CrashOnOverflow> vector = { 4, 3, 2, 1 };
+ Vector<int, 7, UnsafeVectorOverflow> vectorCopy(vector);
+ EXPECT_EQ(4U, vector.size());
+ EXPECT_EQ(4U, vectorCopy.size());
+
+ EXPECT_EQ(4, vectorCopy[0]);
+ EXPECT_EQ(3, vectorCopy[1]);
+ EXPECT_EQ(2, vectorCopy[2]);
+ EXPECT_EQ(1, vectorCopy[3]);
+}
+
+TEST(WTF_Vector, CopyFromOtherOverflowBehavior)
+{
+ Vector<int, 7, WTF::CrashOnOverflow> vector = { 4, 3, 2, 1 };
+ Vector<int, 7, UnsafeVectorOverflow> vectorCopy = { 0, 0, 0 };
+
+ EXPECT_EQ(4U, vector.size());
+ EXPECT_EQ(3U, vectorCopy.size());
+
+ vectorCopy = vector;
+
+ EXPECT_EQ(4U, vector.size());
+ EXPECT_EQ(4U, vectorCopy.size());
+
+ EXPECT_EQ(4, vectorCopy[0]);
+ EXPECT_EQ(3, vectorCopy[1]);
+ EXPECT_EQ(2, vectorCopy[2]);
+ EXPECT_EQ(1, vectorCopy[3]);
+}
+
+TEST(WTF_Vector, InitializeFromOtherMinCapacity)
+{
+ Vector<int, 7, WTF::CrashOnOverflow, 1> vector = { 3, 4, 2, 1 };
+ Vector<int, 7, WTF::CrashOnOverflow, 50> vectorCopy(vector);
+ EXPECT_EQ(4U, vector.size());
+ EXPECT_EQ(4U, vectorCopy.size());
+
+ EXPECT_EQ(3, vectorCopy[0]);
+ EXPECT_EQ(4, vectorCopy[1]);
+ EXPECT_EQ(2, vectorCopy[2]);
+ EXPECT_EQ(1, vectorCopy[3]);
+}
+
+TEST(WTF_Vector, CopyFromOtherMinCapacity)
+{
+ Vector<int, 7, WTF::CrashOnOverflow, 1> vector = { 3, 4, 2, 1 };
+ Vector<int, 7, WTF::CrashOnOverflow, 50> vectorCopy;
+
+ EXPECT_EQ(4U, vector.size());
+ EXPECT_EQ(0U, vectorCopy.size());
+
+ vectorCopy = vector;
+
+ EXPECT_EQ(4U, vector.size());
+ EXPECT_EQ(4U, vectorCopy.size());
+
+ EXPECT_EQ(3, vectorCopy[0]);
+ EXPECT_EQ(4, vectorCopy[1]);
+ EXPECT_EQ(2, vectorCopy[2]);
+ EXPECT_EQ(1, vectorCopy[3]);
+}
+
TEST(WTF_Vector, Reverse)
{
Vector<int> intVector;
@@ -149,12 +247,12 @@ TEST(WTF_Vector, MoveOnly_UncheckedAppend)
vector.reserveInitialCapacity(100);
for (size_t i = 0; i < 100; ++i) {
MoveOnly moveOnly(i);
- vector.uncheckedAppend(std::move(moveOnly));
- EXPECT_EQ(moveOnly.value(), 0U);
+ vector.uncheckedAppend(WTFMove(moveOnly));
+ EXPECT_EQ(0U, moveOnly.value());
}
for (size_t i = 0; i < 100; ++i)
- EXPECT_EQ(vector[i].value(), i);
+ EXPECT_EQ(i, vector[i].value());
}
TEST(WTF_Vector, MoveOnly_Append)
@@ -163,12 +261,12 @@ TEST(WTF_Vector, MoveOnly_Append)
for (size_t i = 0; i < 100; ++i) {
MoveOnly moveOnly(i);
- vector.append(std::move(moveOnly));
- EXPECT_EQ(moveOnly.value(), 0U);
+ vector.append(WTFMove(moveOnly));
+ EXPECT_EQ(0U, moveOnly.value());
}
for (size_t i = 0; i < 100; ++i)
- EXPECT_EQ(vector[i].value(), i);
+ EXPECT_EQ(i, vector[i].value());
for (size_t i = 0; i < 16; ++i) {
Vector<MoveOnly> vector;
@@ -177,13 +275,13 @@ TEST(WTF_Vector, MoveOnly_Append)
for (size_t j = 0; j < i; ++j)
vector.append(j);
- vector.append(std::move(vector[0]));
+ vector.append(WTFMove(vector[0]));
- EXPECT_EQ(vector[0].value(), 0U);
+ EXPECT_EQ(0U, vector[0].value());
for (size_t j = 0; j < i; ++j)
- EXPECT_EQ(vector[j + 1].value(), j);
- EXPECT_EQ(vector.last().value(), i);
+ EXPECT_EQ(j, vector[j + 1].value());
+ EXPECT_EQ(i, vector.last().value());
}
}
@@ -193,7 +291,7 @@ TEST(WTF_Vector, MoveOnly_Insert)
for (size_t i = 0; i < 100; ++i) {
MoveOnly moveOnly(i);
- vector.insert(0, std::move(moveOnly));
+ vector.insert(0, WTFMove(moveOnly));
EXPECT_EQ(0U, moveOnly.value());
}
@@ -203,11 +301,11 @@ TEST(WTF_Vector, MoveOnly_Insert)
for (size_t i = 0; i < 200; i += 2) {
MoveOnly moveOnly(1000 + i);
- vector.insert(i, std::move(moveOnly));
+ vector.insert(i, WTFMove(moveOnly));
EXPECT_EQ(0U, moveOnly.value());
}
- EXPECT_EQ(vector.size(), 200U);
+ EXPECT_EQ(200U, vector.size());
for (size_t i = 0; i < 200; ++i) {
if (i % 2)
EXPECT_EQ(99 - i / 2, vector[i].value());
@@ -216,4 +314,304 @@ TEST(WTF_Vector, MoveOnly_Insert)
}
}
+TEST(WTF_Vector, MoveOnly_TakeLast)
+{
+ Vector<MoveOnly> vector;
+
+ for (size_t i = 0; i < 100; ++i) {
+ MoveOnly moveOnly(i);
+ vector.append(WTFMove(moveOnly));
+ EXPECT_EQ(0U, moveOnly.value());
+ }
+
+ EXPECT_EQ(100U, vector.size());
+ for (size_t i = 0; i < 100; ++i)
+ EXPECT_EQ(99 - i, vector.takeLast().value());
+
+ EXPECT_EQ(0U, vector.size());
+}
+
+TEST(WTF_Vector, VectorOfVectorsOfVectorsInlineCapacitySwap)
+{
+ Vector<Vector<Vector<int, 1>, 1>, 1> a;
+ Vector<Vector<Vector<int, 1>, 1>, 1> b;
+ Vector<Vector<Vector<int, 1>, 1>, 1> c;
+
+ EXPECT_EQ(0U, a.size());
+ EXPECT_EQ(0U, b.size());
+ EXPECT_EQ(0U, c.size());
+
+ Vector<int, 1> x;
+ x.append(42);
+
+ EXPECT_EQ(1U, x.size());
+ EXPECT_EQ(42, x[0]);
+
+ Vector<Vector<int, 1>, 1> y;
+ y.append(x);
+
+ EXPECT_EQ(1U, x.size());
+ EXPECT_EQ(42, x[0]);
+ EXPECT_EQ(1U, y.size());
+ EXPECT_EQ(1U, y[0].size());
+ EXPECT_EQ(42, y[0][0]);
+
+ a.append(y);
+
+ EXPECT_EQ(1U, x.size());
+ EXPECT_EQ(42, x[0]);
+ EXPECT_EQ(1U, y.size());
+ EXPECT_EQ(1U, y[0].size());
+ EXPECT_EQ(42, y[0][0]);
+ EXPECT_EQ(1U, a.size());
+ EXPECT_EQ(1U, a[0].size());
+ EXPECT_EQ(1U, a[0][0].size());
+ EXPECT_EQ(42, a[0][0][0]);
+
+ a.swap(b);
+
+ EXPECT_EQ(0U, a.size());
+ EXPECT_EQ(1U, x.size());
+ EXPECT_EQ(42, x[0]);
+ EXPECT_EQ(1U, y.size());
+ EXPECT_EQ(1U, y[0].size());
+ EXPECT_EQ(42, y[0][0]);
+ EXPECT_EQ(1U, b.size());
+ EXPECT_EQ(1U, b[0].size());
+ EXPECT_EQ(1U, b[0][0].size());
+ EXPECT_EQ(42, b[0][0][0]);
+
+ b.swap(c);
+
+ EXPECT_EQ(0U, a.size());
+ EXPECT_EQ(0U, b.size());
+ EXPECT_EQ(1U, x.size());
+ EXPECT_EQ(42, x[0]);
+ EXPECT_EQ(1U, y.size());
+ EXPECT_EQ(1U, y[0].size());
+ EXPECT_EQ(42, y[0][0]);
+ EXPECT_EQ(1U, c.size());
+ EXPECT_EQ(1U, c[0].size());
+ EXPECT_EQ(1U, c[0][0].size());
+ EXPECT_EQ(42, c[0][0][0]);
+
+ y[0][0] = 24;
+
+ EXPECT_EQ(1U, x.size());
+ EXPECT_EQ(42, x[0]);
+ EXPECT_EQ(1U, y.size());
+ EXPECT_EQ(1U, y[0].size());
+ EXPECT_EQ(24, y[0][0]);
+
+ a.append(y);
+
+ EXPECT_EQ(1U, x.size());
+ EXPECT_EQ(42, x[0]);
+ EXPECT_EQ(1U, y.size());
+ EXPECT_EQ(1U, y[0].size());
+ EXPECT_EQ(24, y[0][0]);
+ EXPECT_EQ(1U, a.size());
+ EXPECT_EQ(1U, a[0].size());
+ EXPECT_EQ(1U, a[0][0].size());
+ EXPECT_EQ(24, a[0][0][0]);
+ EXPECT_EQ(1U, c.size());
+ EXPECT_EQ(1U, c[0].size());
+ EXPECT_EQ(1U, c[0][0].size());
+ EXPECT_EQ(42, c[0][0][0]);
+ EXPECT_EQ(0U, b.size());
+}
+
+TEST(WTF_Vector, RemoveFirst)
+{
+ Vector<int> v;
+ EXPECT_TRUE(v.isEmpty());
+ EXPECT_FALSE(v.removeFirst(1));
+ EXPECT_FALSE(v.removeFirst(-1));
+ EXPECT_TRUE(v.isEmpty());
+
+ v.fill(2, 10);
+ EXPECT_EQ(10U, v.size());
+ EXPECT_FALSE(v.removeFirst(1));
+ EXPECT_EQ(10U, v.size());
+ v.clear();
+
+ v.fill(1, 10);
+ EXPECT_EQ(10U, v.size());
+ EXPECT_TRUE(v.removeFirst(1));
+ EXPECT_TRUE(v == Vector<int>({1, 1, 1, 1, 1, 1, 1, 1, 1}));
+ EXPECT_EQ(9U, v.size());
+ EXPECT_FALSE(v.removeFirst(2));
+ EXPECT_EQ(9U, v.size());
+ EXPECT_TRUE(v == Vector<int>({1, 1, 1, 1, 1, 1, 1, 1, 1}));
+
+ unsigned removed = 0;
+ while (v.removeFirst(1))
+ ++removed;
+ EXPECT_EQ(9U, removed);
+ EXPECT_TRUE(v.isEmpty());
+
+ v.resize(1);
+ EXPECT_EQ(1U, v.size());
+ EXPECT_TRUE(v.removeFirst(1));
+ EXPECT_EQ(0U, v.size());
+ EXPECT_TRUE(v.isEmpty());
+}
+
+TEST(WTF_Vector, RemoveAll)
+{
+ // Using a memcpy-able type.
+ static_assert(VectorTraits<int>::canMoveWithMemcpy, "Should use a memcpy-able type");
+ Vector<int> v;
+ EXPECT_TRUE(v.isEmpty());
+ EXPECT_FALSE(v.removeAll(1));
+ EXPECT_FALSE(v.removeAll(-1));
+ EXPECT_TRUE(v.isEmpty());
+
+ v.fill(1, 10);
+ EXPECT_EQ(10U, v.size());
+ EXPECT_EQ(10U, v.removeAll(1));
+ EXPECT_TRUE(v.isEmpty());
+
+ v.fill(2, 10);
+ EXPECT_EQ(10U, v.size());
+ EXPECT_EQ(0U, v.removeAll(1));
+ EXPECT_EQ(10U, v.size());
+
+ v = {1, 2, 1, 2, 1, 2, 2, 1, 1, 1};
+ EXPECT_EQ(10U, v.size());
+ EXPECT_EQ(6U, v.removeAll(1));
+ EXPECT_EQ(4U, v.size());
+ EXPECT_TRUE(v == Vector<int>({2, 2, 2, 2}));
+ EXPECT_TRUE(v.find(1) == notFound);
+ EXPECT_EQ(4U, v.removeAll(2));
+ EXPECT_TRUE(v.isEmpty());
+
+ v = {3, 1, 2, 1, 2, 1, 2, 2, 1, 1, 1, 3};
+ EXPECT_EQ(12U, v.size());
+ EXPECT_EQ(6U, v.removeAll(1));
+ EXPECT_EQ(6U, v.size());
+ EXPECT_TRUE(v.find(1) == notFound);
+ EXPECT_TRUE(v == Vector<int>({3, 2, 2, 2, 2, 3}));
+
+ EXPECT_EQ(4U, v.removeAll(2));
+ EXPECT_EQ(2U, v.size());
+ EXPECT_TRUE(v.find(2) == notFound);
+ EXPECT_TRUE(v == Vector<int>({3, 3}));
+
+ EXPECT_EQ(2U, v.removeAll(3));
+ EXPECT_TRUE(v.isEmpty());
+
+ v = {1, 1, 1, 3, 2, 4, 2, 2, 2, 4, 4, 3};
+ EXPECT_EQ(12U, v.size());
+ EXPECT_EQ(3U, v.removeAll(1));
+ EXPECT_EQ(9U, v.size());
+ EXPECT_TRUE(v.find(1) == notFound);
+ EXPECT_TRUE(v == Vector<int>({3, 2, 4, 2, 2, 2, 4, 4, 3}));
+
+ // Using a non memcpy-able type.
+ static_assert(!VectorTraits<CString>::canMoveWithMemcpy, "Should use a non memcpy-able type");
+ Vector<CString> vExpected;
+ Vector<CString> v2;
+ EXPECT_TRUE(v2.isEmpty());
+ EXPECT_FALSE(v2.removeAll("1"));
+ EXPECT_TRUE(v2.isEmpty());
+
+ v2.fill("1", 10);
+ EXPECT_EQ(10U, v2.size());
+ EXPECT_EQ(10U, v2.removeAll("1"));
+ EXPECT_TRUE(v2.isEmpty());
+
+ v2.fill("2", 10);
+ EXPECT_EQ(10U, v2.size());
+ EXPECT_EQ(0U, v2.removeAll("1"));
+ EXPECT_EQ(10U, v2.size());
+
+ v2 = {"1", "2", "1", "2", "1", "2", "2", "1", "1", "1"};
+ EXPECT_EQ(10U, v2.size());
+ EXPECT_EQ(6U, v2.removeAll("1"));
+ EXPECT_EQ(4U, v2.size());
+ EXPECT_TRUE(v2.find("1") == notFound);
+ EXPECT_EQ(4U, v2.removeAll("2"));
+ EXPECT_TRUE(v2.isEmpty());
+
+ v2 = {"3", "1", "2", "1", "2", "1", "2", "2", "1", "1", "1", "3"};
+ EXPECT_EQ(12U, v2.size());
+ EXPECT_EQ(6U, v2.removeAll("1"));
+ EXPECT_EQ(6U, v2.size());
+ EXPECT_TRUE(v2.find("1") == notFound);
+ vExpected = {"3", "2", "2", "2", "2", "3"};
+ EXPECT_TRUE(v2 == vExpected);
+
+ EXPECT_EQ(4U, v2.removeAll("2"));
+ EXPECT_EQ(2U, v2.size());
+ EXPECT_TRUE(v2.find("2") == notFound);
+ vExpected = {"3", "3"};
+ EXPECT_TRUE(v2 == vExpected);
+
+ EXPECT_EQ(2U, v2.removeAll("3"));
+ EXPECT_TRUE(v2.isEmpty());
+
+ v2 = {"1", "1", "1", "3", "2", "4", "2", "2", "2", "4", "4", "3"};
+ EXPECT_EQ(12U, v2.size());
+ EXPECT_EQ(3U, v2.removeAll("1"));
+ EXPECT_EQ(9U, v2.size());
+ EXPECT_TRUE(v2.find("1") == notFound);
+ vExpected = {"3", "2", "4", "2", "2", "2", "4", "4", "3"};
+ EXPECT_TRUE(v2 == vExpected);
+}
+
+TEST(WTF_Vector, RemoveFirstMatching)
+{
+ Vector<int> v;
+ EXPECT_TRUE(v.isEmpty());
+ EXPECT_FALSE(v.removeFirstMatching([] (int value) { return value > 0; }));
+ EXPECT_FALSE(v.removeFirstMatching([] (int) { return true; }));
+ EXPECT_FALSE(v.removeFirstMatching([] (int) { return false; }));
+
+ v = {3, 1, 2, 1, 2, 1, 2, 2, 1, 1, 1, 3};
+ EXPECT_EQ(12U, v.size());
+ EXPECT_FALSE(v.removeFirstMatching([] (int) { return false; }));
+ EXPECT_EQ(12U, v.size());
+ EXPECT_FALSE(v.removeFirstMatching([] (int value) { return value < 0; }));
+ EXPECT_EQ(12U, v.size());
+ EXPECT_TRUE(v.removeFirstMatching([] (int value) { return value < 3; }));
+ EXPECT_EQ(11U, v.size());
+ EXPECT_TRUE(v == Vector<int>({3, 2, 1, 2, 1, 2, 2, 1, 1, 1, 3}));
+ EXPECT_TRUE(v.removeFirstMatching([] (int value) { return value > 2; }));
+ EXPECT_EQ(10U, v.size());
+ EXPECT_TRUE(v == Vector<int>({2, 1, 2, 1, 2, 2, 1, 1, 1, 3}));
+ EXPECT_TRUE(v.removeFirstMatching([] (int value) { return value > 2; }));
+ EXPECT_EQ(9U, v.size());
+ EXPECT_TRUE(v == Vector<int>({2, 1, 2, 1, 2, 2, 1, 1, 1}));
+}
+
+TEST(WTF_Vector, RemoveAllMatching)
+{
+ Vector<int> v;
+ EXPECT_TRUE(v.isEmpty());
+ EXPECT_FALSE(v.removeAllMatching([] (int value) { return value > 0; }));
+ EXPECT_FALSE(v.removeAllMatching([] (int) { return true; }));
+ EXPECT_FALSE(v.removeAllMatching([] (int) { return false; }));
+
+ v = {3, 1, 2, 1, 2, 1, 2, 2, 1, 1, 1, 3};
+ EXPECT_EQ(12U, v.size());
+ EXPECT_EQ(0U, v.removeAllMatching([] (int) { return false; }));
+ EXPECT_EQ(12U, v.size());
+ EXPECT_EQ(0U, v.removeAllMatching([] (int value) { return value < 0; }));
+ EXPECT_EQ(12U, v.size());
+ EXPECT_EQ(12U, v.removeAllMatching([] (int value) { return value > 0; }));
+ EXPECT_TRUE(v.isEmpty());
+
+ v = {3, 1, 2, 1, 2, 1, 3, 2, 2, 1, 1, 1, 3};
+ EXPECT_EQ(13U, v.size());
+ EXPECT_EQ(3U, v.removeAllMatching([] (int value) { return value > 2; }));
+ EXPECT_EQ(10U, v.size());
+ EXPECT_TRUE(v == Vector<int>({1, 2, 1, 2, 1, 2, 2, 1, 1, 1}));
+ EXPECT_EQ(6U, v.removeAllMatching([] (int value) { return value != 2; }));
+ EXPECT_EQ(4U, v.size());
+ EXPECT_TRUE(v == Vector<int>({2, 2, 2, 2}));
+ EXPECT_EQ(4U, v.removeAllMatching([] (int value) { return value == 2; }));
+ EXPECT_TRUE(v.isEmpty());
+}
+
} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/WTFString.cpp b/Tools/TestWebKitAPI/Tests/WTF/WTFString.cpp
new file mode 100644
index 000000000..27649658c
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/WTFString.cpp
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <limits>
+#include <wtf/MathExtras.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/WTFString.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF, StringCreationFromLiteral)
+{
+ String stringFromLiteral(ASCIILiteral("Explicit construction syntax"));
+ ASSERT_EQ(strlen("Explicit construction syntax"), stringFromLiteral.length());
+ ASSERT_TRUE(stringFromLiteral == "Explicit construction syntax");
+ ASSERT_TRUE(stringFromLiteral.is8Bit());
+ ASSERT_TRUE(String("Explicit construction syntax") == stringFromLiteral);
+
+ String stringWithTemplate("Template Literal", String::ConstructFromLiteral);
+ ASSERT_EQ(strlen("Template Literal"), stringWithTemplate.length());
+ ASSERT_TRUE(stringWithTemplate == "Template Literal");
+ ASSERT_TRUE(stringWithTemplate.is8Bit());
+ ASSERT_TRUE(String("Template Literal") == stringWithTemplate);
+}
+
+TEST(WTF, StringASCII)
+{
+ CString output;
+
+ // Null String.
+ output = String().ascii();
+ ASSERT_STREQ("", output.data());
+
+ // Empty String.
+ output = emptyString().ascii();
+ ASSERT_STREQ("", output.data());
+
+ // Regular String.
+ output = String(ASCIILiteral("foobar")).ascii();
+ ASSERT_STREQ("foobar", output.data());
+}
+
+static void testNumberToStringECMAScript(double number, const char* reference)
+{
+ CString numberString = String::numberToStringECMAScript(number).latin1();
+ ASSERT_STREQ(reference, numberString.data());
+}
+
+TEST(WTF, StringNumberToStringECMAScriptBoundaries)
+{
+ typedef std::numeric_limits<double> Limits;
+
+ // Infinity.
+ testNumberToStringECMAScript(Limits::infinity(), "Infinity");
+ testNumberToStringECMAScript(-Limits::infinity(), "-Infinity");
+
+ // NaN.
+ testNumberToStringECMAScript(-Limits::quiet_NaN(), "NaN");
+
+ // Zeros.
+ testNumberToStringECMAScript(0, "0");
+ testNumberToStringECMAScript(-0, "0");
+
+ // Min-Max.
+ testNumberToStringECMAScript(Limits::min(), "2.2250738585072014e-308");
+ testNumberToStringECMAScript(Limits::max(), "1.7976931348623157e+308");
+}
+
+TEST(WTF, StringNumberToStringECMAScriptRegularNumbers)
+{
+ // Pi.
+ testNumberToStringECMAScript(piDouble, "3.141592653589793");
+ testNumberToStringECMAScript(piFloat, "3.1415927410125732");
+ testNumberToStringECMAScript(piOverTwoDouble, "1.5707963267948966");
+ testNumberToStringECMAScript(piOverTwoFloat, "1.5707963705062866");
+ testNumberToStringECMAScript(piOverFourDouble, "0.7853981633974483");
+ testNumberToStringECMAScript(piOverFourFloat, "0.7853981852531433");
+
+ // e.
+ const double e = 2.71828182845904523536028747135266249775724709369995;
+ testNumberToStringECMAScript(e, "2.718281828459045");
+
+ // c, speed of light in m/s.
+ const double c = 299792458;
+ testNumberToStringECMAScript(c, "299792458");
+
+ // Golen ratio.
+ const double phi = 1.6180339887498948482;
+ testNumberToStringECMAScript(phi, "1.618033988749895");
+}
+
+TEST(WTF, StringReplaceWithLiteral)
+{
+ // Cases for 8Bit source.
+ String testString = "1224";
+ ASSERT_TRUE(testString.is8Bit());
+ testString.replaceWithLiteral('2', "");
+ ASSERT_STREQ("14", testString.utf8().data());
+
+ testString = "1224";
+ ASSERT_TRUE(testString.is8Bit());
+ testString.replaceWithLiteral('2', "3");
+ ASSERT_STREQ("1334", testString.utf8().data());
+
+ testString = "1224";
+ ASSERT_TRUE(testString.is8Bit());
+ testString.replaceWithLiteral('2', "555");
+ ASSERT_STREQ("15555554", testString.utf8().data());
+
+ testString = "1224";
+ ASSERT_TRUE(testString.is8Bit());
+ testString.replaceWithLiteral('3', "NotFound");
+ ASSERT_STREQ("1224", testString.utf8().data());
+
+ // Cases for 16Bit source.
+ testString = String::fromUTF8("résumé");
+ ASSERT_FALSE(testString.is8Bit());
+ testString.replaceWithLiteral(UChar(0x00E9 /*U+00E9 is 'é'*/), "e");
+ ASSERT_STREQ("resume", testString.utf8().data());
+
+ testString = String::fromUTF8("résumé");
+ ASSERT_FALSE(testString.is8Bit());
+ testString.replaceWithLiteral(UChar(0x00E9 /*U+00E9 is 'é'*/), "");
+ ASSERT_STREQ("rsum", testString.utf8().data());
+
+ testString = String::fromUTF8("résumé");
+ ASSERT_FALSE(testString.is8Bit());
+ testString.replaceWithLiteral('3', "NotFound");
+ ASSERT_STREQ("résumé", testString.utf8().data());
+}
+
+TEST(WTF, StringIsolatedCopy)
+{
+ String original = "1234";
+ auto copy = WTFMove(original).isolatedCopy();
+ ASSERT_FALSE(original.impl() == copy.impl());
+}
+
+TEST(WTF, StringToInt)
+{
+ bool ok = false;
+
+ EXPECT_EQ(0, String().toInt());
+ EXPECT_EQ(0, String().toInt(&ok));
+ EXPECT_FALSE(ok);
+
+ EXPECT_EQ(0, emptyString().toInt());
+ EXPECT_EQ(0, emptyString().toInt(&ok));
+ EXPECT_FALSE(ok);
+
+ EXPECT_EQ(0, String("0").toInt());
+ EXPECT_EQ(0, String("0").toInt(&ok));
+ EXPECT_TRUE(ok);
+
+ EXPECT_EQ(1, String("1").toInt());
+ EXPECT_EQ(1, String("1").toInt(&ok));
+ EXPECT_TRUE(ok);
+
+ EXPECT_EQ(2147483647, String("2147483647").toInt());
+ EXPECT_EQ(2147483647, String("2147483647").toInt(&ok));
+ EXPECT_TRUE(ok);
+
+ EXPECT_EQ(0, String("2147483648").toInt());
+ EXPECT_EQ(0, String("2147483648").toInt(&ok));
+ EXPECT_FALSE(ok);
+
+ EXPECT_EQ(-2147483648, String("-2147483648").toInt());
+ EXPECT_EQ(-2147483648, String("-2147483648").toInt(&ok));
+ EXPECT_TRUE(ok);
+
+ EXPECT_EQ(0, String("-2147483649").toInt());
+ EXPECT_EQ(0, String("-2147483649").toInt(&ok));
+ EXPECT_FALSE(ok);
+
+ // fail if we see leading junk
+ EXPECT_EQ(0, String("x1").toInt());
+ EXPECT_EQ(0, String("x1").toInt(&ok));
+ EXPECT_FALSE(ok);
+
+ // succeed if we see leading spaces
+ EXPECT_EQ(1, String(" 1").toInt());
+ EXPECT_EQ(1, String(" 1").toInt(&ok));
+ EXPECT_TRUE(ok);
+
+ // silently ignore trailing junk
+ EXPECT_EQ(1, String("1x").toInt());
+ EXPECT_EQ(1, String("1x").toInt(&ok));
+ EXPECT_TRUE(ok);
+}
+
+TEST(WTF, StringToDouble)
+{
+ bool ok = false;
+
+ EXPECT_EQ(0.0, String().toDouble());
+ EXPECT_EQ(0.0, String().toDouble(&ok));
+ EXPECT_FALSE(ok);
+
+ EXPECT_EQ(0.0, emptyString().toDouble());
+ EXPECT_EQ(0.0, emptyString().toDouble(&ok));
+ EXPECT_FALSE(ok);
+
+ EXPECT_EQ(0.0, String("0").toDouble());
+ EXPECT_EQ(0.0, String("0").toDouble(&ok));
+ EXPECT_TRUE(ok);
+
+ EXPECT_EQ(1.0, String("1").toDouble());
+ EXPECT_EQ(1.0, String("1").toDouble(&ok));
+ EXPECT_TRUE(ok);
+
+ // fail if we see leading junk
+ EXPECT_EQ(0.0, String("x1").toDouble());
+ EXPECT_EQ(0.0, String("x1").toDouble(&ok));
+ EXPECT_FALSE(ok);
+
+ // succeed if we see leading spaces
+ EXPECT_EQ(1.0, String(" 1").toDouble());
+ EXPECT_EQ(1.0, String(" 1").toDouble(&ok));
+ EXPECT_TRUE(ok);
+
+ // ignore trailing junk, but return false for "ok"
+ // FIXME: This is an inconsistency with toInt, which always guarantees
+ // it will return 0 if it's also going to return false for ok.
+ EXPECT_EQ(1.0, String("1x").toDouble());
+ EXPECT_EQ(1.0, String("1x").toDouble(&ok));
+ EXPECT_FALSE(ok);
+
+ // parse only numbers, not special values such as "infinity"
+ EXPECT_EQ(0.0, String("infinity").toDouble());
+ EXPECT_EQ(0.0, String("infinity").toDouble(&ok));
+ EXPECT_FALSE(ok);
+
+ // parse only numbers, not special values such as "nan"
+ EXPECT_EQ(0.0, String("nan").toDouble());
+ EXPECT_EQ(0.0, String("nan").toDouble(&ok));
+ EXPECT_FALSE(ok);
+}
+
+TEST(WTF, StringhasInfixStartingAt)
+{
+ EXPECT_TRUE(String("Test").is8Bit());
+ EXPECT_TRUE(String("Te").is8Bit());
+ EXPECT_TRUE(String("st").is8Bit());
+ EXPECT_TRUE(String("Test").hasInfixStartingAt(String("Te"), 0));
+ EXPECT_FALSE(String("Test").hasInfixStartingAt(String("Te"), 2));
+ EXPECT_TRUE(String("Test").hasInfixStartingAt(String("st"), 2));
+ EXPECT_FALSE(String("Test").hasInfixStartingAt(String("ST"), 2));
+
+ EXPECT_FALSE(String::fromUTF8("中国").is8Bit());
+ EXPECT_FALSE(String::fromUTF8("中").is8Bit());
+ EXPECT_FALSE(String::fromUTF8("国").is8Bit());
+ EXPECT_TRUE(String::fromUTF8("中国").hasInfixStartingAt(String::fromUTF8("中"), 0));
+ EXPECT_FALSE(String::fromUTF8("中国").hasInfixStartingAt(String::fromUTF8("中"), 1));
+ EXPECT_TRUE(String::fromUTF8("中国").hasInfixStartingAt(String::fromUTF8("国"), 1));
+
+ EXPECT_FALSE(String::fromUTF8("中国").hasInfixStartingAt(String("Te"), 0));
+ EXPECT_FALSE(String("Test").hasInfixStartingAt(String::fromUTF8("中"), 2));
+}
+
+TEST(WTF, StringExistingHash)
+{
+ String string1("Template Literal");
+ ASSERT_FALSE(string1.isNull());
+ ASSERT_FALSE(string1.impl()->hasHash());
+ string1.impl()->hash();
+ ASSERT_EQ(string1.existingHash(), string1.impl()->existingHash());
+ String string2;
+ ASSERT_EQ(string2.existingHash(), 0u);
+}
+
+TEST(WTF, StringUnicodeEqualUCharArray)
+{
+ String string1("abc");
+ ASSERT_FALSE(string1.isNull());
+ ASSERT_TRUE(string1.is8Bit());
+ UChar ab[] = { 'a', 'b' };
+ UChar abc[] = { 'a', 'b', 'c' };
+ UChar abcd[] = { 'a', 'b', 'c', 'd' };
+ UChar aBc[] = { 'a', 'B', 'c' };
+ ASSERT_FALSE(equal(string1, ab));
+ ASSERT_TRUE(equal(string1, abc));
+ ASSERT_FALSE(equal(string1, abcd));
+ ASSERT_FALSE(equal(string1, aBc));
+
+ String string2(abc, 3);
+ ASSERT_FALSE(equal(string2, ab));
+ ASSERT_TRUE(equal(string2, abc));
+ ASSERT_FALSE(equal(string2, abcd));
+ ASSERT_FALSE(equal(string2, aBc));
+}
+
+TEST(WTF, StringRightBasic)
+{
+ auto reference = String::fromUTF8("Cappuccino");
+ EXPECT_TRUE(reference.right(0) == String::fromUTF8(""));
+ EXPECT_TRUE(reference.right(1) == String::fromUTF8("o"));
+ EXPECT_TRUE(reference.right(2) == String::fromUTF8("no"));
+ EXPECT_TRUE(reference.right(3) == String::fromUTF8("ino"));
+ EXPECT_TRUE(reference.right(4) == String::fromUTF8("cino"));
+ EXPECT_TRUE(reference.right(5) == String::fromUTF8("ccino"));
+ EXPECT_TRUE(reference.right(6) == String::fromUTF8("uccino"));
+ EXPECT_TRUE(reference.right(7) == String::fromUTF8("puccino"));
+ EXPECT_TRUE(reference.right(8) == String::fromUTF8("ppuccino"));
+ EXPECT_TRUE(reference.right(9) == String::fromUTF8("appuccino"));
+ EXPECT_TRUE(reference.right(10) == String::fromUTF8("Cappuccino"));
+}
+
+TEST(WTF, StringLeftBasic)
+{
+ auto reference = String::fromUTF8("Cappuccino");
+ EXPECT_TRUE(reference.left(0) == String::fromUTF8(""));
+ EXPECT_TRUE(reference.left(1) == String::fromUTF8("C"));
+ EXPECT_TRUE(reference.left(2) == String::fromUTF8("Ca"));
+ EXPECT_TRUE(reference.left(3) == String::fromUTF8("Cap"));
+ EXPECT_TRUE(reference.left(4) == String::fromUTF8("Capp"));
+ EXPECT_TRUE(reference.left(5) == String::fromUTF8("Cappu"));
+ EXPECT_TRUE(reference.left(6) == String::fromUTF8("Cappuc"));
+ EXPECT_TRUE(reference.left(7) == String::fromUTF8("Cappucc"));
+ EXPECT_TRUE(reference.left(8) == String::fromUTF8("Cappucci"));
+ EXPECT_TRUE(reference.left(9) == String::fromUTF8("Cappuccin"));
+ EXPECT_TRUE(reference.left(10) == String::fromUTF8("Cappuccino"));
+}
+
+TEST(WTF, StringReverseFindBasic)
+{
+ auto reference = String::fromUTF8("Cappuccino");
+ EXPECT_EQ(reference.reverseFind('o'), 9U);
+ EXPECT_EQ(reference.reverseFind('n'), 8U);
+ EXPECT_EQ(reference.reverseFind('c'), 6U);
+ EXPECT_EQ(reference.reverseFind('p'), 3U);
+ EXPECT_EQ(reference.reverseFind('k'), notFound);
+
+ EXPECT_EQ(reference.reverseFind('o', 8), notFound);
+ EXPECT_EQ(reference.reverseFind('c', 8), 6U);
+ EXPECT_EQ(reference.reverseFind('c', 6), 6U);
+ EXPECT_EQ(reference.reverseFind('c', 5), 5U);
+ EXPECT_EQ(reference.reverseFind('c', 4), notFound);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/WeakPtr.cpp b/Tools/TestWebKitAPI/Tests/WTF/WeakPtr.cpp
new file mode 100644
index 000000000..745aadd2b
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/WeakPtr.cpp
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "Test.h"
+#include <wtf/WeakPtr.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF_WeakPtr, Basic)
+{
+ int dummy = 5;
+ WeakPtrFactory<int>* factory = new WeakPtrFactory<int>(&dummy);
+ WeakPtr<int> weakPtr1 = factory->createWeakPtr();
+ WeakPtr<int> weakPtr2 = factory->createWeakPtr();
+ WeakPtr<int> weakPtr3 = factory->createWeakPtr();
+ EXPECT_EQ(weakPtr1.get(), &dummy);
+ EXPECT_EQ(weakPtr2.get(), &dummy);
+ EXPECT_EQ(weakPtr3.get(), &dummy);
+ EXPECT_TRUE(weakPtr1);
+ EXPECT_TRUE(weakPtr2);
+ EXPECT_TRUE(weakPtr3);
+ EXPECT_TRUE(weakPtr1 == weakPtr2);
+ EXPECT_TRUE(weakPtr1 == &dummy);
+ EXPECT_TRUE(&dummy == weakPtr2);
+ delete factory;
+ EXPECT_NULL(weakPtr1.get());
+ EXPECT_NULL(weakPtr2.get());
+ EXPECT_NULL(weakPtr3.get());
+ EXPECT_FALSE(weakPtr1);
+ EXPECT_FALSE(weakPtr2);
+ EXPECT_FALSE(weakPtr3);
+}
+
+TEST(WTF_WeakPtr, Assignment)
+{
+ int dummy = 5;
+ WeakPtr<int> weakPtr;
+ {
+ WeakPtrFactory<int> factory(&dummy);
+ EXPECT_NULL(weakPtr.get());
+ weakPtr = factory.createWeakPtr();
+ EXPECT_EQ(weakPtr.get(), &dummy);
+ }
+ EXPECT_NULL(weakPtr.get());
+}
+
+TEST(WTF_WeakPtr, MultipleFactories)
+{
+ int dummy1 = 5;
+ int dummy2 = 7;
+ WeakPtrFactory<int>* factory1 = new WeakPtrFactory<int>(&dummy1);
+ WeakPtrFactory<int>* factory2 = new WeakPtrFactory<int>(&dummy2);
+ WeakPtr<int> weakPtr1 = factory1->createWeakPtr();
+ WeakPtr<int> weakPtr2 = factory2->createWeakPtr();
+ EXPECT_EQ(weakPtr1.get(), &dummy1);
+ EXPECT_EQ(weakPtr2.get(), &dummy2);
+ EXPECT_TRUE(weakPtr1 != weakPtr2);
+ EXPECT_TRUE(weakPtr1 != &dummy2);
+ EXPECT_TRUE(&dummy1 != weakPtr2);
+ delete factory1;
+ EXPECT_NULL(weakPtr1.get());
+ EXPECT_EQ(weakPtr2.get(), &dummy2);
+ delete factory2;
+ EXPECT_NULL(weakPtr2.get());
+}
+
+TEST(WTF_WeakPtr, RevokeAll)
+{
+ int dummy = 5;
+ WeakPtrFactory<int> factory(&dummy);
+ WeakPtr<int> weakPtr1 = factory.createWeakPtr();
+ WeakPtr<int> weakPtr2 = factory.createWeakPtr();
+ WeakPtr<int> weakPtr3 = factory.createWeakPtr();
+ EXPECT_EQ(weakPtr1.get(), &dummy);
+ EXPECT_EQ(weakPtr2.get(), &dummy);
+ EXPECT_EQ(weakPtr3.get(), &dummy);
+ factory.revokeAll();
+ EXPECT_NULL(weakPtr1.get());
+ EXPECT_NULL(weakPtr2.get());
+ EXPECT_NULL(weakPtr3.get());
+}
+
+TEST(WTF_WeakPtr, NullFactory)
+{
+ WeakPtrFactory<int> factory(nullptr);
+ WeakPtr<int> weakPtr = factory.createWeakPtr();
+ EXPECT_NULL(weakPtr.get());
+ factory.revokeAll();
+ EXPECT_NULL(weakPtr.get());
+}
+
+struct Foo {
+ void bar() { };
+};
+
+TEST(WTF_WeakPtr, Dereference)
+{
+ Foo f;
+ WeakPtrFactory<Foo> factory(&f);
+ WeakPtr<Foo> weakPtr = factory.createWeakPtr();
+ weakPtr->bar();
+}
+
+TEST(WTF_WeakPtr, Forget)
+{
+ int dummy = 5;
+ int dummy2 = 7;
+
+ WeakPtrFactory<int> outerFactory(&dummy2);
+ WeakPtr<int> weakPtr1, weakPtr2, weakPtr3, weakPtr4;
+ {
+ WeakPtrFactory<int> innerFactory(&dummy);
+ weakPtr1 = innerFactory.createWeakPtr();
+ weakPtr2 = innerFactory.createWeakPtr();
+ weakPtr3 = innerFactory.createWeakPtr();
+ EXPECT_EQ(weakPtr1.get(), &dummy);
+ EXPECT_EQ(weakPtr2.get(), &dummy);
+ EXPECT_EQ(weakPtr3.get(), &dummy);
+ weakPtr1.clear();
+ weakPtr3 = nullptr;
+ EXPECT_NULL(weakPtr1.get());
+ EXPECT_EQ(weakPtr2.get(), &dummy);
+ EXPECT_NULL(weakPtr3.get());
+ weakPtr1.clear();
+ weakPtr3.clear();
+ EXPECT_NULL(weakPtr1.get());
+ EXPECT_EQ(weakPtr2.get(), &dummy);
+ EXPECT_NULL(weakPtr3.get());
+ weakPtr3 = nullptr;
+ EXPECT_NULL(weakPtr1.get());
+ EXPECT_EQ(weakPtr2.get(), &dummy);
+ EXPECT_NULL(weakPtr3.get());
+
+ weakPtr4 = weakPtr2;
+ EXPECT_EQ(weakPtr2.get(), &dummy);
+ EXPECT_EQ(weakPtr4.get(), &dummy);
+
+ WeakPtr<int> weakPtr5 = weakPtr2;
+ EXPECT_EQ(weakPtr2.get(), &dummy);
+ EXPECT_EQ(weakPtr5.get(), &dummy);
+ weakPtr5.clear();
+ EXPECT_NULL(weakPtr5.get());
+ EXPECT_EQ(weakPtr2.get(), &dummy);
+
+ weakPtr4 = outerFactory.createWeakPtr();
+ EXPECT_EQ(weakPtr2.get(), &dummy);
+ EXPECT_EQ(weakPtr4.get(), &dummy2);
+ }
+
+ EXPECT_NULL(weakPtr1.get());
+ EXPECT_NULL(weakPtr2.get());
+ EXPECT_EQ(weakPtr4.get(), &dummy2);
+
+ WeakPtr<int> weakPtr5 = weakPtr4;
+ EXPECT_EQ(weakPtr4.get(), &dummy2);
+ EXPECT_EQ(weakPtr5.get(), &dummy2);
+ weakPtr5.clear();
+ EXPECT_NULL(weakPtr5.get());
+ WeakPtr<int> weakPtr6 = weakPtr5;
+ EXPECT_NULL(weakPtr6.get());
+ EXPECT_EQ(weakPtr5.get(), weakPtr6.get());
+
+ WeakPtr<int> weakPtr7 = outerFactory.createWeakPtr();
+ EXPECT_EQ(weakPtr7.get(), &dummy2);
+ weakPtr7 = nullptr;
+ EXPECT_NULL(weakPtr7.get());
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/WorkQueue.cpp b/Tools/TestWebKitAPI/Tests/WTF/WorkQueue.cpp
new file mode 100644
index 000000000..7e277e94c
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/WorkQueue.cpp
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "Test.h"
+#include <wtf/Condition.h>
+#include <wtf/Lock.h>
+#include <wtf/Vector.h>
+#include <wtf/WorkQueue.h>
+#include <string>
+#include <thread>
+
+namespace TestWebKitAPI {
+
+static const char* simpleTestLabel = "simpleTest";
+static const char* longTestLabel = "longTest";
+static const char* thirdTestLabel = "thirdTest";
+static const char* dispatchAfterLabel = "dispatchAfter";
+
+TEST(WTF_WorkQueue, Simple)
+{
+ Lock m_lock;
+ Condition m_testCompleted;
+ Vector<std::string> m_functionCallOrder;
+
+ bool calledSimpleTest = false;
+ bool calledLongTest = false;
+ bool calledThirdTest = false;
+
+ static const char* simpleTestLabel = "simpleTest";
+ static const char* longTestLabel = "longTest";
+ static const char* thirdTestLabel = "thirdTest";
+
+ auto queue = WorkQueue::create("com.apple.WebKit.Test.simple");
+ int initialRefCount = queue->refCount();
+ EXPECT_EQ(1, initialRefCount);
+
+ LockHolder locker(m_lock);
+ queue->dispatch([&](void) {
+ m_functionCallOrder.append(simpleTestLabel);
+ calledSimpleTest = true;
+ });
+
+ queue->dispatch([&](void) {
+ m_functionCallOrder.append(longTestLabel);
+ std::this_thread::sleep_for(std::chrono::nanoseconds(100));
+ calledLongTest = true;
+ });
+
+ queue->dispatch([&](void) {
+ LockHolder locker(m_lock);
+ m_functionCallOrder.append(thirdTestLabel);
+ calledThirdTest = true;
+
+ EXPECT_TRUE(calledSimpleTest);
+ EXPECT_TRUE(calledLongTest);
+ EXPECT_TRUE(calledThirdTest);
+
+ m_testCompleted.notifyOne();
+ });
+
+ EXPECT_GT(queue->refCount(), 1);
+
+ m_testCompleted.wait(m_lock);
+
+ EXPECT_TRUE(calledSimpleTest);
+ EXPECT_TRUE(calledLongTest);
+ EXPECT_TRUE(calledThirdTest);
+
+ EXPECT_EQ(static_cast<size_t>(3), m_functionCallOrder.size());
+ EXPECT_STREQ(simpleTestLabel, m_functionCallOrder[0].c_str());
+ EXPECT_STREQ(longTestLabel, m_functionCallOrder[1].c_str());
+ EXPECT_STREQ(thirdTestLabel, m_functionCallOrder[2].c_str());
+}
+
+TEST(WTF_WorkQueue, TwoQueues)
+{
+ Lock m_lock;
+ Condition m_testQueue1Completed, m_testQueue2Completed;
+ Vector<std::string> m_functionCallOrder;
+
+ bool calledSimpleTest = false;
+ bool calledLongTest = false;
+ bool calledThirdTest = false;
+
+ auto queue1 = WorkQueue::create("com.apple.WebKit.Test.twoQueues1");
+ auto queue2 = WorkQueue::create("com.apple.WebKit.Test.twoQueues2");
+
+ EXPECT_EQ(1, queue1->refCount());
+ EXPECT_EQ(1, queue2->refCount());
+
+ LockHolder locker(m_lock);
+
+ queue1->dispatch([&](void) {
+ m_functionCallOrder.append(simpleTestLabel);
+ calledSimpleTest = true;
+ });
+
+ queue2->dispatch([&](void) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+
+ LockHolder locker(m_lock);
+
+ // Will fail if queue2 took the mutex before queue1.
+ EXPECT_TRUE(calledThirdTest);
+
+ m_functionCallOrder.append(longTestLabel);
+ calledLongTest = true;
+ m_testQueue2Completed.notifyOne();
+ });
+
+ queue1->dispatch([&](void) {
+ LockHolder locker(m_lock);
+ m_functionCallOrder.append(thirdTestLabel);
+ calledThirdTest = true;
+
+ m_testQueue1Completed.notifyOne();
+ });
+
+ m_testQueue1Completed.wait(m_lock);
+
+ EXPECT_TRUE(calledSimpleTest);
+ EXPECT_FALSE(calledLongTest);
+ EXPECT_TRUE(calledThirdTest);
+
+ m_testQueue2Completed.wait(m_lock);
+
+ EXPECT_TRUE(calledSimpleTest);
+ EXPECT_TRUE(calledLongTest);
+ EXPECT_TRUE(calledThirdTest);
+
+ EXPECT_EQ(static_cast<size_t>(3), m_functionCallOrder.size());
+ EXPECT_STREQ(simpleTestLabel, m_functionCallOrder[0].c_str());
+ EXPECT_STREQ(thirdTestLabel, m_functionCallOrder[1].c_str());
+ EXPECT_STREQ(longTestLabel, m_functionCallOrder[2].c_str());
+}
+
+TEST(WTF_WorkQueue, DispatchAfter)
+{
+ Lock m_lock;
+ Condition m_testCompleted, m_dispatchAfterTestCompleted;
+ Vector<std::string> m_functionCallOrder;
+
+ bool calledSimpleTest = false;
+ bool calledDispatchAfterTest = false;
+
+ auto queue = WorkQueue::create("com.apple.WebKit.Test.dispatchAfter");
+
+ LockHolder locker(m_lock);
+
+ queue->dispatch([&](void) {
+ LockHolder locker(m_lock);
+ m_functionCallOrder.append(simpleTestLabel);
+ calledSimpleTest = true;
+ m_testCompleted.notifyOne();
+ });
+
+ queue->dispatchAfter(std::chrono::milliseconds(500), [&](void) {
+ LockHolder locker(m_lock);
+ m_functionCallOrder.append(dispatchAfterLabel);
+ calledDispatchAfterTest = true;
+ m_dispatchAfterTestCompleted.notifyOne();
+ });
+
+ m_testCompleted.wait(m_lock);
+
+ EXPECT_TRUE(calledSimpleTest);
+ EXPECT_FALSE(calledDispatchAfterTest);
+
+ m_dispatchAfterTestCompleted.wait(m_lock);
+
+ EXPECT_TRUE(calledSimpleTest);
+ EXPECT_TRUE(calledDispatchAfterTest);
+
+ EXPECT_EQ(static_cast<size_t>(2), m_functionCallOrder.size());
+ EXPECT_STREQ(simpleTestLabel, m_functionCallOrder[0].c_str());
+ EXPECT_STREQ(dispatchAfterLabel, m_functionCallOrder[1].c_str());
+}
+
+TEST(WTF_WorkQueue, DestroyOnSelf)
+{
+ Lock lock;
+ Condition dispatchAfterTestStarted;
+ Condition dispatchAfterTestCompleted;
+ bool started = false;
+ bool completed = false;
+
+ {
+ LockHolder locker(lock);
+ {
+ auto queue = WorkQueue::create("com.apple.WebKit.Test.dispatchAfter");
+ queue->dispatchAfter(std::chrono::milliseconds(500), [&](void) {
+ LockHolder locker(lock);
+ dispatchAfterTestStarted.wait(lock, [&] {
+ return started;
+ });
+ completed = true;
+ dispatchAfterTestCompleted.notifyOne();
+ });
+ }
+ started = true;
+ dispatchAfterTestStarted.notifyOne();
+ }
+ {
+ LockHolder locker(lock);
+ dispatchAfterTestCompleted.wait(lock, [&] {
+ return completed;
+ });
+ WTF::sleep(0.1);
+ }
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/darwin/OSObjectPtr.cpp b/Tools/TestWebKitAPI/Tests/WTF/darwin/OSObjectPtr.cpp
new file mode 100644
index 000000000..5389dcbc8
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/darwin/OSObjectPtr.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <wtf/OSObjectPtr.h>
+
+#include <dispatch/dispatch.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+namespace TestWebKitAPI {
+
+TEST(OSObjectPtr, AdoptOSObject)
+{
+ OSObjectPtr<dispatch_queue_t> foo = adoptOSObject(dispatch_queue_create(0, DISPATCH_QUEUE_SERIAL));
+
+ EXPECT_EQ(1, CFGetRetainCount(foo.get()));
+}
+
+TEST(OSObjectPtr, RetainRelease)
+{
+ dispatch_queue_t foo = dispatch_queue_create(0, DISPATCH_QUEUE_SERIAL);
+ EXPECT_EQ(1, CFGetRetainCount(foo));
+
+ WTF::retainOSObject(foo);
+ EXPECT_EQ(2, CFGetRetainCount(foo));
+
+ WTF::releaseOSObject(foo);
+ EXPECT_EQ(1, CFGetRetainCount(foo));
+}
+
+TEST(OSObjectPtr, LeakRef)
+{
+ OSObjectPtr<dispatch_queue_t> foo = adoptOSObject(dispatch_queue_create(0, DISPATCH_QUEUE_SERIAL));
+ EXPECT_EQ(1, CFGetRetainCount(foo.get()));
+
+ dispatch_queue_t queue = foo.leakRef();
+ EXPECT_EQ(nullptr, foo.get());
+ EXPECT_EQ(1, CFGetRetainCount(queue));
+
+ WTF::releaseOSObject(queue);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/gobject/GUniquePtr.cpp b/Tools/TestWebKitAPI/Tests/WTF/glib/GUniquePtr.cpp
index 8942f8657..11f02c7b0 100644
--- a/Tools/TestWebKitAPI/Tests/WTF/gobject/GUniquePtr.cpp
+++ b/Tools/TestWebKitAPI/Tests/WTF/glib/GUniquePtr.cpp
@@ -80,7 +80,7 @@ static void (* _g_key_file_free)(GKeyFile*) = g_key_file_free;
log() << "g_key_file_free(" << ptr << ");"; \
_g_key_file_free(x);
-#include <wtf/gobject/GUniquePtr.h>
+#include <wtf/glib/GUniquePtr.h>
namespace TestWebKitAPI {
diff --git a/Tools/TestWebKitAPI/Tests/WTF/glib/WorkQueueGLib.cpp b/Tools/TestWebKitAPI/Tests/WTF/glib/WorkQueueGLib.cpp
new file mode 100644
index 000000000..9923d6580
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/glib/WorkQueueGLib.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "Test.h"
+#include <gio/gio.h>
+#include <thread>
+#include <wtf/Condition.h>
+#include <wtf/Lock.h>
+#include <wtf/WorkQueue.h>
+#include <wtf/glib/GRefPtr.h>
+#include <wtf/glib/GUniquePtr.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF_WorkQueue, AsyncIO)
+{
+ struct TestingContext {
+ Lock m_lock;
+ Condition m_testCompleted;
+ GMainContext* m_mainContext;
+ } context;
+
+ auto queue = WorkQueue::create("com.apple.WebKit.Test.AsyncIO");
+ context.m_mainContext = g_main_context_default();
+ EXPECT_FALSE(g_main_context_get_thread_default());
+
+ GUniquePtr<char> currentDirectory(g_get_current_dir());
+ GRefPtr<GFile> file = adoptGRef(g_file_new_for_path(currentDirectory.get()));
+
+ LockHolder locker(context.m_lock);
+ queue->dispatch([&](void) {
+ EXPECT_TRUE(g_main_context_get_thread_default());
+ EXPECT_TRUE(g_main_context_get_thread_default() != context.m_mainContext);
+ context.m_mainContext = g_main_context_get_thread_default();
+ g_file_query_info_async(file.get(), G_FILE_ATTRIBUTE_STANDARD_SIZE, G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT, nullptr,
+ [](GObject*, GAsyncResult*, gpointer userData) {
+ TestingContext* context = static_cast<TestingContext*>(userData);
+ LockHolder locker(context->m_lock);
+ EXPECT_EQ(g_main_context_get_thread_default(), context->m_mainContext);
+ context->m_testCompleted.notifyOne();
+ }, &context);
+ });
+
+ context.m_testCompleted.wait(context.m_lock);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/AffineTransform.cpp b/Tools/TestWebKitAPI/Tests/WebCore/AffineTransform.cpp
new file mode 100644
index 000000000..9bcd1a4de
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/AffineTransform.cpp
@@ -0,0 +1,1024 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <WebCore/AffineTransform.h>
+#include <WebCore/FloatPoint.h>
+#include <WebCore/FloatQuad.h>
+#include <WebCore/FloatRect.h>
+#include <WebCore/FloatSize.h>
+#include <WebCore/IntPoint.h>
+#include <WebCore/IntRect.h>
+#include <WebCore/IntSize.h>
+#include <WebCore/TransformationMatrix.h>
+
+#if USE(CG)
+#include <CoreGraphics/CoreGraphics.h>
+#endif
+
+#if PLATFORM(WIN)
+#include <d2d1.h>
+#endif
+
+namespace TestWebKitAPI {
+
+static void testGetAndSet(WebCore::AffineTransform& affineTransform)
+{
+ affineTransform.setA(1.1);
+ EXPECT_DOUBLE_EQ(1.1, affineTransform.a());
+ affineTransform.setB(2.2);
+ EXPECT_DOUBLE_EQ(2.2, affineTransform.b());
+ affineTransform.setC(3.3);
+ EXPECT_DOUBLE_EQ(3.3, affineTransform.c());
+ affineTransform.setD(4.4);
+ EXPECT_DOUBLE_EQ(4.4, affineTransform.d());
+ affineTransform.setE(5.5);
+ EXPECT_DOUBLE_EQ(5.5, affineTransform.e());
+ affineTransform.setF(6.6);
+ EXPECT_DOUBLE_EQ(6.6, affineTransform.f());
+}
+
+static void testIdentity(const WebCore::AffineTransform& transform)
+{
+ EXPECT_DOUBLE_EQ(1.0, transform.a());
+ EXPECT_DOUBLE_EQ(0.0, transform.b());
+ EXPECT_DOUBLE_EQ(0.0, transform.c());
+ EXPECT_DOUBLE_EQ(1.0, transform.d());
+ EXPECT_DOUBLE_EQ(0.0, transform.e());
+ EXPECT_DOUBLE_EQ(0.0, transform.f());
+}
+
+TEST(AffineTransform, DefaultConstruction)
+{
+ WebCore::AffineTransform test;
+
+ testIdentity(test);
+ testGetAndSet(test);
+
+ ASSERT_FALSE(test.isIdentity());
+}
+
+static void testValueConstruction(const WebCore::AffineTransform& transform)
+{
+ EXPECT_DOUBLE_EQ(6.0, transform.a());
+ EXPECT_DOUBLE_EQ(5.0, transform.b());
+ EXPECT_DOUBLE_EQ(4.0, transform.c());
+ EXPECT_DOUBLE_EQ(3.0, transform.d());
+ EXPECT_DOUBLE_EQ(2.0, transform.e());
+ EXPECT_DOUBLE_EQ(1.0, transform.f());
+}
+
+static void testDoubled(const WebCore::AffineTransform& transform)
+{
+ EXPECT_DOUBLE_EQ(12.0, transform.a());
+ EXPECT_DOUBLE_EQ(10.0, transform.b());
+ EXPECT_DOUBLE_EQ(8.0, transform.c());
+ EXPECT_DOUBLE_EQ(6.0, transform.d());
+ EXPECT_DOUBLE_EQ(2.0, transform.e());
+ EXPECT_DOUBLE_EQ(1.0, transform.f());
+}
+
+static void testHalved(const WebCore::AffineTransform& transform)
+{
+ EXPECT_DOUBLE_EQ(3.0, transform.a());
+ EXPECT_DOUBLE_EQ(2.5, transform.b());
+ EXPECT_DOUBLE_EQ(2.0, transform.c());
+ EXPECT_DOUBLE_EQ(1.5, transform.d());
+ EXPECT_DOUBLE_EQ(2.0, transform.e());
+ EXPECT_DOUBLE_EQ(1.0, transform.f());
+}
+
+TEST(AffineTransform, ValueConstruction)
+{
+ WebCore::AffineTransform test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ testValueConstruction(test);
+ testGetAndSet(test);
+
+ ASSERT_FALSE(test.isIdentity());
+ ASSERT_FALSE(test.preservesAxisAlignment());
+}
+
+#if USE(CG)
+TEST(AffineTransform, CGAffineTransformConstruction)
+{
+ CGAffineTransform cgTransform = CGAffineTransformMake(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+ WebCore::AffineTransform test(cgTransform);
+
+ testValueConstruction(test);
+ testGetAndSet(test);
+
+ ASSERT_FALSE(test.isIdentity());
+}
+#endif
+
+#if PLATFORM(WIN)
+TEST(AffineTransform, D2D1MatrixConstruction)
+{
+ D2D1_MATRIX_3X2_F d2dTransform = D2D1::Matrix3x2F(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+ WebCore::AffineTransform test(d2dTransform);
+
+ testValueConstruction(test);
+ testGetAndSet(test);
+
+ ASSERT_FALSE(test.isIdentity());
+}
+#endif
+
+TEST(AffineTransform, Identity)
+{
+ WebCore::AffineTransform test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ ASSERT_FALSE(test.isIdentity());
+ ASSERT_FALSE(test.isIdentityOrTranslation());
+ ASSERT_FALSE(test.isIdentityOrTranslationOrFlipped());
+ ASSERT_FALSE(test.preservesAxisAlignment());
+
+ test.makeIdentity();
+
+ ASSERT_TRUE(test.isIdentity());
+ ASSERT_TRUE(test.isIdentityOrTranslation());
+ ASSERT_TRUE(test.isIdentityOrTranslationOrFlipped());
+ ASSERT_TRUE(test.preservesAxisAlignment());
+
+ testIdentity(test);
+}
+
+TEST(AffineTransform, MapFloatPoint)
+{
+ WebCore::AffineTransform test;
+ WebCore::FloatPoint point(100.0f, 50.0f);
+
+ auto mappedPoint = test.mapPoint(point);
+
+ ASSERT_FLOAT_EQ(100.0f, mappedPoint.x());
+ ASSERT_FLOAT_EQ(50.0f, mappedPoint.y());
+
+ test.setD(2.0);
+
+ auto mappedPoint2 = test.mapPoint(point);
+
+ ASSERT_FLOAT_EQ(100.0f, mappedPoint2.x());
+ ASSERT_FLOAT_EQ(100.0f, mappedPoint2.y());
+
+ test.setA(0.5);
+
+ auto mappedPoint3 = test.mapPoint(point);
+
+ ASSERT_FLOAT_EQ(50.0f, mappedPoint3.x());
+ ASSERT_FLOAT_EQ(100.0f, mappedPoint3.y());
+}
+
+TEST(AffineTransform, MapIntPoint)
+{
+ WebCore::AffineTransform test;
+ WebCore::IntPoint point(100, 50);
+
+ auto mappedPoint = test.mapPoint(point);
+
+ ASSERT_EQ(100, mappedPoint.x());
+ ASSERT_EQ(50, mappedPoint.y());
+
+ test.setD(2.0);
+
+ auto mappedPoint2 = test.mapPoint(point);
+
+ ASSERT_EQ(100, mappedPoint2.x());
+ ASSERT_EQ(100, mappedPoint2.y());
+
+ test.setA(0.5);
+
+ auto mappedPoint3 = test.mapPoint(point);
+
+ ASSERT_EQ(50, mappedPoint3.x());
+ ASSERT_EQ(100, mappedPoint3.y());
+}
+
+TEST(AffineTransform, MapIntSize)
+{
+ WebCore::AffineTransform test;
+ WebCore::IntSize size(200, 300);
+
+ auto mappedSize = test.mapSize(size);
+
+ ASSERT_EQ(200, mappedSize.width());
+ ASSERT_EQ(300, mappedSize.height());
+
+ test.setD(2.0);
+
+ auto mappedSize2 = test.mapSize(size);
+
+ ASSERT_EQ(200, mappedSize2.width());
+ ASSERT_EQ(600, mappedSize2.height());
+
+ test.setA(0.5);
+
+ auto mappedSize3 = test.mapSize(size);
+
+ ASSERT_EQ(100, mappedSize3.width());
+ ASSERT_EQ(600, mappedSize3.height());
+}
+
+TEST(AffineTransform, MapFloatSize)
+{
+ WebCore::AffineTransform test;
+ WebCore::FloatSize size(200.0f, 300.0f);
+
+ auto mappedSize = test.mapSize(size);
+
+ ASSERT_EQ(200.0f, mappedSize.width());
+ ASSERT_EQ(300.0f, mappedSize.height());
+
+ test.setD(2.0);
+
+ auto mappedSize2 = test.mapSize(size);
+
+ ASSERT_EQ(200.0f, mappedSize2.width());
+ ASSERT_EQ(600.0f, mappedSize2.height());
+
+ test.setA(0.5);
+
+ auto mappedSize3 = test.mapSize(size);
+
+ ASSERT_EQ(100.0f, mappedSize3.width());
+ ASSERT_EQ(600.0f, mappedSize3.height());
+}
+
+TEST(AffineTransform, MapIntRect)
+{
+ WebCore::AffineTransform test;
+ WebCore::IntRect rect(10, 20, 200, 300);
+
+ auto mappedRect = test.mapRect(rect);
+
+ ASSERT_EQ(10, mappedRect.x());
+ ASSERT_EQ(20, mappedRect.y());
+ ASSERT_EQ(200, mappedRect.width());
+ ASSERT_EQ(300, mappedRect.height());
+
+ test.setD(2.0);
+
+ auto mappedRect2 = test.mapRect(rect);
+
+ ASSERT_EQ(10, mappedRect2.x());
+ ASSERT_EQ(40, mappedRect2.y());
+ ASSERT_EQ(200, mappedRect2.width());
+ ASSERT_EQ(600, mappedRect2.height());
+
+ test.setA(0.5);
+
+ auto mappedRect3 = test.mapRect(rect);
+
+ ASSERT_EQ(5, mappedRect3.x());
+ ASSERT_EQ(40, mappedRect3.y());
+ ASSERT_EQ(100, mappedRect3.width());
+ ASSERT_EQ(600, mappedRect3.height());
+}
+
+TEST(AffineTransform, MapFloatRect)
+{
+ WebCore::AffineTransform test;
+ WebCore::FloatRect rect(10.f, 20.0f, 200.0f, 300.0f);
+
+ auto mappedRect = test.mapRect(rect);
+
+ ASSERT_FLOAT_EQ(10.0f, mappedRect.x());
+ ASSERT_FLOAT_EQ(20.0f, mappedRect.y());
+ ASSERT_FLOAT_EQ(200.0f, mappedRect.width());
+ ASSERT_FLOAT_EQ(300.0f, mappedRect.height());
+
+ test.setD(2.0);
+
+ auto mappedRect2 = test.mapRect(rect);
+
+ ASSERT_FLOAT_EQ(10.0f, mappedRect2.x());
+ ASSERT_FLOAT_EQ(40.0f, mappedRect2.y());
+ ASSERT_FLOAT_EQ(200.0f, mappedRect2.width());
+ ASSERT_FLOAT_EQ(600.0f, mappedRect2.height());
+
+ test.setA(0.5);
+
+ auto mappedRect3 = test.mapRect(rect);
+
+ ASSERT_FLOAT_EQ(5.0f, mappedRect3.x());
+ ASSERT_FLOAT_EQ(40.0f, mappedRect3.y());
+ ASSERT_FLOAT_EQ(100.0f, mappedRect3.width());
+ ASSERT_FLOAT_EQ(600.0f, mappedRect3.height());
+}
+
+TEST(AffineTransform, MapFloatQuad)
+{
+ WebCore::FloatRect rect(100.0f, 100.0f, 100.0f, 50.0f);
+ WebCore::FloatQuad quad(rect);
+
+ ASSERT_FLOAT_EQ(100.0f, quad.p1().x());
+ ASSERT_FLOAT_EQ(100.0f, quad.p1().y());
+ ASSERT_FLOAT_EQ(200.0f, quad.p2().x());
+ ASSERT_FLOAT_EQ(100.0f, quad.p2().y());
+ ASSERT_FLOAT_EQ(200.0f, quad.p3().x());
+ ASSERT_FLOAT_EQ(150.0f, quad.p3().y());
+ ASSERT_FLOAT_EQ(100.0f, quad.p4().x());
+ ASSERT_FLOAT_EQ(150.0f, quad.p4().y());
+
+ WebCore::AffineTransform test;
+ auto mappedQuad = test.mapQuad(quad);
+
+ ASSERT_FLOAT_EQ(100.0f, mappedQuad.p1().x());
+ ASSERT_FLOAT_EQ(100.0f, mappedQuad.p1().y());
+ ASSERT_FLOAT_EQ(200.0f, mappedQuad.p2().x());
+ ASSERT_FLOAT_EQ(100.0f, mappedQuad.p2().y());
+ ASSERT_FLOAT_EQ(200.0f, mappedQuad.p3().x());
+ ASSERT_FLOAT_EQ(150.0f, mappedQuad.p3().y());
+ ASSERT_FLOAT_EQ(100.0f, mappedQuad.p4().x());
+ ASSERT_FLOAT_EQ(150.0f, mappedQuad.p4().y());
+
+ test.setD(2.0);
+
+ auto mappedQuad2 = test.mapQuad(quad);
+
+ ASSERT_FLOAT_EQ(100.0f, mappedQuad2.p1().x());
+ ASSERT_FLOAT_EQ(200.0f, mappedQuad2.p1().y());
+ ASSERT_FLOAT_EQ(200.0f, mappedQuad2.p2().x());
+ ASSERT_FLOAT_EQ(200.0f, mappedQuad2.p2().y());
+ ASSERT_FLOAT_EQ(200.0f, mappedQuad2.p3().x());
+ ASSERT_FLOAT_EQ(300.0f, mappedQuad2.p3().y());
+ ASSERT_FLOAT_EQ(100.0f, mappedQuad2.p4().x());
+ ASSERT_FLOAT_EQ(300.0f, mappedQuad2.p4().y());
+
+ test.setA(0.5);
+
+ auto mappedQuad3 = test.mapQuad(quad);
+
+ ASSERT_FLOAT_EQ(50.0f, mappedQuad3.p1().x());
+ ASSERT_FLOAT_EQ(200.0f, mappedQuad3.p1().y());
+ ASSERT_FLOAT_EQ(100.0f, mappedQuad3.p2().x());
+ ASSERT_FLOAT_EQ(200.0f, mappedQuad3.p2().y());
+ ASSERT_FLOAT_EQ(100.0f, mappedQuad3.p3().x());
+ ASSERT_FLOAT_EQ(300.0f, mappedQuad3.p3().y());
+ ASSERT_FLOAT_EQ(50.0f, mappedQuad3.p4().x());
+ ASSERT_FLOAT_EQ(300.0f, mappedQuad3.p4().y());
+}
+
+TEST(AffineTransform, Multiply)
+{
+ WebCore::AffineTransform test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+ WebCore::AffineTransform identity;
+
+ testValueConstruction(test);
+
+ test.multiply(identity);
+
+ testValueConstruction(test);
+
+ WebCore::AffineTransform doubler(2.0, 0.0, 0.0, 2.0, 0.0, 0.0);
+
+ test.multiply(doubler);
+
+ testDoubled(test);
+
+ WebCore::AffineTransform halver(0.5, 0.0, 0.0, 0.5, 0.0, 0.0);
+
+ test.multiply(halver);
+
+ testValueConstruction(test);
+
+ test.multiply(halver);
+
+ testHalved(test);
+}
+
+TEST(AffineTransform, Scale)
+{
+ WebCore::AffineTransform test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ testValueConstruction(test);
+
+ test.scale(1.0);
+
+ testValueConstruction(test);
+
+ test.scale(2.0);
+
+ testDoubled(test);
+
+ test.scale(0.5);
+
+ testValueConstruction(test);
+
+ test.scale(0.5);
+
+ testHalved(test);
+}
+
+TEST(AffineTransform, ScaleUniformNonUniform)
+{
+ WebCore::AffineTransform test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ testValueConstruction(test);
+
+ test.scaleNonUniform(1.0, 1.0);
+
+ testValueConstruction(test);
+
+ test.scaleNonUniform(2.0, 2.0);
+
+ testDoubled(test);
+
+ test.scaleNonUniform(0.5, 0.5);
+
+ testValueConstruction(test);
+
+ test.scaleNonUniform(0.5, 0.5);
+
+ testHalved(test);
+}
+
+TEST(AffineTransform, ScaleNonUniform)
+{
+ WebCore::AffineTransform test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ testValueConstruction(test);
+
+ test.scaleNonUniform(1.0, 2.0);
+
+ EXPECT_DOUBLE_EQ(6.0, test.a());
+ EXPECT_DOUBLE_EQ(5.0, test.b());
+ EXPECT_DOUBLE_EQ(8.0, test.c());
+ EXPECT_DOUBLE_EQ(6.0, test.d());
+ EXPECT_DOUBLE_EQ(2.0, test.e());
+ EXPECT_DOUBLE_EQ(1.0, test.f());
+
+ test.scaleNonUniform(1.0, 0.5);
+
+ testValueConstruction(test);
+
+ test.scaleNonUniform(2.0, 1.0);
+
+ EXPECT_DOUBLE_EQ(12.0, test.a());
+ EXPECT_DOUBLE_EQ(10.0, test.b());
+ EXPECT_DOUBLE_EQ(4.0, test.c());
+ EXPECT_DOUBLE_EQ(3.0, test.d());
+ EXPECT_DOUBLE_EQ(2.0, test.e());
+ EXPECT_DOUBLE_EQ(1.0, test.f());
+
+ test.scaleNonUniform(0.5, 1.0);
+
+ testValueConstruction(test);
+
+ test.scaleNonUniform(0.5, 2.0);
+
+ EXPECT_DOUBLE_EQ(3.0, test.a());
+ EXPECT_DOUBLE_EQ(2.5, test.b());
+ EXPECT_DOUBLE_EQ(8.0, test.c());
+ EXPECT_DOUBLE_EQ(6.0, test.d());
+ EXPECT_DOUBLE_EQ(2.0, test.e());
+ EXPECT_DOUBLE_EQ(1.0, test.f());
+}
+
+TEST(AffineTransform, ScaleFloatSize)
+{
+ WebCore::AffineTransform test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ testValueConstruction(test);
+
+ WebCore::FloatSize first(1.0f, 2.0f);
+
+ test.scale(first);
+
+ EXPECT_DOUBLE_EQ(6.0, test.a());
+ EXPECT_DOUBLE_EQ(5.0, test.b());
+ EXPECT_DOUBLE_EQ(8.0, test.c());
+ EXPECT_DOUBLE_EQ(6.0, test.d());
+ EXPECT_DOUBLE_EQ(2.0, test.e());
+ EXPECT_DOUBLE_EQ(1.0, test.f());
+
+ WebCore::FloatSize second(1.0f, 0.5f);
+
+ test.scale(second);
+
+ testValueConstruction(test);
+
+ WebCore::FloatSize third(2.0f, 1.0f);
+
+ test.scale(third);
+
+ EXPECT_DOUBLE_EQ(12.0, test.a());
+ EXPECT_DOUBLE_EQ(10.0, test.b());
+ EXPECT_DOUBLE_EQ(4.0, test.c());
+ EXPECT_DOUBLE_EQ(3.0, test.d());
+ EXPECT_DOUBLE_EQ(2.0, test.e());
+ EXPECT_DOUBLE_EQ(1.0, test.f());
+
+ WebCore::FloatSize fourth(0.5f, 1.0f);
+
+ test.scale(fourth);
+
+ testValueConstruction(test);
+
+ WebCore::FloatSize fifth(0.5f, 2.0f);
+
+ test.scale(fifth);
+
+ EXPECT_DOUBLE_EQ(3.0, test.a());
+ EXPECT_DOUBLE_EQ(2.5, test.b());
+ EXPECT_DOUBLE_EQ(8.0, test.c());
+ EXPECT_DOUBLE_EQ(6.0, test.d());
+ EXPECT_DOUBLE_EQ(2.0, test.e());
+ EXPECT_DOUBLE_EQ(1.0, test.f());
+}
+
+TEST(AffineTransform, Rotate)
+{
+ WebCore::AffineTransform test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ test.rotate(360.0);
+
+ testValueConstruction(test);
+
+ test.rotate(180.0);
+
+ static double epsilon = 0.0001;
+
+ EXPECT_NEAR(-6.0, test.a(), epsilon);
+ EXPECT_NEAR(-5.0, test.b(), epsilon);
+ EXPECT_NEAR(-4.0, test.c(), epsilon);
+ EXPECT_NEAR(-3.0, test.d(), epsilon);
+ EXPECT_DOUBLE_EQ(2.0, test.e());
+ EXPECT_DOUBLE_EQ(1.0, test.f());
+
+ test.rotate(-180.0);
+
+ testValueConstruction(test);
+
+ test.rotate(90.0);
+
+ EXPECT_NEAR(4.0, test.a(), epsilon);
+ EXPECT_NEAR(3.0, test.b(), epsilon);
+ EXPECT_NEAR(-6.0, test.c(), epsilon);
+ EXPECT_NEAR(-5.0, test.d(), epsilon);
+ EXPECT_DOUBLE_EQ(2.0, test.e());
+ EXPECT_DOUBLE_EQ(1.0, test.f());
+
+ test.rotate(-90.0);
+
+ testValueConstruction(test);
+}
+
+TEST(AffineTransform, TranslateXY)
+{
+ WebCore::AffineTransform test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ test.translate(0.0, 0.0);
+
+ testValueConstruction(test);
+
+ test.translate(5.0, 0.0);
+
+ EXPECT_DOUBLE_EQ(6.0, test.a());
+ EXPECT_DOUBLE_EQ(5.0, test.b());
+ EXPECT_DOUBLE_EQ(4.0, test.c());
+ EXPECT_DOUBLE_EQ(3.0, test.d());
+ EXPECT_DOUBLE_EQ(32.0, test.e());
+ EXPECT_DOUBLE_EQ(26.0, test.f());
+
+ test.translate(0.0, -1.2);
+
+ EXPECT_DOUBLE_EQ(6.0, test.a());
+ EXPECT_DOUBLE_EQ(5.0, test.b());
+ EXPECT_DOUBLE_EQ(4.0, test.c());
+ EXPECT_DOUBLE_EQ(3.0, test.d());
+ EXPECT_DOUBLE_EQ(27.2, test.e());
+ EXPECT_DOUBLE_EQ(22.4, test.f());
+}
+
+TEST(AffineTransform, TranslateFloatPoint)
+{
+ WebCore::AffineTransform test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ WebCore::FloatPoint none;
+ test.translate(none);
+
+ testValueConstruction(test);
+
+ WebCore::FloatPoint first(5.0f, 0.0f);
+
+ test.translate(first);
+
+ EXPECT_DOUBLE_EQ(6.0, test.a());
+ EXPECT_DOUBLE_EQ(5.0, test.b());
+ EXPECT_DOUBLE_EQ(4.0, test.c());
+ EXPECT_DOUBLE_EQ(3.0, test.d());
+ EXPECT_DOUBLE_EQ(32.0, test.e());
+ EXPECT_DOUBLE_EQ(26.0, test.f());
+
+ WebCore::FloatPoint second(0.0f, -1.2f);
+
+ test.translate(second);
+
+ static double epsilon = 0.0001;
+
+ EXPECT_DOUBLE_EQ(6.0, test.a());
+ EXPECT_DOUBLE_EQ(5.0, test.b());
+ EXPECT_DOUBLE_EQ(4.0, test.c());
+ EXPECT_DOUBLE_EQ(3.0, test.d());
+ EXPECT_NEAR(27.2, test.e(), epsilon);
+ EXPECT_NEAR(22.4, test.f(), epsilon);
+
+ WebCore::AffineTransform test2;
+
+ ASSERT_TRUE(test2.isIdentity());
+ ASSERT_TRUE(test2.isIdentityOrTranslation());
+ ASSERT_TRUE(test2.isIdentityOrTranslationOrFlipped());
+
+ test2.translate(second);
+
+ ASSERT_FALSE(test2.isIdentity());
+ ASSERT_TRUE(test2.isIdentityOrTranslation());
+ ASSERT_TRUE(test2.isIdentityOrTranslationOrFlipped());
+}
+
+TEST(AffineTransform, Shear)
+{
+ WebCore::AffineTransform test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ test.shear(0.0, 0.0);
+
+ testValueConstruction(test);
+
+ test.shear(2.0, 2.0);
+
+ EXPECT_DOUBLE_EQ(14.0, test.a());
+ EXPECT_DOUBLE_EQ(11.0, test.b());
+ EXPECT_DOUBLE_EQ(16.0, test.c());
+ EXPECT_DOUBLE_EQ(13.0, test.d());
+ EXPECT_DOUBLE_EQ(2.0, test.e());
+ EXPECT_DOUBLE_EQ(1.0, test.f());
+
+ test.shear(-1.0, 2.0);
+
+ EXPECT_DOUBLE_EQ(46.0, test.a());
+ EXPECT_DOUBLE_EQ(37.0, test.b());
+ EXPECT_DOUBLE_EQ(2.0, test.c());
+ EXPECT_DOUBLE_EQ(2.0, test.d());
+ EXPECT_DOUBLE_EQ(2.0, test.e());
+ EXPECT_DOUBLE_EQ(1.0, test.f());
+}
+
+TEST(AffineTransform, FlipX)
+{
+ WebCore::AffineTransform test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ testValueConstruction(test);
+
+ test.flipX();
+
+ EXPECT_DOUBLE_EQ(-6.0, test.a());
+ EXPECT_DOUBLE_EQ(-5.0, test.b());
+ EXPECT_DOUBLE_EQ(4.0, test.c());
+ EXPECT_DOUBLE_EQ(3.0, test.d());
+ EXPECT_DOUBLE_EQ(2.0, test.e());
+ EXPECT_DOUBLE_EQ(1.0, test.f());
+
+ test.flipX();
+
+ testValueConstruction(test);
+
+ WebCore::AffineTransform test2;
+
+ testIdentity(test2);
+
+ ASSERT_TRUE(test2.isIdentity());
+ ASSERT_TRUE(test2.isIdentityOrTranslation());
+ ASSERT_TRUE(test2.isIdentityOrTranslationOrFlipped());
+
+ test2.flipX();
+
+ EXPECT_DOUBLE_EQ(-1.0, test2.a());
+ EXPECT_DOUBLE_EQ(0.0, test2.b());
+ EXPECT_DOUBLE_EQ(0.0, test2.c());
+ EXPECT_DOUBLE_EQ(1.0, test2.d());
+ EXPECT_DOUBLE_EQ(0.0, test2.e());
+ EXPECT_DOUBLE_EQ(0.0, test2.f());
+
+ ASSERT_FALSE(test2.isIdentity());
+ ASSERT_FALSE(test2.isIdentityOrTranslation());
+ // 'Flipped' just means in the Y direction
+ ASSERT_FALSE(test2.isIdentityOrTranslationOrFlipped());
+
+ test2.flipX();
+
+ ASSERT_TRUE(test2.isIdentity());
+ ASSERT_TRUE(test2.isIdentityOrTranslation());
+ ASSERT_TRUE(test2.isIdentityOrTranslationOrFlipped());
+}
+
+TEST(AffineTransform, FlipY)
+{
+ WebCore::AffineTransform test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ testValueConstruction(test);
+
+ test.flipY();
+
+ EXPECT_DOUBLE_EQ(6.0, test.a());
+ EXPECT_DOUBLE_EQ(5.0, test.b());
+ EXPECT_DOUBLE_EQ(-4.0, test.c());
+ EXPECT_DOUBLE_EQ(-3.0, test.d());
+ EXPECT_DOUBLE_EQ(2.0, test.e());
+ EXPECT_DOUBLE_EQ(1.0, test.f());
+
+ test.flipY();
+
+ testValueConstruction(test);
+
+ WebCore::AffineTransform test2;
+
+ testIdentity(test2);
+
+ ASSERT_TRUE(test2.isIdentity());
+ ASSERT_TRUE(test2.isIdentityOrTranslation());
+ ASSERT_TRUE(test2.isIdentityOrTranslationOrFlipped());
+
+ test2.flipY();
+
+ EXPECT_DOUBLE_EQ(1.0, test2.a());
+ EXPECT_DOUBLE_EQ(0.0, test2.b());
+ EXPECT_DOUBLE_EQ(0.0, test2.c());
+ EXPECT_DOUBLE_EQ(-1.0, test2.d());
+ EXPECT_DOUBLE_EQ(0.0, test2.e());
+ EXPECT_DOUBLE_EQ(0.0, test2.f());
+
+ ASSERT_FALSE(test2.isIdentity());
+ ASSERT_FALSE(test2.isIdentityOrTranslation());
+ ASSERT_TRUE(test2.isIdentityOrTranslationOrFlipped());
+
+ test2.flipY();
+
+ ASSERT_TRUE(test2.isIdentity());
+ ASSERT_TRUE(test2.isIdentityOrTranslation());
+ ASSERT_TRUE(test2.isIdentityOrTranslationOrFlipped());
+}
+
+TEST(AffineTransform, FlipXandFlipY)
+{
+ WebCore::AffineTransform test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ testValueConstruction(test);
+
+ test.flipX();
+
+ EXPECT_DOUBLE_EQ(-6.0, test.a());
+ EXPECT_DOUBLE_EQ(-5.0, test.b());
+ EXPECT_DOUBLE_EQ(4.0, test.c());
+ EXPECT_DOUBLE_EQ(3.0, test.d());
+ EXPECT_DOUBLE_EQ(2.0, test.e());
+ EXPECT_DOUBLE_EQ(1.0, test.f());
+
+ test.flipY();
+
+ EXPECT_DOUBLE_EQ(-6.0, test.a());
+ EXPECT_DOUBLE_EQ(-5.0, test.b());
+ EXPECT_DOUBLE_EQ(-4.0, test.c());
+ EXPECT_DOUBLE_EQ(-3.0, test.d());
+ EXPECT_DOUBLE_EQ(2.0, test.e());
+ EXPECT_DOUBLE_EQ(1.0, test.f());
+
+ test.flipX();
+
+ EXPECT_DOUBLE_EQ(6.0, test.a());
+ EXPECT_DOUBLE_EQ(5.0, test.b());
+ EXPECT_DOUBLE_EQ(-4.0, test.c());
+ EXPECT_DOUBLE_EQ(-3.0, test.d());
+ EXPECT_DOUBLE_EQ(2.0, test.e());
+ EXPECT_DOUBLE_EQ(1.0, test.f());
+
+ test.flipY();
+
+ testValueConstruction(test);
+
+ WebCore::AffineTransform test2;
+
+ ASSERT_TRUE(test2.isIdentity());
+ ASSERT_TRUE(test2.isIdentityOrTranslation());
+ ASSERT_TRUE(test2.isIdentityOrTranslationOrFlipped());
+
+ test2.flipX();
+
+ ASSERT_FALSE(test2.isIdentity());
+ ASSERT_FALSE(test2.isIdentityOrTranslation());
+ ASSERT_FALSE(test2.isIdentityOrTranslationOrFlipped());
+
+ test2.flipY();
+
+ ASSERT_FALSE(test2.isIdentity());
+ ASSERT_FALSE(test2.isIdentityOrTranslation());
+ // False here because X is also flipped.
+ ASSERT_FALSE(test2.isIdentityOrTranslationOrFlipped());
+
+ test2.flipX();
+
+ ASSERT_FALSE(test2.isIdentity());
+ ASSERT_FALSE(test2.isIdentityOrTranslation());
+ ASSERT_TRUE(test2.isIdentityOrTranslationOrFlipped());
+
+ test2.flipY();
+
+ ASSERT_TRUE(test2.isIdentity());
+ ASSERT_TRUE(test2.isIdentityOrTranslation());
+ ASSERT_TRUE(test2.isIdentityOrTranslationOrFlipped());
+}
+
+TEST(AffineTransform, Skew)
+{
+ WebCore::AffineTransform test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ testValueConstruction(test);
+
+ test.skew(360.0, 360.0);
+
+ testValueConstruction(test);
+
+ test.skew(0.0, 0.0);
+
+ testValueConstruction(test);
+
+ test.skew(180.0, 180.0);
+
+ static double epsilon = 0.0001;
+
+ EXPECT_DOUBLE_EQ(6.0, test.a());
+ EXPECT_DOUBLE_EQ(5.0, test.b());
+ EXPECT_NEAR(4.0, test.c(), epsilon);
+ EXPECT_DOUBLE_EQ(3.0, test.d());
+ EXPECT_DOUBLE_EQ(2.0, test.e());
+ EXPECT_DOUBLE_EQ(1.0, test.f());
+
+ test.skew(-180.0, -180.0);
+
+ testValueConstruction(test);
+}
+
+TEST(AffineTransform, XandYScale)
+{
+ WebCore::AffineTransform test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ EXPECT_NEAR(7.8102, test.xScale(), 0.0001);
+ EXPECT_NEAR(5.0, test.yScale(), 0.0001);
+}
+
+TEST(AffineTransform, Equality)
+{
+ WebCore::AffineTransform test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+ WebCore::AffineTransform test2;
+
+ ASSERT_FALSE(test == test2);
+ ASSERT_TRUE(test != test2);
+
+ test.makeIdentity();
+
+ ASSERT_TRUE(test == test2);
+ ASSERT_FALSE(test != test2);
+}
+
+TEST(AffineTransform, Inverse)
+{
+ WebCore::AffineTransform test;
+
+ auto inverse = test.inverse();
+
+ ASSERT(inverse);
+
+ EXPECT_DOUBLE_EQ(1.0, inverse->a());
+ EXPECT_DOUBLE_EQ(0.0, inverse->b());
+ EXPECT_DOUBLE_EQ(0.0, inverse->c());
+ EXPECT_DOUBLE_EQ(1.0, inverse->d());
+ EXPECT_DOUBLE_EQ(0.0, inverse->e());
+ EXPECT_DOUBLE_EQ(0.0, inverse->f());
+
+ auto test2 = test * inverse.value();
+
+ testIdentity(test2);
+}
+
+TEST(AffineTransform, Blend)
+{
+ WebCore::AffineTransform test;
+
+ WebCore::AffineTransform test2;
+ test2.scale(2.0);
+
+ test.blend(test2, 50);
+
+ EXPECT_DOUBLE_EQ(-48.0, test.a());
+ EXPECT_DOUBLE_EQ(0.0, test.b());
+ EXPECT_DOUBLE_EQ(0.0, test.c());
+ EXPECT_DOUBLE_EQ(-48.0, test.d());
+ EXPECT_DOUBLE_EQ(0.0, test.e());
+ EXPECT_DOUBLE_EQ(0.0, test.f());
+}
+
+TEST(AffineTransform, Translation)
+{
+ auto test = WebCore::AffineTransform::translation(-5.0, -7.0);
+ EXPECT_DOUBLE_EQ(1.0, test.a());
+ EXPECT_DOUBLE_EQ(0.0, test.b());
+ EXPECT_DOUBLE_EQ(0.0, test.c());
+ EXPECT_DOUBLE_EQ(1.0, test.d());
+ EXPECT_DOUBLE_EQ(-5.0, test.e());
+ EXPECT_DOUBLE_EQ(-7.0, test.f());
+}
+
+TEST(AffineTransform, ToTransformationMatrix)
+{
+ WebCore::AffineTransform transform;
+ WebCore::TransformationMatrix matrix = transform.toTransformationMatrix();
+
+ EXPECT_DOUBLE_EQ(1.0, matrix.m11());
+ EXPECT_DOUBLE_EQ(0.0, matrix.m12());
+ EXPECT_DOUBLE_EQ(0.0, matrix.m13());
+ EXPECT_DOUBLE_EQ(0.0, matrix.m14());
+ EXPECT_DOUBLE_EQ(0.0, matrix.m21());
+ EXPECT_DOUBLE_EQ(1.0, matrix.m22());
+ EXPECT_DOUBLE_EQ(0.0, matrix.m23());
+ EXPECT_DOUBLE_EQ(0.0, matrix.m24());
+ EXPECT_DOUBLE_EQ(0.0, matrix.m31());
+ EXPECT_DOUBLE_EQ(0.0, matrix.m32());
+ EXPECT_DOUBLE_EQ(1.0, matrix.m33());
+ EXPECT_DOUBLE_EQ(0.0, matrix.m34());
+}
+
+TEST(AffineTransform, MakeMapBetweenRects)
+{
+ WebCore::AffineTransform transform;
+
+ WebCore::FloatRect fromRect(10.0f, 10.0f, 100.0f, 100.0f);
+ WebCore::FloatRect toRect(70.0f, 70.0f, 200.0f, 50.0f);
+
+ auto mapBetween = WebCore::makeMapBetweenRects(fromRect, toRect);
+
+ EXPECT_DOUBLE_EQ(2.0, mapBetween.a());
+ EXPECT_DOUBLE_EQ(0.0, mapBetween.b());
+ EXPECT_DOUBLE_EQ(0.0, mapBetween.c());
+ EXPECT_DOUBLE_EQ(0.5, mapBetween.d());
+ EXPECT_DOUBLE_EQ(60.0, mapBetween.e());
+ EXPECT_DOUBLE_EQ(60.0, mapBetween.f());
+}
+
+#if USE(CG)
+TEST(AffineTransform, CoreGraphicsCasting)
+{
+ WebCore::AffineTransform test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ CGAffineTransform test2 = CGAffineTransformMake(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ ASSERT_TRUE(CGAffineTransformEqualToTransform(test, test2));
+
+ WebCore::AffineTransform test3;
+
+ ASSERT_FALSE(CGAffineTransformEqualToTransform(test, test3));
+}
+#endif
+
+#if PLATFORM(WIN)
+TEST(AffineTransform, Direct2DCasting)
+{
+ WebCore::AffineTransform transform(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ D2D1_MATRIX_3X2_F test = transform;
+ D2D1_MATRIX_3X2_F test2 = D2D1::Matrix3x2F(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ static const double epsilon = 0.0000001;
+
+ EXPECT_NEAR(test._11, test2._11, epsilon);
+ EXPECT_NEAR(test._12, test2._12, epsilon);
+ EXPECT_NEAR(test._21, test2._21, epsilon);
+ EXPECT_NEAR(test._22, test2._22, epsilon);
+ EXPECT_NEAR(test._31, test2._31, epsilon);
+ EXPECT_NEAR(test._32, test2._32, epsilon);
+}
+#endif
+
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/CARingBuffer.cpp b/Tools/TestWebKitAPI/Tests/WebCore/CARingBuffer.cpp
new file mode 100644
index 000000000..2aab65dd8
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/CARingBuffer.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if PLATFORM(MAC)
+
+#include "Test.h"
+#include <WebCore/CARingBuffer.h>
+#include <wtf/MainThread.h>
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+class CARingBufferTest : public testing::Test {
+public:
+
+ virtual void SetUp()
+ {
+ WTF::initializeMainThread();
+ m_ringBuffer = std::make_unique<CARingBuffer>();
+ }
+
+ // CAAudioStreamDescription(double sampleRate, UInt32 numChannels, PCMFormat format, bool isInterleaved, size_t capacity)
+ void setup(double sampleRate, UInt32 numChannels, CAAudioStreamDescription::PCMFormat format, bool isInterleaved, size_t capacity)
+ {
+ m_description = CAAudioStreamDescription(sampleRate, numChannels, format, isInterleaved);
+ m_capacity = capacity;
+ size_t listSize = offsetof(AudioBufferList, mBuffers) + (sizeof(AudioBuffer) * std::max<uint32_t>(1, m_description.numberOfChannelStreams()));
+ m_bufferList = std::unique_ptr<AudioBufferList>(static_cast<AudioBufferList*>(::operator new (listSize)));
+ m_ringBuffer->allocate(m_description, capacity);
+ }
+
+ void setListDataBuffer(uint8_t* bufferData, size_t sampleCount)
+ {
+ size_t bufferCount = m_description.numberOfChannelStreams();
+ size_t channelCount = m_description.numberOfInterleavedChannels();
+ size_t bytesPerChannel = sampleCount * m_description.bytesPerFrame();
+
+ m_bufferList->mNumberBuffers = bufferCount;
+ for (unsigned i = 0; i < bufferCount; ++i) {
+ m_bufferList->mBuffers[i].mNumberChannels = channelCount;
+ m_bufferList->mBuffers[i].mDataByteSize = bytesPerChannel;
+ m_bufferList->mBuffers[i].mData = bufferData;
+ if (bufferData)
+ bufferData = bufferData + bytesPerChannel;
+ }
+ }
+
+ const CAAudioStreamDescription& description() const { return m_description; }
+ AudioBufferList& bufferList() const { return *m_bufferList.get(); }
+ CARingBuffer& ringBuffer() const { return *m_ringBuffer.get(); }
+ size_t capacity() const { return m_capacity; }
+
+private:
+ size_t audioBufferListSizeForStream(const CAAudioStreamDescription& format)
+ {
+ return offsetof(AudioBufferList, mBuffers) + (sizeof(AudioBuffer) * std::max<uint32_t>(1, format.numberOfChannelStreams()));
+ }
+
+ void configureBufferListForStream(AudioBufferList& bufferList, const CAAudioStreamDescription& format, uint8_t* bufferData, size_t sampleCount)
+ {
+ size_t bufferCount = format.numberOfChannelStreams();
+ size_t channelCount = format.numberOfInterleavedChannels();
+ size_t bytesPerChannel = sampleCount * format.bytesPerFrame();
+
+ bufferList.mNumberBuffers = bufferCount;
+ for (unsigned i = 0; i < bufferCount; ++i) {
+ bufferList.mBuffers[i].mNumberChannels = channelCount;
+ bufferList.mBuffers[i].mDataByteSize = bytesPerChannel;
+ bufferList.mBuffers[i].mData = bufferData;
+ if (bufferData)
+ bufferData = bufferData + bytesPerChannel;
+ }
+ }
+
+ std::unique_ptr<AudioBufferList> m_bufferList;
+ std::unique_ptr<CARingBuffer> m_ringBuffer;
+ CAAudioStreamDescription m_description = { };
+ size_t m_capacity = { 0 };
+};
+
+TEST_F(CARingBufferTest, Basics)
+{
+ const int capacity = 32;
+
+ setup(44100, 1, CAAudioStreamDescription::PCMFormat::Float32, true, capacity);
+
+ float sourceBuffer[capacity];
+ for (int i = 0; i < capacity; i++)
+ sourceBuffer[i] = i + 0.5;
+
+ setListDataBuffer(reinterpret_cast<uint8_t*>(sourceBuffer), capacity);
+
+ // Fill the first half of the buffer ...
+ int sampleCount = capacity / 2;
+ CARingBuffer::Error err = ringBuffer().store(&bufferList(), sampleCount, 0);
+ EXPECT_EQ(err, CARingBuffer::Error::Ok);
+
+ uint64_t startTime;
+ uint64_t endTime;
+ ringBuffer().getCurrentFrameBounds(startTime, endTime);
+ EXPECT_EQ(0, (int)startTime);
+ EXPECT_EQ((int)sampleCount, (int)endTime);
+
+ float scratchBuffer[capacity];
+ setListDataBuffer(reinterpret_cast<uint8_t*>(scratchBuffer), capacity);
+
+ err = ringBuffer().fetch(&bufferList(), sampleCount, 0);
+ EXPECT_EQ(err, CARingBuffer::Error::Ok);
+ EXPECT_TRUE(!memcmp(sourceBuffer, scratchBuffer, sampleCount * description().sampleWordSize()));
+
+ // ... and the second half.
+ err = ringBuffer().store(&bufferList(), capacity / 2, capacity / 2);
+ EXPECT_EQ(err, CARingBuffer::Error::Ok);
+
+ ringBuffer().getCurrentFrameBounds(startTime, endTime);
+ EXPECT_EQ(0, (int)startTime);
+ EXPECT_EQ(capacity, (int)endTime);
+
+ memset(scratchBuffer, 0, sampleCount * description().sampleWordSize());
+ err = ringBuffer().fetch(&bufferList(), sampleCount, 0);
+ EXPECT_EQ(err, CARingBuffer::Error::Ok);
+ EXPECT_TRUE(!memcmp(sourceBuffer, scratchBuffer, sampleCount * description().sampleWordSize()));
+
+ // Force the buffer to wrap around
+ err = ringBuffer().store(&bufferList(), capacity, capacity - 1);
+ EXPECT_EQ(err, CARingBuffer::Error::Ok);
+
+ ringBuffer().getCurrentFrameBounds(startTime, endTime);
+ EXPECT_EQ((int)capacity - 1, (int)startTime);
+ EXPECT_EQ(capacity - 1 + capacity, (int)endTime);
+
+ // Make sure it returns an error when asked to store too much ...
+ err = ringBuffer().store(&bufferList(), capacity * 3, capacity / 2);
+ EXPECT_EQ(err, CARingBuffer::Error::TooMuch);
+
+ // ... and doesn't modify the buffer
+ ringBuffer().getCurrentFrameBounds(startTime, endTime);
+ EXPECT_EQ((int)capacity - 1, (int)startTime);
+ EXPECT_EQ(capacity - 1 + capacity, (int)endTime);
+
+ ringBuffer().flush();
+ ringBuffer().getCurrentFrameBounds(startTime, endTime);
+ EXPECT_EQ(0, (int)startTime);
+ EXPECT_EQ(0, (int)endTime);
+}
+
+template <typename type>
+class MixingTest {
+public:
+ static void run(CARingBufferTest& test)
+ {
+ const int sampleCount = 64;
+
+ CAAudioStreamDescription::PCMFormat format;
+ if (std::is_same<type, float>::value)
+ format = CAAudioStreamDescription::PCMFormat::Float32;
+ else if (std::is_same<type, double>::value)
+ format = CAAudioStreamDescription::PCMFormat::Float64;
+ else if (std::is_same<type, int32_t>::value)
+ format = CAAudioStreamDescription::PCMFormat::Int32;
+ else if (std::is_same<type, int16_t>::value)
+ format = CAAudioStreamDescription::PCMFormat::Int16;
+ else
+ ASSERT_NOT_REACHED();
+
+ test.setup(44100, 1, format, true, sampleCount);
+
+ type referenceBuffer[sampleCount];
+ type sourceBuffer[sampleCount];
+ type readBuffer[sampleCount];
+
+ for (int i = 0; i < sampleCount; i++) {
+ sourceBuffer[i] = i * 0.5;
+ referenceBuffer[i] = sourceBuffer[i];
+ }
+
+ test.setListDataBuffer(reinterpret_cast<uint8_t*>(sourceBuffer), sampleCount);
+ CARingBuffer::Error err = test.ringBuffer().store(&test.bufferList(), sampleCount, 0);
+ EXPECT_EQ(err, CARingBuffer::Error::Ok);
+
+ memset(readBuffer, 0, sampleCount * test.description().sampleWordSize());
+ test.setListDataBuffer(reinterpret_cast<uint8_t*>(readBuffer), sampleCount);
+ err = test.ringBuffer().fetch(&test.bufferList(), sampleCount, 0, CARingBuffer::FetchMode::Mix);
+ EXPECT_EQ(err, CARingBuffer::Error::Ok);
+
+ for (int i = 0; i < sampleCount; i++)
+ EXPECT_EQ(readBuffer[i], referenceBuffer[i]) << "Ring buffer value differs at index " << i;
+
+ err = test.ringBuffer().fetch(&test.bufferList(), sampleCount, 0, CARingBuffer::FetchMode::Mix);
+ EXPECT_EQ(err, CARingBuffer::Error::Ok);
+ err = test.ringBuffer().fetch(&test.bufferList(), sampleCount, 0, CARingBuffer::FetchMode::Mix);
+ EXPECT_EQ(err, CARingBuffer::Error::Ok);
+ err = test.ringBuffer().fetch(&test.bufferList(), sampleCount, 0, CARingBuffer::FetchMode::Mix);
+ EXPECT_EQ(err, CARingBuffer::Error::Ok);
+
+ for (int i = 0; i < sampleCount; i++)
+ referenceBuffer[i] += sourceBuffer[i] * 3;
+
+ for (int i = 0; i < sampleCount; i++)
+ EXPECT_EQ(readBuffer[i], referenceBuffer[i]) << "Ring buffer value differs at index " << i;
+ }
+};
+
+TEST_F(CARingBufferTest, FloatMixing)
+{
+ MixingTest<float>::run(*this);
+}
+
+TEST_F(CARingBufferTest, DoubleMixing)
+{
+ MixingTest<double>::run(*this);
+}
+
+TEST_F(CARingBufferTest, Int32Mixing)
+{
+ MixingTest<int32_t>::run(*this);
+}
+
+TEST_F(CARingBufferTest, Int16Mixing)
+{
+ MixingTest<int16_t>::run(*this);
+}
+
+}
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/CSSParser.cpp b/Tools/TestWebKitAPI/Tests/WebCore/CSSParser.cpp
new file mode 100644
index 000000000..edc7dcd91
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/CSSParser.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2014 Igalia, S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <WebCore/CSSParser.h>
+#include <WebCore/CSSValueList.h>
+#include <WebCore/StyleProperties.h>
+
+namespace TestWebKitAPI {
+
+using namespace WebCore;
+
+static unsigned computeNumberOfTracks(CSSValueList& valueList)
+{
+ unsigned numberOfTracks = 0;
+ for (const auto& value : valueList) {
+ if (value->isGridLineNamesValue())
+ continue;
+ ++numberOfTracks;
+ }
+ return numberOfTracks;
+}
+
+TEST(CSSPropertyParserTest, GridTrackLimits)
+{
+ struct {
+ const CSSPropertyID propertyID;
+ const char* input;
+ const size_t output;
+ } testCases[] = {
+ {CSSPropertyGridTemplateColumns, "grid-template-columns: repeat(999999, 20px);", 999999},
+ {CSSPropertyGridTemplateRows, "grid-template-rows: repeat(999999, 20px);", 999999},
+ {CSSPropertyGridTemplateColumns, "grid-template-columns: repeat(1000000, 10%);", 1000000},
+ {CSSPropertyGridTemplateRows, "grid-template-rows: repeat(1000000, 10%);", 1000000},
+ {CSSPropertyGridTemplateColumns, "grid-template-columns: repeat(1000000, [first] -webkit-min-content [last]);", 1000000},
+ {CSSPropertyGridTemplateRows, "grid-template-rows: repeat(1000000, [first] -webkit-min-content [last]);", 1000000},
+ {CSSPropertyGridTemplateColumns, "grid-template-columns: repeat(1000001, auto);", 1000000},
+ {CSSPropertyGridTemplateRows, "grid-template-rows: repeat(1000001, auto);", 1000000},
+ {CSSPropertyGridTemplateColumns, "grid-template-columns: repeat(400000, 2em minmax(10px, -webkit-max-content) 0.5fr);", 999999},
+ {CSSPropertyGridTemplateRows, "grid-template-rows: repeat(400000, 2em minmax(10px, -webkit-max-content) 0.5fr);", 999999},
+ {CSSPropertyGridTemplateColumns, "grid-template-columns: repeat(600000, [first] 3vh 10% 2fr [nav] 10px auto 1fr 6em [last]);", 999999},
+ {CSSPropertyGridTemplateRows, "grid-template-rows: repeat(600000, [first] 3vh 10% 2fr [nav] 10px auto 1fr 6em [last]);", 999999},
+ {CSSPropertyGridTemplateColumns, "grid-template-columns: repeat(100000000000000000000, 10% 1fr);", 1000000},
+ {CSSPropertyGridTemplateRows, "grid-template-rows: repeat(100000000000000000000, 10% 1fr);", 1000000},
+ {CSSPropertyGridTemplateColumns, "grid-template-columns: repeat(100000000000000000000, 10% 5em 1fr auto auto 15px -webkit-min-content);", 999999},
+ {CSSPropertyGridTemplateRows, "grid-template-rows: repeat(100000000000000000000, 10% 5em 1fr auto auto 15px -webkit-min-content);", 999999},
+ };
+
+ CSSParser parser(strictCSSParserContext());
+ auto properties = MutableStyleProperties::create();
+
+ for (auto& testCase : testCases) {
+ ASSERT_TRUE(parser.parseDeclaration(properties, testCase.input));
+ RefPtr<CSSValue> value = properties->getPropertyCSSValue(testCase.propertyID);
+
+ ASSERT_TRUE(value->isValueList());
+ EXPECT_EQ(computeNumberOfTracks(*downcast<CSSValueList>(value.get())), testCase.output);
+ }
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/CalculationValue.cpp b/Tools/TestWebKitAPI/Tests/WebCore/CalculationValue.cpp
new file mode 100644
index 000000000..07fbdce00
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/CalculationValue.cpp
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <WebCore/CalculationValue.h>
+
+namespace TestWebKitAPI {
+
+static unsigned deletionCount;
+
+class CalculationDeletionTestNode : public WebCore::CalcExpressionNode {
+public:
+ virtual ~CalculationDeletionTestNode()
+ {
+ ++deletionCount;
+ }
+
+ float evaluate(float) const override { return 0; }
+ bool operator==(const CalcExpressionNode&) const override { ASSERT_NOT_REACHED(); return false; }
+};
+
+static Ref<WebCore::CalculationValue> createTestValue()
+{
+ auto node = std::make_unique<CalculationDeletionTestNode>();
+ return WebCore::CalculationValue::create(WTFMove(node), WebCore::ValueRangeAll);
+}
+
+TEST(CalculationValue, LengthConstruction)
+{
+ RefPtr<WebCore::CalculationValue> value = createTestValue();
+
+ EXPECT_EQ(1U, value->refCount());
+
+ {
+ WebCore::Length length(*value);
+ EXPECT_EQ(2U, value->refCount());
+ }
+
+ EXPECT_EQ(1U, value->refCount());
+
+ {
+ WebCore::Length lengthA(*value);
+ EXPECT_EQ(2U, value->refCount());
+ WebCore::Length lengthB(lengthA);
+ EXPECT_EQ(2U, value->refCount());
+ }
+
+ EXPECT_EQ(1U, value->refCount());
+
+ {
+ WebCore::Length lengthC(*value);
+ EXPECT_EQ(2U, value->refCount());
+ WebCore::Length lengthD(WTFMove(lengthC));
+ EXPECT_EQ(2U, value->refCount());
+ }
+
+ EXPECT_EQ(1U, value->refCount());
+
+ EXPECT_EQ(0U, deletionCount);
+ value = nullptr;
+ EXPECT_EQ(1U, deletionCount);
+ deletionCount = 0;
+}
+
+TEST(CalculationValue, LengthConstructionReleasedValue)
+{
+ RefPtr<WebCore::CalculationValue> value = createTestValue();
+
+ EXPECT_EQ(1U, value->refCount());
+
+ {
+ auto* rawValue = value.get();
+ WebCore::Length length(value.releaseNonNull());
+ EXPECT_EQ(1U, rawValue->refCount());
+
+ EXPECT_EQ(0U, deletionCount);
+ }
+
+ EXPECT_EQ(1U, deletionCount);
+ deletionCount = 0;
+
+ value = createTestValue();
+
+ {
+ auto* rawValue = value.get();
+ WebCore::Length lengthA(value.releaseNonNull());
+ EXPECT_EQ(1U, rawValue->refCount());
+ WebCore::Length lengthB(lengthA);
+ EXPECT_EQ(1U, rawValue->refCount());
+
+ EXPECT_EQ(0U, deletionCount);
+ }
+
+ EXPECT_EQ(1U, deletionCount);
+ deletionCount = 0;
+
+ value = createTestValue();
+
+ {
+ auto* rawValue = value.get();
+ WebCore::Length lengthC(value.releaseNonNull());
+ EXPECT_EQ(1U, rawValue->refCount());
+ WebCore::Length lengthD(WTFMove(lengthC));
+ EXPECT_EQ(1U, rawValue->refCount());
+
+ EXPECT_EQ(0U, deletionCount);
+ }
+
+ EXPECT_EQ(1U, deletionCount);
+ deletionCount = 0;
+}
+
+TEST(CalculationValue, LengthAssignment)
+{
+ RefPtr<WebCore::CalculationValue> value = createTestValue();
+
+ EXPECT_EQ(1U, value->refCount());
+
+ {
+ WebCore::Length lengthA(*value);
+ EXPECT_EQ(2U, value->refCount());
+ WebCore::Length lengthB;
+ lengthB = lengthA;
+ EXPECT_EQ(2U, value->refCount());
+ }
+
+ EXPECT_EQ(1U, value->refCount());
+
+ {
+ WebCore::Length lengthC(*value);
+ EXPECT_EQ(2U, value->refCount());
+ WebCore::Length lengthD;
+ lengthD = WTFMove(lengthC);
+ EXPECT_EQ(2U, value->refCount());
+ }
+
+ EXPECT_EQ(1U, value->refCount());
+
+ EXPECT_EQ(0U, deletionCount);
+ value = nullptr;
+ EXPECT_EQ(1U, deletionCount);
+ deletionCount = 0;
+
+ value = createTestValue();
+ RefPtr<WebCore::CalculationValue> value2 = createTestValue();
+
+ EXPECT_EQ(1U, value->refCount());
+ EXPECT_EQ(1U, value2->refCount());
+
+ {
+ WebCore::Length lengthE(*value);
+ EXPECT_EQ(2U, value->refCount());
+ WebCore::Length lengthF(*value2);
+ EXPECT_EQ(2U, value2->refCount());
+ lengthE = lengthF;
+ EXPECT_EQ(1U, value->refCount());
+ EXPECT_EQ(2U, value2->refCount());
+ }
+
+ EXPECT_EQ(1U, value->refCount());
+ EXPECT_EQ(1U, value2->refCount());
+
+ {
+ WebCore::Length lengthG(*value);
+ EXPECT_EQ(2U, value->refCount());
+ WebCore::Length lengthH(*value2);
+ EXPECT_EQ(2U, value2->refCount());
+ lengthG = WTFMove(lengthH);
+ EXPECT_EQ(1U, value->refCount());
+ EXPECT_EQ(2U, value2->refCount());
+ }
+
+ EXPECT_EQ(0U, deletionCount);
+ value = nullptr;
+ EXPECT_EQ(1U, deletionCount);
+ value2 = nullptr;
+ EXPECT_EQ(2U, deletionCount);
+ deletionCount = 0;
+}
+
+TEST(CalculationValue, LengthAssignmentReleasedValue)
+{
+ RefPtr<WebCore::CalculationValue> value = createTestValue();
+
+ {
+ auto* rawValue = value.get();
+ WebCore::Length lengthA(value.releaseNonNull());
+ EXPECT_EQ(1U, rawValue->refCount());
+ WebCore::Length lengthB;
+ lengthB = lengthA;
+ EXPECT_EQ(1U, rawValue->refCount());
+
+ EXPECT_EQ(0U, deletionCount);
+ }
+
+ EXPECT_EQ(1U, deletionCount);
+ deletionCount = 0;
+
+ value = createTestValue();
+
+ {
+ auto* rawValue = value.get();
+ WebCore::Length lengthC(value.releaseNonNull());
+ EXPECT_EQ(1U, rawValue->refCount());
+ WebCore::Length lengthD;
+ lengthD = WTFMove(lengthC);
+ EXPECT_EQ(1U, rawValue->refCount());
+
+ EXPECT_EQ(0U, deletionCount);
+ }
+
+ EXPECT_EQ(1U, deletionCount);
+ deletionCount = 0;
+
+ value = createTestValue();
+ RefPtr<WebCore::CalculationValue> value2 = createTestValue();
+
+ EXPECT_EQ(1U, value->refCount());
+ EXPECT_EQ(1U, value2->refCount());
+
+ {
+ auto* rawValue = value.get();
+ WebCore::Length lengthE(value.releaseNonNull());
+ EXPECT_EQ(1U, rawValue->refCount());
+ auto* rawValue2 = value2.get();
+ WebCore::Length lengthF(value2.releaseNonNull());
+ EXPECT_EQ(1U, rawValue2->refCount());
+
+ lengthE = lengthF;
+ EXPECT_EQ(1U, deletionCount);
+ EXPECT_EQ(1U, rawValue2->refCount());
+ }
+
+ EXPECT_EQ(2U, deletionCount);
+ deletionCount = 0;
+
+ value = createTestValue();
+ value2 = createTestValue();
+
+ EXPECT_EQ(1U, value->refCount());
+ EXPECT_EQ(1U, value2->refCount());
+
+ {
+ auto* rawValue = value.get();
+ WebCore::Length lengthG(value.releaseNonNull());
+ EXPECT_EQ(1U, rawValue->refCount());
+ auto* rawValue2 = value2.get();
+ WebCore::Length lengthH(value2.releaseNonNull());
+ EXPECT_EQ(1U, rawValue2->refCount());
+
+ lengthG = WTFMove(lengthH);
+ EXPECT_EQ(1U, deletionCount);
+ EXPECT_EQ(1U, rawValue2->refCount());
+ }
+
+ EXPECT_EQ(2U, deletionCount);
+ deletionCount = 0;
+}
+
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/Color.cpp b/Tools/TestWebKitAPI/Tests/WebCore/Color.cpp
new file mode 100644
index 000000000..61af1c660
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/Color.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "Test.h"
+#include <WebCore/Color.h>
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+TEST(Color, RGBToHSV_White)
+{
+ Color color = Color::white;
+
+ double h = 0;
+ double s = 0;
+ double v = 0;
+ color.getHSV(h, s, v);
+
+ EXPECT_DOUBLE_EQ(0, h);
+ EXPECT_DOUBLE_EQ(0, s);
+ EXPECT_DOUBLE_EQ(1, v);
+}
+
+TEST(Color, RGBToHSV_Black)
+{
+ Color color = Color::black;
+
+ double h = 0;
+ double s = 0;
+ double v = 0;
+ color.getHSV(h, s, v);
+
+ EXPECT_DOUBLE_EQ(0, h);
+ EXPECT_DOUBLE_EQ(0, s);
+ EXPECT_DOUBLE_EQ(0, v);
+}
+
+TEST(Color, RGBToHSV_Red)
+{
+ Color color(255, 0, 0);
+
+ double h = 0;
+ double s = 0;
+ double v = 0;
+ color.getHSV(h, s, v);
+
+ EXPECT_DOUBLE_EQ(0, h);
+ EXPECT_DOUBLE_EQ(1, s);
+ EXPECT_DOUBLE_EQ(1, v);
+}
+
+TEST(Color, RGBToHSV_Green)
+{
+ Color color(0, 255, 0);
+
+ double h = 0;
+ double s = 0;
+ double v = 0;
+ color.getHSV(h, s, v);
+
+ EXPECT_DOUBLE_EQ(0.33333333333333331, h);
+ EXPECT_DOUBLE_EQ(1, s);
+ EXPECT_DOUBLE_EQ(1, v);
+}
+
+TEST(Color, RGBToHSV_Blue)
+{
+ Color color(0, 0, 255);
+
+ double h = 0;
+ double s = 0;
+ double v = 0;
+ color.getHSV(h, s, v);
+
+ EXPECT_DOUBLE_EQ(0.66666666666666663, h);
+ EXPECT_DOUBLE_EQ(1, s);
+ EXPECT_DOUBLE_EQ(1, v);
+}
+
+TEST(Color, RGBToHSV_DarkGray)
+{
+ Color color = Color::darkGray;
+
+ double h = 0;
+ double s = 0;
+ double v = 0;
+ color.getHSV(h, s, v);
+
+ EXPECT_DOUBLE_EQ(0, h);
+ EXPECT_DOUBLE_EQ(0, s);
+ EXPECT_DOUBLE_EQ(0.50196078431372548, v);
+}
+
+TEST(Color, RGBToHSV_Gray)
+{
+ Color color = Color::gray;
+
+ double h = 0;
+ double s = 0;
+ double v = 0;
+ color.getHSV(h, s, v);
+
+ EXPECT_DOUBLE_EQ(0, h);
+ EXPECT_DOUBLE_EQ(0, s);
+ EXPECT_DOUBLE_EQ(0.62745098039215685, v);
+}
+
+TEST(Color, RGBToHSV_LightGray)
+{
+ Color color = Color::lightGray;
+
+ double h = 0;
+ double s = 0;
+ double v = 0;
+ color.getHSV(h, s, v);
+
+ EXPECT_DOUBLE_EQ(0, h);
+ EXPECT_DOUBLE_EQ(0, s);
+ EXPECT_DOUBLE_EQ(0.75294117647058822, v);
+}
+
+TEST(Color, Validity)
+{
+ Color invalidColor;
+ EXPECT_FALSE(invalidColor.isValid());
+ EXPECT_FALSE(invalidColor.isExtended());
+
+ Color otherInvalidColor = invalidColor;
+ EXPECT_FALSE(otherInvalidColor.isValid());
+ EXPECT_FALSE(otherInvalidColor.isExtended());
+
+ Color validColor(255, 0, 0);
+ EXPECT_TRUE(validColor.isValid());
+ EXPECT_FALSE(validColor.isExtended());
+
+ Color otherValidColor = validColor;
+ EXPECT_TRUE(otherValidColor.isValid());
+ EXPECT_FALSE(otherValidColor.isExtended());
+
+ validColor = Color(1, 2, 3, 4);
+ EXPECT_TRUE(validColor.isValid());
+ EXPECT_FALSE(validColor.isExtended());
+ EXPECT_EQ(validColor.red(), 1);
+ EXPECT_EQ(validColor.green(), 2);
+ EXPECT_EQ(validColor.blue(), 3);
+ EXPECT_EQ(validColor.alpha(), 4);
+
+ Color yetAnotherValidColor(WTFMove(validColor));
+ EXPECT_TRUE(yetAnotherValidColor.isValid());
+ EXPECT_FALSE(yetAnotherValidColor.isExtended());
+ EXPECT_EQ(yetAnotherValidColor.red(), 1);
+ EXPECT_EQ(yetAnotherValidColor.green(), 2);
+ EXPECT_EQ(yetAnotherValidColor.blue(), 3);
+ EXPECT_EQ(yetAnotherValidColor.alpha(), 4);
+
+ otherValidColor = WTFMove(yetAnotherValidColor);
+ EXPECT_TRUE(otherValidColor.isValid());
+ EXPECT_FALSE(otherValidColor.isExtended());
+ EXPECT_EQ(otherValidColor.red(), 1);
+ EXPECT_EQ(otherValidColor.green(), 2);
+ EXPECT_EQ(otherValidColor.blue(), 3);
+ EXPECT_EQ(otherValidColor.alpha(), 4);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/ComplexTextController.cpp b/Tools/TestWebKitAPI/Tests/WebCore/ComplexTextController.cpp
new file mode 100644
index 000000000..680dac0be
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/ComplexTextController.cpp
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <JavaScriptCore/InitializeThreading.h>
+#include <WebCore/ComplexTextController.h>
+#include <WebCore/FontCascade.h>
+#include <wtf/MainThread.h>
+#include <wtf/RunLoop.h>
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+class ComplexTextControllerTest : public testing::Test {
+public:
+ virtual void SetUp()
+ {
+ JSC::initializeThreading();
+ RunLoop::initializeMainRunLoop();
+ }
+};
+
+TEST_F(ComplexTextControllerTest, InitialAdvanceWithLeftRunInRTL)
+{
+ FontCascadeDescription description;
+ description.setOneFamily("Times");
+ description.setComputedSize(80);
+ FontCascade font(description);
+ font.update();
+ auto spaceWidth = font.primaryFont().spaceWidth();
+
+#if USE_LAYOUT_SPECIFIC_ADVANCES
+ Vector<FloatSize> advances = { FloatSize(), FloatSize(21.640625, 0.0), FloatSize(42.3046875, 0.0), FloatSize(55.8984375, 0.0), FloatSize(22.34375, 0.0) };
+ Vector<FloatPoint> origins = { FloatPoint(-15.15625, 18.046875), FloatPoint(), FloatPoint(), FloatPoint(), FloatPoint() };
+#else
+ Vector<FloatSize> advances = { FloatSize(15.15625, -18.046875), FloatSize(21.640625, 0.0), FloatSize(42.3046875, 0.0), FloatSize(55.8984375, 0.0), FloatSize(22.34375, 0.0) };
+ Vector<FloatPoint> origins = { };
+#endif
+
+ FloatSize initialAdvance = FloatSize(-15.15625, 18.046875);
+
+ UChar characters[] = { 0x644, 0x637, 0x641, 0x627, 0x64b, 0x20 };
+ size_t charactersLength = WTF_ARRAY_LENGTH(characters);
+ TextRun textRun(StringView(characters, charactersLength));
+ auto run1 = ComplexTextController::ComplexTextRun::create({ FloatSize(21.875, 0) }, { FloatPoint() }, { 5 }, { 5 }, FloatSize(), font.primaryFont(), characters, 0, charactersLength, 5, 6, false);
+ auto run2 = ComplexTextController::ComplexTextRun::create(advances, origins, { 193, 377, 447, 431, 458 }, { 4, 3, 2, 1, 0 }, initialAdvance, font.primaryFont(), characters, 0, charactersLength, 0, 5, false);
+ Vector<Ref<ComplexTextController::ComplexTextRun>> runs;
+ runs.append(WTFMove(run1));
+ runs.append(WTFMove(run2));
+ ComplexTextController controller(font, textRun, runs);
+
+ float totalWidth = 0;
+ for (size_t i = 1; i < advances.size(); ++i)
+ totalWidth += advances[i].width();
+ EXPECT_NEAR(controller.totalWidth(), spaceWidth + totalWidth, 0.0001);
+ GlyphBuffer glyphBuffer;
+ EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+ controller.advance(0, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+ controller.advance(1, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), advances[4].width(), 0.0001);
+ controller.advance(6, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), spaceWidth + totalWidth, 0.0001);
+ EXPECT_NEAR(glyphBuffer.initialAdvance().width(), 0, 0.0001);
+ EXPECT_NEAR(glyphBuffer.initialAdvance().height(), 0, 0.0001);
+ EXPECT_EQ(glyphBuffer.size(), 6U);
+ EXPECT_NEAR(glyphBuffer.advanceAt(0).width(), advances[4].width(), 0.0001);
+ EXPECT_NEAR(glyphBuffer.advanceAt(1).width(), advances[3].width(), 0.0001);
+ EXPECT_NEAR(glyphBuffer.advanceAt(2).width(), advances[2].width(), 0.0001);
+ EXPECT_NEAR(glyphBuffer.advanceAt(3).width(), advances[1].width(), 0.0001);
+ EXPECT_NEAR(glyphBuffer.advanceAt(4).width(), -initialAdvance.width(), 0.0001);
+ EXPECT_NEAR(glyphBuffer.advanceAt(5).width(), spaceWidth + initialAdvance.width(), 0.0001);
+}
+
+TEST_F(ComplexTextControllerTest, InitialAdvanceInRTL)
+{
+ FontCascadeDescription description;
+ description.setOneFamily("Times");
+ description.setComputedSize(80);
+ FontCascade font(description);
+ font.update();
+
+#if USE_LAYOUT_SPECIFIC_ADVANCES
+ Vector<FloatSize> advances = { FloatSize(), FloatSize(21.640625, 0.0), FloatSize(42.3046875, 0.0), FloatSize(55.8984375, 0.0), FloatSize(22.34375, 0.0) };
+ Vector<FloatPoint> origins = { FloatPoint(-15.15625, 18.046875), FloatPoint(), FloatPoint(), FloatPoint(), FloatPoint() };
+#else
+ Vector<FloatSize> advances = { FloatSize(15.15625, -18.046875), FloatSize(21.640625, 0.0), FloatSize(42.3046875, 0.0), FloatSize(55.8984375, 0.0), FloatSize(22.34375, 0.0) };
+ Vector<FloatPoint> origins = { };
+#endif
+
+ FloatSize initialAdvance = FloatSize(-15.15625, 18.046875);
+
+ UChar characters[] = { 0x644, 0x637, 0x641, 0x627, 0x64b };
+ size_t charactersLength = WTF_ARRAY_LENGTH(characters);
+ TextRun textRun(StringView(characters, charactersLength));
+ auto run = ComplexTextController::ComplexTextRun::create(advances, origins, { 193, 377, 447, 431, 458 }, { 4, 3, 2, 1, 0 }, initialAdvance, font.primaryFont(), characters, 0, charactersLength, 0, 5, false);
+ Vector<Ref<ComplexTextController::ComplexTextRun>> runs;
+ runs.append(WTFMove(run));
+ ComplexTextController controller(font, textRun, runs);
+
+ float totalWidth = 0;
+ for (size_t i = 1; i < advances.size(); ++i)
+ totalWidth += advances[i].width();
+ EXPECT_NEAR(controller.totalWidth(), totalWidth, 0.0001);
+ GlyphBuffer glyphBuffer;
+ EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+ controller.advance(0, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+ controller.advance(1, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), advances[4].width(), 0.0001);
+ controller.advance(5, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), totalWidth, 0.0001);
+ EXPECT_NEAR(glyphBuffer.initialAdvance().width(), initialAdvance.width(), 0.0001);
+ EXPECT_NEAR(glyphBuffer.initialAdvance().height(), initialAdvance.height(), 0.0001);
+ EXPECT_EQ(glyphBuffer.size(), 5U);
+ EXPECT_NEAR(glyphBuffer.advanceAt(0).width(), advances[4].width(), 0.0001);
+ EXPECT_NEAR(glyphBuffer.advanceAt(1).width(), advances[3].width(), 0.0001);
+ EXPECT_NEAR(glyphBuffer.advanceAt(2).width(), advances[2].width(), 0.0001);
+ EXPECT_NEAR(glyphBuffer.advanceAt(3).width(), advances[1].width(), 0.0001);
+ EXPECT_NEAR(glyphBuffer.advanceAt(4).width(), -initialAdvance.width(), 0.0001);
+ EXPECT_NEAR(glyphBuffer.advanceAt(4).height(), initialAdvance.height(), 0.0001);
+}
+
+TEST_F(ComplexTextControllerTest, InitialAdvanceWithLeftRunInLTR)
+{
+ FontCascadeDescription description;
+ description.setOneFamily("LucidaGrande");
+ description.setComputedSize(80);
+ FontCascade font(description);
+ font.update();
+ auto spaceWidth = font.primaryFont().spaceWidth();
+
+#if USE_LAYOUT_SPECIFIC_ADVANCES
+ Vector<FloatSize> advances = { FloatSize(76.347656, 0.000000), FloatSize(0.000000, 0.000000) };
+ Vector<FloatPoint> origins = { FloatPoint(), FloatPoint(-23.281250, -8.398438) };
+#else
+ Vector<FloatSize> advances = { FloatSize(53.066406, -8.398438), FloatSize(23.281250, 8.398438) };
+ Vector<FloatPoint> origins = { };
+#endif
+
+ FloatSize initialAdvance = FloatSize(28.144531, 0);
+
+ UChar characters[] = { 0x20, 0x61, 0x20e3 };
+ size_t charactersLength = WTF_ARRAY_LENGTH(characters);
+ TextRun textRun(StringView(characters, charactersLength));
+ auto run1 = ComplexTextController::ComplexTextRun::create({ FloatSize(spaceWidth, 0) }, { FloatPoint() }, { 5 }, { 0 }, FloatSize(), font.primaryFont(), characters, 0, charactersLength, 0, 1, true);
+ auto run2 = ComplexTextController::ComplexTextRun::create(advances, origins, { 68, 1471 }, { 1, 2 }, initialAdvance, font.primaryFont(), characters, 0, charactersLength, 1, 3, true);
+ Vector<Ref<ComplexTextController::ComplexTextRun>> runs;
+ runs.append(WTFMove(run1));
+ runs.append(WTFMove(run2));
+ ComplexTextController controller(font, textRun, runs);
+
+ EXPECT_NEAR(controller.totalWidth(), spaceWidth + 76.347656 + initialAdvance.width(), 0.0001);
+ GlyphBuffer glyphBuffer;
+ EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+ controller.advance(0, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+ controller.advance(1, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), spaceWidth, 0.0001);
+ controller.advance(2, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), spaceWidth + advances[0].width() + initialAdvance.width(), 0.0001);
+ controller.advance(3, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), spaceWidth + 76.347656 + initialAdvance.width(), 0.0001);
+ EXPECT_NEAR(glyphBuffer.initialAdvance().width(), 0, 0.0001);
+ EXPECT_NEAR(glyphBuffer.initialAdvance().height(), 0, 0.0001);
+ EXPECT_EQ(glyphBuffer.size(), 3U);
+ EXPECT_NEAR(glyphBuffer.advanceAt(0).width(), spaceWidth + initialAdvance.width(), 0.0001);
+ EXPECT_NEAR(glyphBuffer.advanceAt(1).width(), 53.066406, 0.0001);
+ EXPECT_NEAR(glyphBuffer.advanceAt(2).width(), 23.281250, 0.0001);
+}
+
+TEST_F(ComplexTextControllerTest, InitialAdvanceInLTR)
+{
+ FontCascadeDescription description;
+ description.setOneFamily("LucidaGrande");
+ description.setComputedSize(80);
+ FontCascade font(description);
+ font.update();
+
+#if USE_LAYOUT_SPECIFIC_ADVANCES
+ Vector<FloatSize> advances = { FloatSize(76.347656, 0.000000), FloatSize(0.000000, 0.000000) };
+ Vector<FloatPoint> origins = { FloatPoint(), FloatPoint(-23.281250, -8.398438) };
+#else
+ Vector<FloatSize> advances = { FloatSize(53.066406, -8.398438), FloatSize(23.281250, 8.398438) };
+ Vector<FloatPoint> origins = { };
+#endif
+
+ FloatSize initialAdvance = FloatSize(28.144531, 0);
+
+ UChar characters[] = { 0x61, 0x20e3 };
+ size_t charactersLength = WTF_ARRAY_LENGTH(characters);
+ TextRun textRun(StringView(characters, charactersLength));
+ auto run = ComplexTextController::ComplexTextRun::create(advances, origins, { 68, 1471 }, { 0, 1 }, initialAdvance, font.primaryFont(), characters, 0, charactersLength, 0, 2, true);
+ Vector<Ref<ComplexTextController::ComplexTextRun>> runs;
+ runs.append(WTFMove(run));
+ ComplexTextController controller(font, textRun, runs);
+
+ EXPECT_NEAR(controller.totalWidth(), 76.347656 + initialAdvance.width(), 0.0001);
+ GlyphBuffer glyphBuffer;
+ EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+ controller.advance(0, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+ controller.advance(1, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), advances[0].width() + initialAdvance.width(), 0.0001);
+ controller.advance(2, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), 76.347656 + initialAdvance.width(), 0.0001);
+ EXPECT_NEAR(glyphBuffer.initialAdvance().width(), initialAdvance.width(), 0.0001);
+ EXPECT_NEAR(glyphBuffer.initialAdvance().height(), initialAdvance.height(), 0.0001);
+ EXPECT_EQ(glyphBuffer.size(), 2U);
+ EXPECT_NEAR(glyphBuffer.advanceAt(0).width(), 53.066406, 0.0001);
+ EXPECT_NEAR(glyphBuffer.advanceAt(1).width(), 23.281250, 0.0001);
+}
+
+TEST_F(ComplexTextControllerTest, InitialAdvanceInRTLNoOrigins)
+{
+ FontCascadeDescription description;
+ description.setOneFamily("Times");
+ description.setComputedSize(48);
+ FontCascade font(description);
+ font.update();
+
+ FloatSize initialAdvance = FloatSize(4.33996383363472, 12.368896925859);
+
+ UChar characters[] = { 0x633, 0x20, 0x627, 0x650 };
+ size_t charactersLength = WTF_ARRAY_LENGTH(characters);
+ TextRun textRun(StringView(characters, charactersLength));
+ auto run1 = ComplexTextController::ComplexTextRun::create({ FloatSize(-4.33996383363472, -12.368896925859), FloatSize(14.0397830018083, 0) }, { }, { 884, 240 }, { 3, 2 }, initialAdvance, font.primaryFont(), characters, 0, charactersLength, 2, 4, false);
+ auto run2 = ComplexTextController::ComplexTextRun::create({ FloatSize(12.0, 0) }, { }, { 3 }, { 1 }, FloatSize(), font.primaryFont(), characters, 0, charactersLength, 1, 2, false);
+ auto run3 = ComplexTextController::ComplexTextRun::create({ FloatSize(43.8119349005425, 0) }, { }, { 276 }, { 0 }, FloatSize(), font.primaryFont(), characters, 0, charactersLength, 0, 1, false);
+ Vector<Ref<ComplexTextController::ComplexTextRun>> runs;
+ runs.append(WTFMove(run1));
+ runs.append(WTFMove(run2));
+ runs.append(WTFMove(run3));
+ ComplexTextController controller(font, textRun, runs);
+
+ float totalWidth = 14.0397830018083 + 12.0 + 43.8119349005425;
+ EXPECT_NEAR(controller.totalWidth(), totalWidth, 0.0001);
+ GlyphBuffer glyphBuffer;
+ EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+ controller.advance(0, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+ controller.advance(1, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), 43.8119349005425, 0.0001);
+ controller.advance(2, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), 43.8119349005425 + 12.0, 0.0001);
+ controller.advance(3, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), totalWidth, 0.0001);
+ controller.advance(4, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), totalWidth, 0.0001);
+ EXPECT_NEAR(glyphBuffer.initialAdvance().width(), initialAdvance.width(), 0.0001);
+ EXPECT_NEAR(glyphBuffer.initialAdvance().height(), initialAdvance.height(), 0.0001);
+ EXPECT_EQ(glyphBuffer.size(), 4U);
+ EXPECT_NEAR(glyphBuffer.advanceAt(0).width(), 43.8119349005425, 0.0001);
+ EXPECT_NEAR(glyphBuffer.advanceAt(1).width(), 12.0, 0.0001);
+ EXPECT_NEAR(glyphBuffer.advanceAt(2).width(), 14.0397830018083, 0.0001);
+ EXPECT_NEAR(glyphBuffer.advanceAt(3).width(), -4.33996383363472, 0.0001);
+ EXPECT_NEAR(glyphBuffer.advanceAt(3).height(), 12.368896925859, 0.0001);
+}
+
+TEST_F(ComplexTextControllerTest, LeadingExpansion)
+{
+ FontCascadeDescription description;
+ description.setOneFamily("Times");
+ description.setComputedSize(48);
+ FontCascade font(description);
+ font.update();
+
+ UChar characters[] = { 'a' };
+ size_t charactersLength = WTF_ARRAY_LENGTH(characters);
+ TextRun textRun(StringView(characters, charactersLength), 0, 100, ForceLeadingExpansion);
+ auto run = ComplexTextController::ComplexTextRun::create({ FloatSize(24, 0) }, { }, { 16 }, { 0 }, FloatSize(), font.primaryFont(), characters, 0, charactersLength, 0, 1, true);
+ Vector<Ref<ComplexTextController::ComplexTextRun>> runs;
+ runs.append(WTFMove(run));
+ ComplexTextController controller(font, textRun, runs);
+
+ float totalWidth = 100 + 24;
+ EXPECT_NEAR(controller.totalWidth(), totalWidth, 0.0001);
+ GlyphBuffer glyphBuffer;
+ EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+ controller.advance(0, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+ controller.advance(1, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), totalWidth, 0.0001);
+ EXPECT_NEAR(glyphBuffer.initialAdvance().width(), 100, 0.0001);
+ EXPECT_NEAR(glyphBuffer.initialAdvance().height(), 0, 0.0001);
+ EXPECT_EQ(glyphBuffer.size(), 1U);
+ EXPECT_NEAR(glyphBuffer.advanceAt(0).width(), 24, 0.0001);
+}
+
+TEST_F(ComplexTextControllerTest, VerticalAdvances)
+{
+ FontCascadeDescription description;
+ description.setOneFamily("Times");
+ description.setComputedSize(48);
+ FontCascade font(description);
+ font.update();
+
+ UChar characters[] = { 'a', 'b', 'c', 'd' };
+ size_t charactersLength = WTF_ARRAY_LENGTH(characters);
+ TextRun textRun(StringView(characters, charactersLength));
+ auto run1 = ComplexTextController::ComplexTextRun::create({ FloatSize(0, 1), FloatSize(0, 2) }, { FloatPoint(0, 4), FloatPoint(0, 8) }, { 16, 17 }, { 0, 1 }, FloatSize(0, 16), font.primaryFont(), characters, 0, charactersLength, 0, 2, true);
+ auto run2 = ComplexTextController::ComplexTextRun::create({ FloatSize(0, 32), FloatSize(0, 64) }, { FloatPoint(0, 128), FloatPoint(0, 256) }, { 18, 19 }, { 2, 3 }, FloatSize(0, 512), font.primaryFont(), characters, 0, charactersLength, 2, 4, true);
+ Vector<Ref<ComplexTextController::ComplexTextRun>> runs;
+ runs.append(WTFMove(run1));
+ runs.append(WTFMove(run2));
+ ComplexTextController controller(font, textRun, runs);
+
+ EXPECT_NEAR(controller.totalWidth(), 0, 0.0001);
+ GlyphBuffer glyphBuffer;
+ EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+ controller.advance(0, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+ controller.advance(1, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+ controller.advance(2, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+ controller.advance(3, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+ controller.advance(4, &glyphBuffer);
+ EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+ EXPECT_NEAR(glyphBuffer.initialAdvance().width(), 0, 0.0001);
+ EXPECT_NEAR(glyphBuffer.initialAdvance().height(), 16, 0.0001);
+ EXPECT_EQ(glyphBuffer.size(), 4U);
+ EXPECT_NEAR(glyphBuffer.advanceAt(0).width(), 0, 0.0001);
+ EXPECT_NEAR(glyphBuffer.advanceAt(0).height(), 4 - 1 -8, 0.0001);
+ EXPECT_NEAR(glyphBuffer.advanceAt(1).width(), 0, 0.0001);
+ EXPECT_NEAR(glyphBuffer.advanceAt(1).height(), 8 - 2 - 512, 0.0001);
+ EXPECT_NEAR(glyphBuffer.advanceAt(2).width(), 0, 0.0001);
+ EXPECT_NEAR(glyphBuffer.advanceAt(2).height(), 128 - 32 - 256, 0.0001);
+ EXPECT_NEAR(glyphBuffer.advanceAt(3).width(), 0, 0.0001);
+ EXPECT_NEAR(glyphBuffer.advanceAt(3).height(), 256 - 64, 0.0001);
+}
+
+TEST_F(ComplexTextControllerTest, TotalWidthWithJustification)
+{
+ FontCascadeDescription description;
+ description.setOneFamily("Times");
+ description.setComputedSize(80);
+ FontCascade font(description);
+ font.update();
+
+ Vector<FloatSize> advances = { FloatSize(1, 0), FloatSize(2, 0), FloatSize(4, 0), FloatSize(8, 0), FloatSize(16, 0) };
+#if USE_LAYOUT_SPECIFIC_ADVANCES
+ Vector<FloatPoint> origins = { FloatPoint(), FloatPoint(), FloatPoint(), FloatPoint(), FloatPoint() };
+#else
+ Vector<FloatPoint> origins = { };
+#endif
+
+ FloatSize initialAdvance = FloatSize();
+
+ UChar characters[] = { 0x644, ' ', 0x644, ' ', 0x644 };
+ size_t charactersLength = WTF_ARRAY_LENGTH(characters);
+ TextRun textRun(StringView(characters, charactersLength), 0, 14, DefaultExpansion, RTL);
+ auto run = ComplexTextController::ComplexTextRun::create(advances, origins, { 5, 6, 7, 8, 9 }, { 4, 3, 2, 1, 0 }, initialAdvance, font.primaryFont(), characters, 0, charactersLength, 0, 5, false);
+ Vector<Ref<ComplexTextController::ComplexTextRun>> runs;
+ runs.append(WTFMove(run));
+ ComplexTextController controller(font, textRun, runs);
+
+ EXPECT_NEAR(controller.totalWidth(), 1 + 20 + 7 + 4 + 20 + 7 + 16, 0.0001);
+ GlyphBuffer glyphBuffer;
+ EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+ controller.advance(5, &glyphBuffer);
+ EXPECT_EQ(glyphBuffer.size(), 5U);
+ EXPECT_NEAR(glyphBuffer.advanceAt(0).width() + glyphBuffer.advanceAt(1).width() + glyphBuffer.advanceAt(2).width() + glyphBuffer.advanceAt(3).width() + glyphBuffer.advanceAt(4).width(), controller.totalWidth(), 0.0001);
+}
+
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp b/Tools/TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp
new file mode 100644
index 000000000..40950c273
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp
@@ -0,0 +1,2795 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "PlatformUtilities.h"
+#include <JavaScriptCore/InitializeThreading.h>
+#include <WebCore/CombinedURLFilters.h>
+#include <WebCore/ContentExtensionCompiler.h>
+#include <WebCore/ContentExtensionError.h>
+#include <WebCore/ContentExtensionsBackend.h>
+#include <WebCore/DFA.h>
+#include <WebCore/DFABytecodeCompiler.h>
+#include <WebCore/DFABytecodeInterpreter.h>
+#include <WebCore/NFA.h>
+#include <WebCore/NFAToDFA.h>
+#include <WebCore/ResourceLoadInfo.h>
+#include <WebCore/URL.h>
+#include <WebCore/URLFilterParser.h>
+#include <wtf/MainThread.h>
+#include <wtf/RunLoop.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+namespace ContentExtensions {
+inline std::ostream& operator<<(std::ostream& os, const ActionType& action)
+{
+ switch (action) {
+ case ActionType::BlockLoad:
+ return os << "ActionType::BlockLoad";
+ case ActionType::BlockCookies:
+ return os << "ActionType::BlockCookies";
+ case ActionType::CSSDisplayNoneSelector:
+ return os << "ActionType::CSSDisplayNone";
+ case ActionType::CSSDisplayNoneStyleSheet:
+ return os << "ActionType::CSSDisplayNoneStyleSheet";
+ case ActionType::IgnorePreviousRules:
+ return os << "ActionType::IgnorePreviousRules";
+ case ActionType::MakeHTTPS:
+ return os << "ActionType::MakeHTTPS";
+ case ActionType::InvalidAction:
+ return os << "ActionType::InvalidAction";
+ }
+}
+}
+}
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+class ContentExtensionTest : public testing::Test {
+public:
+ virtual void SetUp()
+ {
+ JSC::initializeThreading();
+ RunLoop::initializeMainRunLoop();
+ }
+};
+
+struct CompiledContentExtensionData {
+ Vector<ContentExtensions::SerializedActionByte> actions;
+ Vector<ContentExtensions::DFABytecode> filtersWithoutDomains;
+ Vector<ContentExtensions::DFABytecode> filtersWithDomains;
+ Vector<ContentExtensions::DFABytecode> domainFilters;
+};
+
+class InMemoryContentExtensionCompilationClient final : public ContentExtensions::ContentExtensionCompilationClient {
+public:
+ InMemoryContentExtensionCompilationClient(CompiledContentExtensionData& data)
+ : m_data(data)
+ {
+ EXPECT_EQ(data.actions.size(), 0ull);
+ EXPECT_EQ(data.filtersWithoutDomains.size(), 0ull);
+ EXPECT_EQ(data.filtersWithDomains.size(), 0ull);
+ EXPECT_EQ(data.domainFilters.size(), 0ull);
+ }
+
+ void writeActions(Vector<ContentExtensions::SerializedActionByte>&& actions) override
+ {
+ EXPECT_FALSE(finalized);
+ EXPECT_EQ(m_data.actions.size(), 0ull);
+ EXPECT_EQ(m_data.filtersWithoutDomains.size(), 0ull);
+ EXPECT_EQ(m_data.filtersWithDomains.size(), 0ull);
+ EXPECT_EQ(m_data.domainFilters.size(), 0ull);
+ m_data.actions.appendVector(actions);
+ }
+
+ void writeFiltersWithoutDomainsBytecode(Vector<ContentExtensions::DFABytecode>&& bytecode) override
+ {
+ EXPECT_FALSE(finalized);
+ EXPECT_EQ(m_data.filtersWithDomains.size(), 0ull);
+ EXPECT_EQ(m_data.domainFilters.size(), 0ull);
+ m_data.filtersWithoutDomains.appendVector(bytecode);
+ }
+
+ void writeFiltersWithDomainsBytecode(Vector<ContentExtensions::DFABytecode>&& bytecode) override
+ {
+ EXPECT_FALSE(finalized);
+ EXPECT_EQ(m_data.domainFilters.size(), 0ull);
+ m_data.filtersWithDomains.appendVector(bytecode);
+ }
+
+ void writeDomainFiltersBytecode(Vector<ContentExtensions::DFABytecode>&& bytecode) override
+ {
+ EXPECT_FALSE(finalized);
+ m_data.domainFilters.appendVector(bytecode);
+ }
+
+ void finalize() override
+ {
+ finalized = true;
+ }
+
+private:
+ CompiledContentExtensionData& m_data;
+ bool finalized { false };
+};
+
+class InMemoryCompiledContentExtension : public ContentExtensions::CompiledContentExtension {
+public:
+ static RefPtr<InMemoryCompiledContentExtension> createFromFilter(String&& filter)
+ {
+ CompiledContentExtensionData extensionData;
+ InMemoryContentExtensionCompilationClient client(extensionData);
+ auto compilerError = ContentExtensions::compileRuleList(client, WTFMove(filter));
+ if (compilerError) {
+ // Compiling should always succeed here. We have other tests for compile failures.
+ EXPECT_TRUE(false);
+ return nullptr;
+ }
+
+ return InMemoryCompiledContentExtension::create(WTFMove(extensionData));
+ }
+
+ static RefPtr<InMemoryCompiledContentExtension> create(CompiledContentExtensionData&& data)
+ {
+ return adoptRef(new InMemoryCompiledContentExtension(WTFMove(data)));
+ }
+
+ virtual ~InMemoryCompiledContentExtension()
+ {
+ }
+
+ const ContentExtensions::SerializedActionByte* actions() const override { return m_data.actions.data(); }
+ unsigned actionsLength() const override { return m_data.actions.size(); }
+ const ContentExtensions::DFABytecode* filtersWithoutDomainsBytecode() const override { return m_data.filtersWithoutDomains.data(); }
+ unsigned filtersWithoutDomainsBytecodeLength() const override { return m_data.filtersWithoutDomains.size(); }
+ const ContentExtensions::DFABytecode* filtersWithDomainsBytecode() const override { return m_data.filtersWithDomains.data(); }
+ unsigned filtersWithDomainsBytecodeLength() const override { return m_data.filtersWithDomains.size(); }
+ const ContentExtensions::DFABytecode* domainFiltersBytecode() const override { return m_data.domainFilters.data(); }
+ unsigned domainFiltersBytecodeLength() const override { return m_data.domainFilters.size(); }
+
+private:
+ InMemoryCompiledContentExtension(CompiledContentExtensionData&& data)
+ : m_data(WTFMove(data))
+ {
+ }
+
+ CompiledContentExtensionData m_data;
+};
+
+void static testRequest(ContentExtensions::ContentExtensionsBackend contentExtensionsBackend, const ResourceLoadInfo& resourceLoadInfo, Vector<ContentExtensions::ActionType> expectedActions, bool ignorePreviousRules = false)
+{
+ auto actions = contentExtensionsBackend.actionsForResourceLoad(resourceLoadInfo);
+ unsigned expectedSize = actions.size();
+ if (!ignorePreviousRules)
+ expectedSize--; // The last action is applying the compiled stylesheet.
+
+ EXPECT_EQ(expectedActions.size(), expectedSize);
+ if (expectedActions.size() != expectedSize)
+ return;
+
+ for (unsigned i = 0; i < expectedActions.size(); ++i)
+ EXPECT_EQ(expectedActions[i], actions[i].type());
+ if (!ignorePreviousRules)
+ EXPECT_EQ(actions[actions.size() - 1].type(), ContentExtensions::ActionType::CSSDisplayNoneStyleSheet);
+}
+
+static ResourceLoadInfo mainDocumentRequest(const char* url, ResourceType resourceType = ResourceType::Document)
+{
+ return { URL(URL(), url), URL(URL(), url), resourceType };
+}
+
+static ResourceLoadInfo subResourceRequest(const char* url, const char* mainDocumentURL, ResourceType resourceType = ResourceType::Document)
+{
+ return { URL(URL(), url), URL(URL(), mainDocumentURL), resourceType };
+}
+
+ContentExtensions::ContentExtensionsBackend makeBackend(const char* json)
+{
+ AtomicString::init();
+ auto extension = InMemoryCompiledContentExtension::createFromFilter(json);
+ ContentExtensions::ContentExtensionsBackend backend;
+ backend.addContentExtension("testFilter", extension);
+ return backend;
+}
+
+static Vector<ContentExtensions::NFA> createNFAs(ContentExtensions::CombinedURLFilters& combinedURLFilters)
+{
+ Vector<ContentExtensions::NFA> nfas;
+
+ combinedURLFilters.processNFAs(std::numeric_limits<size_t>::max(), [&](ContentExtensions::NFA&& nfa) {
+ nfas.append(WTFMove(nfa));
+ });
+
+ return nfas;
+}
+
+TEST_F(ContentExtensionTest, Basic)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\"}}]");
+
+ testRequest(backend, mainDocumentRequest("http://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+}
+
+TEST_F(ContentExtensionTest, SingleCharacter)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^z\"}}]");
+ testRequest(matchBackend, mainDocumentRequest("http://webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("zttp://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"y\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("http://webkit.org/"), { });
+ testRequest(searchBackend, mainDocumentRequest("http://webkit.org/ywebkit"), { ContentExtensions::ActionType::BlockLoad });
+}
+
+TEST_F(ContentExtensionTest, SingleCharacterDisjunction)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^z\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^c\"}}]");
+ testRequest(matchBackend, mainDocumentRequest("http://webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("bttp://webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("cttp://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("dttp://webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("zttp://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"x\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"y\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("http://webkit.org/"), { });
+ testRequest(searchBackend, mainDocumentRequest("http://webkit.org/dwebkit"), { });
+ testRequest(searchBackend, mainDocumentRequest("http://webkit.org/xwebkit"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("http://webkit.org/ywebkit"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("http://webkit.org/zwebkit"), { });
+}
+
+TEST_F(ContentExtensionTest, RangeBasic)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"w[0-9]c\", \"url-filter-is-case-sensitive\":true}},"
+ "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"[A-H][a-z]cko\", \"url-filter-is-case-sensitive\":true}}]");
+
+ testRequest(backend, mainDocumentRequest("http://w3c.org"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("w2c://whatwg.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/w0c"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/wac"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/wAc"), { });
+
+ // Note: URL parsing and canonicalization lowercase the scheme and hostname.
+ testRequest(backend, mainDocumentRequest("Aacko://webkit.org"), { });
+ testRequest(backend, mainDocumentRequest("aacko://webkit.org"), { });
+ testRequest(backend, mainDocumentRequest("http://gCcko.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://gccko.org/"), { });
+
+ testRequest(backend, mainDocumentRequest("http://webkit.org/Gecko"), { ContentExtensions::ActionType::BlockCookies });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/gecko"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/GEcko"), { });
+}
+
+TEST_F(ContentExtensionTest, RangeExclusionGeneratingUniversalTransition)
+{
+ // Transition of the type ([^X]X) effictively transition on every input.
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[^a]+afoobar\"}}]");
+
+ testRequest(backend, mainDocumentRequest("http://w3c.org"), { });
+
+ testRequest(backend, mainDocumentRequest("http://w3c.org/foobafoobar"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://w3c.org/foobarfoobar"), { });
+ testRequest(backend, mainDocumentRequest("http://w3c.org/FOOBAFOOBAR"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://w3c.org/FOOBARFOOBAR"), { });
+
+ // The character before the "a" prefix cannot be another "a".
+ testRequest(backend, mainDocumentRequest("http://w3c.org/aafoobar"), { });
+ testRequest(backend, mainDocumentRequest("http://w3c.org/Aafoobar"), { });
+ testRequest(backend, mainDocumentRequest("http://w3c.org/aAfoobar"), { });
+ testRequest(backend, mainDocumentRequest("http://w3c.org/AAfoobar"), { });
+}
+
+TEST_F(ContentExtensionTest, PatternStartingWithGroup)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(http://whatwg\\\\.org/)?webkit\134\134.org\"}}]");
+
+ testRequest(backend, mainDocumentRequest("http://whatwg.org/webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://whatwg.org/webkit.org"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://whatwg.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://whatwg.org"), { });
+}
+
+TEST_F(ContentExtensionTest, PatternNestedGroups)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://webkit\\\\.org/(foo(bar)*)+\"}}]");
+
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foo"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foobar"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foobarbar"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foofoobar"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foobarfoobar"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foob"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foor"), { ContentExtensions::ActionType::BlockLoad });
+
+ testRequest(backend, mainDocumentRequest("http://webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/bar"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/fobar"), { });
+}
+
+TEST_F(ContentExtensionTest, EmptyGroups)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://webkit\\\\.org/foo()bar\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://webkit\\\\.org/((me)()(too))\"}}]");
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foo"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/bar"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foobar"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/me"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/too"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/metoo"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foome"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foomebar"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/mefoo"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/mefootoo"), { });
+}
+
+TEST_F(ContentExtensionTest, QuantifiedEmptyGroups)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://webkit\\\\.org/foo()+bar\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://webkit\\\\.org/(()*()?(target)()+)\"}}]");
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foo"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/bar"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foobar"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/me"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/too"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/target"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foome"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foomebar"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/mefoo"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/mefootoo"), { });
+}
+
+TEST_F(ContentExtensionTest, MatchPastEndOfString)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\".+\"}}]");
+
+ testRequest(backend, mainDocumentRequest("http://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foo"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foobar"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foobarbar"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foofoobar"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foobarfoobar"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foob"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foor"), { ContentExtensions::ActionType::BlockLoad });
+}
+
+TEST_F(ContentExtensionTest, StartOfLineAssertion)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^foobar\"}}]");
+
+ testRequest(backend, mainDocumentRequest("foobar://webkit.org/foobar"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("foobars:///foobar"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("foobarfoobar:///foobarfoobarfoobar"), { ContentExtensions::ActionType::BlockLoad });
+
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foobarfoo"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foobarf"), { });
+ testRequest(backend, mainDocumentRequest("http://foobar.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://foobar.org/"), { });
+}
+
+TEST_F(ContentExtensionTest, EndOfLineAssertion)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"foobar$\"}}]");
+
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foobar"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("file:///foobar"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("file:///foobarfoobarfoobar"), { ContentExtensions::ActionType::BlockLoad });
+
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foobarfoo"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foobarf"), { });
+}
+
+TEST_F(ContentExtensionTest, EndOfLineAssertionWithInvertedCharacterSet)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[^y]$\"}}]");
+
+ testRequest(backend, mainDocumentRequest("http://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/a"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foobar"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/Ya"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/yFoobar"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/y"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/Y"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foobary"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foobarY"), { });
+}
+
+TEST_F(ContentExtensionTest, DotDoesNotIncludeEndOfLine)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"https://webkit\\\\.org/.\"}}]");
+
+ testRequest(backend, mainDocumentRequest("https://webkit.org/foobar"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/A"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/z"), { ContentExtensions::ActionType::BlockLoad });
+}
+
+TEST_F(ContentExtensionTest, PrefixInfixSuffixExactMatch)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"infix\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^prefix\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"suffix$\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://exact\\\\.org/$\"}}]");
+
+ testRequest(backend, mainDocumentRequest("infix://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://infix.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/infix"), { ContentExtensions::ActionType::BlockLoad });
+
+ testRequest(backend, mainDocumentRequest("prefix://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://prefix.org/"), { });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/prefix"), { });
+
+ testRequest(backend, mainDocumentRequest("https://webkit.org/suffix"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://suffix.org/"), { });
+ testRequest(backend, mainDocumentRequest("suffix://webkit.org/"), { });
+
+ testRequest(backend, mainDocumentRequest("http://exact.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://exact.org/oops"), { });
+}
+
+TEST_F(ContentExtensionTest, DuplicatedMatchAllTermsInVariousFormat)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\".*.*(.)*(.*)(.+)*(.?)*infix\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"pre(.?)+(.+)?post\"}}]");
+
+ testRequest(backend, mainDocumentRequest("infix://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://infix.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/infix"), { ContentExtensions::ActionType::BlockLoad });
+
+ testRequest(backend, mainDocumentRequest("pre://webkit.org/post"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://prepost.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://pre.org/posttail"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://pre.pre/posttail"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://pre.org/posttailpost"), { ContentExtensions::ActionType::BlockLoad });
+
+ testRequest(backend, mainDocumentRequest("https://post.org/pre"), { });
+ testRequest(backend, mainDocumentRequest("https://pre.org/pre"), { });
+ testRequest(backend, mainDocumentRequest("https://post.org/post"), { });
+}
+
+TEST_F(ContentExtensionTest, UndistinguishableActionInsidePrefixTree)
+{
+ // In this case, the two actions are undistinguishable. The actions of "prefix" appear inside the prefixtree
+ // ending at "suffix".
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"prefix\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"prefixsuffix\"}}]");
+
+ testRequest(backend, mainDocumentRequest("http://webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://prefix.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/prefix"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/aaaprefixaaa"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://prefixsuffix.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/prefixsuffix"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/bbbprefixsuffixbbb"), { ContentExtensions::ActionType::BlockLoad });
+
+ testRequest(backend, mainDocumentRequest("http://suffix.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/suffix"), { });
+}
+
+TEST_F(ContentExtensionTest, DistinguishableActionInsidePrefixTree)
+{
+ // In this case, the two actions are distinguishable.
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"prefix\"}},"
+ "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"prefixsuffix\"}}]");
+
+ testRequest(backend, mainDocumentRequest("http://webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://prefix.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/prefix"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/aaaprefixaaa"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://prefixsuffix.org/"), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/prefixsuffix"), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/bbbprefixsuffixbbb"), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::BlockLoad });
+
+ testRequest(backend, mainDocumentRequest("http://suffix.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/suffix"), { });
+}
+
+TEST_F(ContentExtensionTest, DistinguishablePrefixAreNotMerged)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"foo\\\\.org\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"bar\\\\.org\"}}]");
+
+ testRequest(backend, mainDocumentRequest("http://webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://foo.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://bar.org/"), { ContentExtensions::ActionType::BlockLoad });
+
+ testRequest(backend, mainDocumentRequest("http://foor.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://fooar.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://fooba.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://foob.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://foor.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://foar.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://foba.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://fob.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://barf.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://barfo.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://baroo.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://baro.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://baf.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://bafo.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://baoo.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://bao.org/"), { });
+
+ testRequest(backend, mainDocumentRequest("http://foo.orgbar.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://oo.orgbar.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://o.orgbar.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://.orgbar.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://rgbar.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://gbar.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://foo.orgar.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://foo.orgr.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://foo.org.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://foo.orgorg/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://foo.orgrg/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://foo.orgg/"), { ContentExtensions::ActionType::BlockLoad });
+}
+
+static void compareContents(const ContentExtensions::DFABytecodeInterpreter::Actions& a, const Vector<uint64_t>& b)
+{
+ EXPECT_EQ(a.size(), b.size());
+ for (unsigned i = 0; i < b.size(); ++i)
+ EXPECT_TRUE(a.contains(b[i]));
+}
+
+TEST_F(ContentExtensionTest, SearchSuffixesWithIdenticalActionAreMerged)
+{
+ ContentExtensions::CombinedURLFilters combinedURLFilters;
+ ContentExtensions::URLFilterParser parser(combinedURLFilters);
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("foo\\.org", false, 0));
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("ba\\.org", false, 0));
+
+ Vector<ContentExtensions::NFA> nfas = createNFAs(combinedURLFilters);
+ EXPECT_EQ(1ul, nfas.size());
+ EXPECT_EQ(12ul, nfas.first().nodes.size());
+
+ ContentExtensions::DFA dfa = ContentExtensions::NFAToDFA::convert(nfas.first());
+ Vector<ContentExtensions::DFABytecode> bytecode;
+ ContentExtensions::DFABytecodeCompiler compiler(dfa, bytecode);
+ compiler.compile();
+ ContentExtensions::DFABytecodeInterpreter interpreter(bytecode.data(), bytecode.size());
+ compareContents(interpreter.interpret("foo.org", 0), { 0 });
+ compareContents(interpreter.interpret("ba.org", 0), { 0 });
+ compareContents(interpreter.interpret("bar.org", 0), { });
+
+ compareContents(interpreter.interpret("paddingfoo.org", 0), { 0 });
+ compareContents(interpreter.interpret("paddingba.org", 0), { 0 });
+ compareContents(interpreter.interpret("paddingbar.org", 0), { });
+}
+
+TEST_F(ContentExtensionTest, SearchSuffixesWithDistinguishableActionAreNotMerged)
+{
+ ContentExtensions::CombinedURLFilters combinedURLFilters;
+ ContentExtensions::URLFilterParser parser(combinedURLFilters);
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("foo\\.org", false, 0));
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("ba\\.org", false, 1));
+
+ Vector<ContentExtensions::NFA> nfas = createNFAs(combinedURLFilters);
+
+ EXPECT_EQ(1ul, nfas.size());
+ EXPECT_EQ(17ul, nfas.first().nodes.size());
+
+ ContentExtensions::DFA dfa = ContentExtensions::NFAToDFA::convert(nfas.first());
+ Vector<ContentExtensions::DFABytecode> bytecode;
+ ContentExtensions::DFABytecodeCompiler compiler(dfa, bytecode);
+ compiler.compile();
+ ContentExtensions::DFABytecodeInterpreter interpreter(bytecode.data(), bytecode.size());
+ compareContents(interpreter.interpret("foo.org", 0), { 0 });
+ compareContents(interpreter.interpret("ba.org", 0), { 1 });
+ compareContents(interpreter.interpret("bar.org", 0), { });
+
+ compareContents(interpreter.interpret("paddingfoo.org", 0), { 0 });
+ compareContents(interpreter.interpret("paddingba.org", 0), { 1 });
+ compareContents(interpreter.interpret("paddingba.orgfoo.org", 0), { 1, 0 });
+ compareContents(interpreter.interpret("paddingbar.org", 0), { });
+}
+
+TEST_F(ContentExtensionTest, DomainTriggers)
+{
+ auto ifDomainBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-domain\":[\"webkit.org\"]}}]");
+ testRequest(ifDomainBackend, mainDocumentRequest("http://webkit.org/test.htm"), { });
+ testRequest(ifDomainBackend, mainDocumentRequest("http://bugs.webkit.org/test.htm"), { });
+ testRequest(ifDomainBackend, mainDocumentRequest("http://webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(ifDomainBackend, mainDocumentRequest("http://bugs.webkit.org/test.html"), { });
+ testRequest(ifDomainBackend, mainDocumentRequest("http://sub2.sub1.webkit.org/test.html"), { });
+ testRequest(ifDomainBackend, mainDocumentRequest("http://not_webkit.org/test.htm"), { });
+ testRequest(ifDomainBackend, mainDocumentRequest("http://webkit.organization/test.htm"), { });
+ testRequest(ifDomainBackend, mainDocumentRequest("http://not_webkit.org/test.html"), { });
+ testRequest(ifDomainBackend, mainDocumentRequest("http://webkit.organization/test.html"), { });
+
+ auto unlessDomainBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"unless-domain\":[\"webkit.org\"]}}]");
+ testRequest(unlessDomainBackend, mainDocumentRequest("http://webkit.org/test.htm"), { });
+ testRequest(unlessDomainBackend, mainDocumentRequest("http://bugs.webkit.org/test.htm"), { });
+ testRequest(unlessDomainBackend, mainDocumentRequest("http://webkit.org/test.html"), { });
+ testRequest(unlessDomainBackend, mainDocumentRequest("http://bugs.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(unlessDomainBackend, mainDocumentRequest("http://sub2.sub1.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(unlessDomainBackend, mainDocumentRequest("http://not_webkit.org/test.htm"), { });
+ testRequest(unlessDomainBackend, mainDocumentRequest("http://webkit.organization/test.htm"), { });
+ testRequest(unlessDomainBackend, mainDocumentRequest("http://not_webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(unlessDomainBackend, mainDocumentRequest("http://webkit.organization/test.html"), { ContentExtensions::ActionType::BlockLoad });
+
+ auto ifDomainStarBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-domain\":[\"*webkit.org\"]}}]");
+ testRequest(ifDomainStarBackend, mainDocumentRequest("http://webkit.org/test.htm"), { });
+ testRequest(ifDomainStarBackend, mainDocumentRequest("http://bugs.webkit.org/test.htm"), { });
+ testRequest(ifDomainStarBackend, mainDocumentRequest("http://webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(ifDomainStarBackend, mainDocumentRequest("http://bugs.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(ifDomainStarBackend, mainDocumentRequest("http://sub2.sub1.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(ifDomainStarBackend, mainDocumentRequest("http://not_webkit.org/test.htm"), { });
+ testRequest(ifDomainStarBackend, mainDocumentRequest("http://webkit.organization/test.htm"), { });
+ testRequest(ifDomainStarBackend, mainDocumentRequest("http://not_webkit.org/test.html"), { });
+ testRequest(ifDomainStarBackend, mainDocumentRequest("http://webkit.organization/test.html"), { });
+
+ auto unlessDomainStarBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"unless-domain\":[\"*webkit.org\"]}}]");
+ testRequest(unlessDomainStarBackend, mainDocumentRequest("http://webkit.org/test.htm"), { });
+ testRequest(unlessDomainStarBackend, mainDocumentRequest("http://bugs.webkit.org/test.htm"), { });
+ testRequest(unlessDomainStarBackend, mainDocumentRequest("http://webkit.org/test.html"), { });
+ testRequest(unlessDomainStarBackend, mainDocumentRequest("http://bugs.webkit.org/test.html"), { });
+ testRequest(unlessDomainStarBackend, mainDocumentRequest("http://sub2.sub1.webkit.org/test.html"), { });
+ testRequest(unlessDomainStarBackend, mainDocumentRequest("http://not_webkit.org/test.htm"), { });
+ testRequest(unlessDomainStarBackend, mainDocumentRequest("http://webkit.organization/test.htm"), { });
+ testRequest(unlessDomainStarBackend, mainDocumentRequest("http://not_webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(unlessDomainStarBackend, mainDocumentRequest("http://webkit.organization/test.html"), { ContentExtensions::ActionType::BlockLoad });
+
+ auto ifSubDomainBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-domain\":[\"sub1.webkit.org\"]}}]");
+ testRequest(ifSubDomainBackend, mainDocumentRequest("http://webkit.org/test.html"), { });
+ testRequest(ifSubDomainBackend, mainDocumentRequest("http://bugs.webkit.org/test.html"), { });
+ testRequest(ifSubDomainBackend, mainDocumentRequest("http://sub1.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(ifSubDomainBackend, mainDocumentRequest("http://sub2.sub1.webkit.org/test.html"), { });
+
+ auto ifSubDomainStarBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-domain\":[\"*sub1.webkit.org\"]}}]");
+ testRequest(ifSubDomainStarBackend, mainDocumentRequest("http://webkit.org/test.html"), { });
+ testRequest(ifSubDomainStarBackend, mainDocumentRequest("http://bugs.webkit.org/test.html"), { });
+ testRequest(ifSubDomainStarBackend, mainDocumentRequest("http://sub1.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(ifSubDomainStarBackend, mainDocumentRequest("http://sub2.sub1.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
+
+ auto unlessSubDomainBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"unless-domain\":[\"sub1.webkit.org\"]}}]");
+ testRequest(unlessSubDomainBackend, mainDocumentRequest("http://webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(unlessSubDomainBackend, mainDocumentRequest("http://bugs.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(unlessSubDomainBackend, mainDocumentRequest("http://sub1.webkit.org/test.html"), { });
+ testRequest(unlessSubDomainBackend, mainDocumentRequest("http://sub2.sub1.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
+
+ auto unlessSubDomainStarBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"unless-domain\":[\"*sub1.webkit.org\"]}}]");
+ testRequest(unlessSubDomainStarBackend, mainDocumentRequest("http://webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(unlessSubDomainStarBackend, mainDocumentRequest("http://bugs.webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(unlessSubDomainStarBackend, mainDocumentRequest("http://sub1.webkit.org/test.html"), { });
+ testRequest(unlessSubDomainStarBackend, mainDocumentRequest("http://sub2.sub1.webkit.org/test.html"), { });
+
+ auto combinedBackend1 = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test_block_load\", \"if-domain\":[\"webkit.org\"]}},"
+ "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"test_block_cookies\", \"unless-domain\":[\"webkit.org\"]}}]");
+ testRequest(combinedBackend1, mainDocumentRequest("http://webkit.org"), { });
+ testRequest(combinedBackend1, mainDocumentRequest("http://not_webkit.org"), { });
+ testRequest(combinedBackend1, mainDocumentRequest("http://webkit.org/test_block_load.html"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(combinedBackend1, subResourceRequest("http://whatwg.org/test_block_load.html", "http://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(combinedBackend1, subResourceRequest("http://whatwg.org/shouldnt_match.html", "http://webkit.org/"), { });
+ testRequest(combinedBackend1, subResourceRequest("http://whatwg.org/test_block_load.html", "http://not_webkit.org/"), { });
+ testRequest(combinedBackend1, subResourceRequest("http://whatwg.org/shouldnt_match.html", "http://not_webkit.org/"), { });
+ testRequest(combinedBackend1, mainDocumentRequest("http://webkit.org/test_block_cookies.html"), { });
+ testRequest(combinedBackend1, subResourceRequest("http://whatwg.org/test_block_cookies.html", "http://webkit.org/"), { });
+ testRequest(combinedBackend1, subResourceRequest("http://whatwg.org/shouldnt_match.html", "http://webkit.org/"), { });
+ testRequest(combinedBackend1, subResourceRequest("http://whatwg.org/test_block_cookies.html", "http://not_webkit.org/path/to/main/document.html"), { ContentExtensions::ActionType::BlockCookies });
+ testRequest(combinedBackend1, subResourceRequest("http://whatwg.org/shouldnt_match.html", "http://not_webkit.org/"), { });
+
+ auto combinedBackend2 = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test_block_load\\\\.html\", \"if-domain\":[\"webkit.org\"]}},"
+ "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"test_block_cookies\\\\.html\", \"unless-domain\":[\"w3c.org\"]}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"test_css\\\\.html\"}}]");
+ testRequest(combinedBackend2, mainDocumentRequest("http://webkit.org/test_css.html"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(combinedBackend2, mainDocumentRequest("http://webkit.org/test_css.htm"), { });
+ testRequest(combinedBackend2, mainDocumentRequest("http://webkit.org/test_block_load.html"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(combinedBackend2, mainDocumentRequest("http://not_webkit.org/test_block_load.html"), { });
+ testRequest(combinedBackend2, mainDocumentRequest("http://not_webkit.org/test_css.html"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(combinedBackend2, mainDocumentRequest("http://webkit.org/TEST_CSS.hTmL/test_block_load.html"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad});
+ testRequest(combinedBackend2, mainDocumentRequest("http://w3c.org/test_css.html"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(combinedBackend2, mainDocumentRequest("http://w3c.org/test_block_load.html"), { });
+ testRequest(combinedBackend2, mainDocumentRequest("http://w3c.org/test_block_cookies.html"), { });
+ testRequest(combinedBackend2, mainDocumentRequest("http://w3c.org/test_css.html/test_block_cookies.html"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(combinedBackend2, mainDocumentRequest("http://not_w3c.org/test_block_cookies.html"), { ContentExtensions::ActionType::BlockCookies });
+ testRequest(combinedBackend2, mainDocumentRequest("http://not_w3c.org/test_css.html/test_block_cookies.html"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockCookies });
+
+ auto ifDomainWithFlagsBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\", \"if-domain\":[\"webkit.org\"],\"resource-type\":[\"image\"]}}]");
+ testRequest(ifDomainWithFlagsBackend, mainDocumentRequest("http://webkit.org/test.html"), { });
+ testRequest(ifDomainWithFlagsBackend, mainDocumentRequest("http://webkit.org/test.png", ResourceType::Image), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(ifDomainWithFlagsBackend, mainDocumentRequest("http://not_webkit.org/test.html"), { });
+ testRequest(ifDomainWithFlagsBackend, mainDocumentRequest("http://not_webkit.org/test.png", ResourceType::Image), { });
+
+ auto unlessDomainWithFlagsBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\", \"unless-domain\":[\"webkit.org\"],\"resource-type\":[\"image\"]}}]");
+ testRequest(unlessDomainWithFlagsBackend, mainDocumentRequest("http://webkit.org/test.html"), { });
+ testRequest(unlessDomainWithFlagsBackend, mainDocumentRequest("http://webkit.org/test.png", ResourceType::Image), { });
+ testRequest(unlessDomainWithFlagsBackend, mainDocumentRequest("http://not_webkit.org/test.html"), { });
+ testRequest(unlessDomainWithFlagsBackend, mainDocumentRequest("http://not_webkit.org/test.png", ResourceType::Image), { ContentExtensions::ActionType::BlockLoad });
+
+ // Domains should not be interepted as regular expressions.
+ auto domainRegexBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-domain\":[\"we?bkit.org\"]}}]");
+ testRequest(domainRegexBackend, mainDocumentRequest("http://webkit.org/test.html"), { });
+ testRequest(domainRegexBackend, mainDocumentRequest("http://wbkit.org/test.html"), { });
+
+ auto multipleIfDomainsBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-domain\":[\"webkit.org\", \"w3c.org\"]}}]");
+ testRequest(multipleIfDomainsBackend, mainDocumentRequest("http://webkit.org/test.htm"), { });
+ testRequest(multipleIfDomainsBackend, mainDocumentRequest("http://webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(multipleIfDomainsBackend, mainDocumentRequest("http://w3c.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(multipleIfDomainsBackend, mainDocumentRequest("http://whatwg.org/test.html"), { });
+
+ auto multipleUnlessDomainsBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"unless-domain\":[\"webkit.org\", \"w3c.org\"]}}]");
+ testRequest(multipleUnlessDomainsBackend, mainDocumentRequest("http://webkit.org/test.htm"), { });
+ testRequest(multipleUnlessDomainsBackend, mainDocumentRequest("http://webkit.org/test.html"), { });
+ testRequest(multipleUnlessDomainsBackend, mainDocumentRequest("http://w3c.org/test.html"), { });
+ testRequest(multipleUnlessDomainsBackend, mainDocumentRequest("http://whatwg.org/test.html"), { ContentExtensions::ActionType::BlockLoad });
+
+ // FIXME: Add and test domain-specific popup-only blocking (with layout tests).
+}
+
+TEST_F(ContentExtensionTest, DomainTriggersAlongMergedActions)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"test\\\\.html\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"test\\\\.html\", \"if-domain\":[\"webkit.org\"]}},"
+ "{\"action\":{\"type\":\"css-display-none\", \"selector\": \"*\"},\"trigger\":{\"url-filter\":\"trigger-on-scripts\\\\.html\",\"resource-type\":[\"script\"]}},"
+ "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"ignore-previous\",\"resource-type\":[\"image\"]}},"
+ "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"except-this\"}}]");
+
+ testRequest(backend, mainDocumentRequest("http://webkit.org/test.htm"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/test.html"), { ContentExtensions::ActionType::BlockLoad, ContentExtensions::ActionType::BlockCookies });
+ testRequest(backend, mainDocumentRequest("http://notwebkit.org/test.html"), { ContentExtensions::ActionType::BlockCookies });
+
+ testRequest(backend, mainDocumentRequest("http://notwebkit.org/trigger-on-scripts.html"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/trigger-on-scripts.html"), { });
+ testRequest(backend, mainDocumentRequest("http://notwebkit.org/trigger-on-scripts.html", ResourceType::Script), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/trigger-on-scripts.html", ResourceType::Script), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(backend, mainDocumentRequest("http://notwebkit.org/trigger-on-scripts.html.test.html", ResourceType::Script), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockCookies });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/trigger-on-scripts.html.test.html", ResourceType::Script), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad, ContentExtensions::ActionType::BlockCookies });
+
+ testRequest(backend, mainDocumentRequest("http://notwebkit.org/ignore-previous-trigger-on-scripts.html"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/ignore-previous-trigger-on-scripts.html"), { });
+ testRequest(backend, mainDocumentRequest("http://notwebkit.org/ignore-previous-trigger-on-scripts.html", ResourceType::Script), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/ignore-previous-trigger-on-scripts.html", ResourceType::Script), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(backend, mainDocumentRequest("http://notwebkit.org/ignore-previous-trigger-on-scripts.html.test.html", ResourceType::Script), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockCookies });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/ignore-previous-trigger-on-scripts.html.test.html", ResourceType::Script), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad, ContentExtensions::ActionType::BlockCookies });
+
+ testRequest(backend, mainDocumentRequest("http://notwebkit.org/ignore-previous-trigger-on-scripts.html", ResourceType::Image), { }, true);
+ testRequest(backend, mainDocumentRequest("http://webkit.org/ignore-previous-trigger-on-scripts.html", ResourceType::Image), { }, true);
+ testRequest(backend, mainDocumentRequest("http://notwebkit.org/ignore-previous-trigger-on-scripts.html.test.html", ResourceType::Image), { }, true);
+ testRequest(backend, mainDocumentRequest("http://webkit.org/ignore-previous-trigger-on-scripts.html.test.html", ResourceType::Image), { }, true);
+
+ testRequest(backend, mainDocumentRequest("http://notwebkit.org/except-this-ignore-previous-trigger-on-scripts.html"), { ContentExtensions::ActionType::BlockCookies });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/except-this-ignore-previous-trigger-on-scripts.html"), { ContentExtensions::ActionType::BlockCookies });
+ testRequest(backend, mainDocumentRequest("http://notwebkit.org/except-this-ignore-previous-trigger-on-scripts.html.test.html"), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::BlockCookies });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/except-this-ignore-previous-trigger-on-scripts.html.test.html"), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::BlockLoad, ContentExtensions::ActionType::BlockCookies });
+ testRequest(backend, mainDocumentRequest("http://notwebkit.org/except-this-ignore-previous-trigger-on-scripts.html", ResourceType::Image), { ContentExtensions::ActionType::BlockCookies }, true);
+ testRequest(backend, mainDocumentRequest("http://webkit.org/except-this-ignore-previous-trigger-on-scripts.html", ResourceType::Image), { ContentExtensions::ActionType::BlockCookies }, true);
+ testRequest(backend, mainDocumentRequest("http://notwebkit.org/except-this-ignore-previous-trigger-on-scripts.html.test.html", ResourceType::Image), { ContentExtensions::ActionType::BlockCookies }, true);
+ testRequest(backend, mainDocumentRequest("http://webkit.org/except-this-ignore-previous-trigger-on-scripts.html.test.html", ResourceType::Image), { ContentExtensions::ActionType::BlockCookies }, true);
+ testRequest(backend, mainDocumentRequest("http://notwebkit.org/except-this-ignore-previous-trigger-on-scripts.html", ResourceType::Script), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/except-this-ignore-previous-trigger-on-scripts.html", ResourceType::Script), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(backend, mainDocumentRequest("http://notwebkit.org/except-this-ignore-previous-trigger-on-scripts.html.test.html", ResourceType::Script), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockCookies });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/except-this-ignore-previous-trigger-on-scripts.html.test.html", ResourceType::Script), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad, ContentExtensions::ActionType::BlockCookies });
+
+}
+
+TEST_F(ContentExtensionTest, MultipleExtensions)
+{
+ auto extension1 = InMemoryCompiledContentExtension::createFromFilter("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"block_load\"}}]");
+ auto extension2 = InMemoryCompiledContentExtension::createFromFilter("[{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"block_cookies\"}}]");
+ ContentExtensions::ContentExtensionsBackend backend;
+ backend.addContentExtension("testFilter1", extension1);
+ backend.addContentExtension("testFilter2", extension2);
+
+ // These each have two display:none stylesheets. The second one is implied by using the default parameter ignorePreviousRules = false.
+ testRequest(backend, mainDocumentRequest("http://webkit.org"), { ContentExtensions::ActionType::CSSDisplayNoneStyleSheet });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/block_load.html"), { ContentExtensions::ActionType::CSSDisplayNoneStyleSheet, ContentExtensions::ActionType::BlockLoad});
+ testRequest(backend, mainDocumentRequest("http://webkit.org/block_cookies.html"), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::CSSDisplayNoneStyleSheet});
+ testRequest(backend, mainDocumentRequest("http://webkit.org/block_load/block_cookies.html"), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::CSSDisplayNoneStyleSheet, ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/block_cookies/block_load.html"), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::CSSDisplayNoneStyleSheet, ContentExtensions::ActionType::BlockLoad });
+
+ auto ignoreExtension1 = InMemoryCompiledContentExtension::createFromFilter("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"block_load\"}},"
+ "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"ignore1\"}}]");
+ auto ignoreExtension2 = InMemoryCompiledContentExtension::createFromFilter("[{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"block_cookies\"}},"
+ "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"ignore2\"}}]");
+ ContentExtensions::ContentExtensionsBackend backendWithIgnore;
+ backendWithIgnore.addContentExtension("testFilter1", ignoreExtension1);
+ backendWithIgnore.addContentExtension("testFilter2", ignoreExtension2);
+
+ testRequest(backendWithIgnore, mainDocumentRequest("http://webkit.org"), { ContentExtensions::ActionType::CSSDisplayNoneStyleSheet, ContentExtensions::ActionType::CSSDisplayNoneStyleSheet }, true);
+ testRequest(backendWithIgnore, mainDocumentRequest("http://webkit.org/block_load/ignore1.html"), { ContentExtensions::ActionType::CSSDisplayNoneStyleSheet }, true);
+ testRequest(backendWithIgnore, mainDocumentRequest("http://webkit.org/block_cookies/ignore1.html"), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::CSSDisplayNoneStyleSheet}, true);
+ testRequest(backendWithIgnore, mainDocumentRequest("http://webkit.org/block_load/ignore2.html"), { ContentExtensions::ActionType::BlockLoad, ContentExtensions::ActionType::CSSDisplayNoneStyleSheet }, true);
+ testRequest(backendWithIgnore, mainDocumentRequest("http://webkit.org/block_cookies/ignore2.html"), { ContentExtensions::ActionType::CSSDisplayNoneStyleSheet}, true);
+ testRequest(backendWithIgnore, mainDocumentRequest("http://webkit.org/block_load/block_cookies/ignore1/ignore2.html"), { }, true);
+}
+
+TEST_F(ContentExtensionTest, TermsKnownToMatchAnything)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre1.*post1$\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre2(.*)post2$\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre3(.*)?post3$\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre4(.*)+post4$\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre5(.*)*post5$\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre6(.)*post6$\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre7(.+)*post7$\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre8(.?)*post8$\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre9(.+)?post9$\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^pre0(.?)+post0$\"}}]");
+
+ testRequest(backend, mainDocumentRequest("pre1://webkit.org/post1"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("pre2://webkit.org/post2"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("pre3://webkit.org/post3"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("pre4://webkit.org/post4"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("pre5://webkit.org/post5"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("pre6://webkit.org/post6"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("pre7://webkit.org/post7"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("pre8://webkit.org/post8"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("pre9://webkit.org/post9"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("pre0://webkit.org/post0"), { ContentExtensions::ActionType::BlockLoad });
+
+ testRequest(backend, mainDocumentRequest("pre1://webkit.org/post2"), { });
+ testRequest(backend, mainDocumentRequest("pre2://webkit.org/post3"), { });
+ testRequest(backend, mainDocumentRequest("pre3://webkit.org/post4"), { });
+ testRequest(backend, mainDocumentRequest("pre4://webkit.org/post5"), { });
+ testRequest(backend, mainDocumentRequest("pre5://webkit.org/post6"), { });
+ testRequest(backend, mainDocumentRequest("pre6://webkit.org/post7"), { });
+ testRequest(backend, mainDocumentRequest("pre7://webkit.org/post8"), { });
+ testRequest(backend, mainDocumentRequest("pre8://webkit.org/post9"), { });
+ testRequest(backend, mainDocumentRequest("pre9://webkit.org/post0"), { });
+ testRequest(backend, mainDocumentRequest("pre0://webkit.org/post1"), { });
+
+ testRequest(backend, mainDocumentRequest("pre0://webkit.org/post1"), { });
+ testRequest(backend, mainDocumentRequest("pre1://webkit.org/post2"), { });
+ testRequest(backend, mainDocumentRequest("pre2://webkit.org/post3"), { });
+ testRequest(backend, mainDocumentRequest("pre3://webkit.org/post4"), { });
+ testRequest(backend, mainDocumentRequest("pre4://webkit.org/post5"), { });
+ testRequest(backend, mainDocumentRequest("pre5://webkit.org/post6"), { });
+ testRequest(backend, mainDocumentRequest("pre6://webkit.org/post7"), { });
+ testRequest(backend, mainDocumentRequest("pre7://webkit.org/post8"), { });
+ testRequest(backend, mainDocumentRequest("pre8://webkit.org/post9"), { });
+ testRequest(backend, mainDocumentRequest("pre9://webkit.org/post0"), { });
+}
+
+TEST_F(ContentExtensionTest, TrailingDotStar)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"foo.*$\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"bar(.*)$\"}}]");
+
+ testRequest(backend, mainDocumentRequest("https://webkit.org/"), { });
+
+ testRequest(backend, mainDocumentRequest("foo://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://foo.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://webkit.foo/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/foo"), { ContentExtensions::ActionType::BlockLoad });
+
+ testRequest(backend, mainDocumentRequest("bar://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://bar.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://webkit.bar/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/bar"), { ContentExtensions::ActionType::BlockLoad });
+}
+
+TEST_F(ContentExtensionTest, TrailingTermsCarryingNoData)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"foob?a?r?\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"bazo(ok)?a?$\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"cats*$\"}}]");
+
+ testRequest(backend, mainDocumentRequest("https://webkit.org/"), { });
+
+ // Anything is fine after foo.
+ testRequest(backend, mainDocumentRequest("https://webkit.org/foo"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/foob"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/fooc"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/fooba"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/foobar"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/foobar-stuff"), { ContentExtensions::ActionType::BlockLoad });
+
+ // Bazooka has to be at the tail without any character not defined by the filter.
+ testRequest(backend, mainDocumentRequest("https://webkit.org/baz"), { });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/bazo"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/bazoa"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/bazob"), { });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/bazoo"), { });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/bazook"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/bazookb"), { });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/bazooka"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/bazookaa"), { });
+
+ // The pattern must finish with cat, with any number of 's' following it, but no other character.
+ testRequest(backend, mainDocumentRequest("https://cat.org/"), { });
+ testRequest(backend, mainDocumentRequest("https://cats.org/"), { });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/cat"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/cats"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/catss"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/catsss"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/catso"), { });
+}
+
+TEST_F(ContentExtensionTest, UselessTermsMatchingEverythingAreEliminated)
+{
+ ContentExtensions::CombinedURLFilters combinedURLFilters;
+ ContentExtensions::URLFilterParser parser(combinedURLFilters);
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern(".*web", false, 0));
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(.*)web", false, 0));
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(.)*web", false, 0));
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(.+)*web", false, 0));
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(.?)*web", false, 0));
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(.+)?web", false, 0));
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(.?)+web", false, 0));
+
+ Vector<ContentExtensions::NFA> nfas = createNFAs(combinedURLFilters);
+ EXPECT_EQ(1ul, nfas.size());
+ EXPECT_EQ(7ul, nfas.first().nodes.size());
+
+ ContentExtensions::DFA dfa = ContentExtensions::NFAToDFA::convert(nfas.first());
+ Vector<ContentExtensions::DFABytecode> bytecode;
+ ContentExtensions::DFABytecodeCompiler compiler(dfa, bytecode);
+ compiler.compile();
+ ContentExtensions::DFABytecodeInterpreter interpreter(bytecode.data(), bytecode.size());
+ compareContents(interpreter.interpret("eb", 0), { });
+ compareContents(interpreter.interpret("we", 0), { });
+ compareContents(interpreter.interpret("weeb", 0), { });
+ compareContents(interpreter.interpret("web", 0), { 0 });
+ compareContents(interpreter.interpret("wweb", 0), { 0 });
+ compareContents(interpreter.interpret("wwebb", 0), { 0 });
+ compareContents(interpreter.interpret("http://theweb.com/", 0), { 0 });
+}
+
+TEST_F(ContentExtensionTest, LoadType)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":[\"third-party\"]}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"whatwg.org\",\"load-type\":[\"first-party\"]}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"alwaysblock.pdf\"}}]");
+
+ testRequest(backend, mainDocumentRequest("http://webkit.org"), { });
+ testRequest(backend, {URL(URL(), "http://webkit.org"), URL(URL(), "http://not_webkit.org"), ResourceType::Document}, { ContentExtensions::ActionType::BlockLoad });
+
+ testRequest(backend, mainDocumentRequest("http://whatwg.org"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, {URL(URL(), "http://whatwg.org"), URL(URL(), "http://not_whatwg.org"), ResourceType::Document}, { });
+
+ testRequest(backend, mainDocumentRequest("http://foobar.org/alwaysblock.pdf"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, {URL(URL(), "http://foobar.org/alwaysblock.pdf"), URL(URL(), "http://not_foobar.org/alwaysblock.pdf"), ResourceType::Document}, { ContentExtensions::ActionType::BlockLoad });
+}
+
+TEST_F(ContentExtensionTest, ResourceType)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"block_all_types.org\",\"resource-type\":[\"document\",\"image\",\"style-sheet\",\"script\",\"font\",\"raw\",\"svg-document\",\"media\",\"popup\"]}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"block_only_images\",\"resource-type\":[\"image\"]}}]");
+
+ testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::Document), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::Image), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::StyleSheet), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::Script), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::Font), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::Raw), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::SVGDocument), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::Media), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://block_all_types.org", ResourceType::Popup), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://block_only_images.org", ResourceType::Image), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://block_only_images.org", ResourceType::Document), { });
+}
+
+TEST_F(ContentExtensionTest, ResourceAndLoadType)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"BlockOnlyIfThirdPartyAndScript\",\"resource-type\":[\"script\"],\"load-type\":[\"third-party\"]}}]");
+
+ testRequest(backend, subResourceRequest("http://webkit.org/BlockOnlyIfThirdPartyAndScript.js", "http://webkit.org", ResourceType::Script), { });
+ testRequest(backend, subResourceRequest("http://webkit.org/BlockOnlyIfThirdPartyAndScript.png", "http://not_webkit.org", ResourceType::Image), { });
+ testRequest(backend, subResourceRequest("http://webkit.org/BlockOnlyIfThirdPartyAndScript.js", "http://not_webkit.org", ResourceType::Script), { ContentExtensions::ActionType::BlockLoad });
+}
+
+TEST_F(ContentExtensionTest, ResourceOrLoadTypeMatchingEverything)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\".*\",\"resource-type\":[\"image\"]}},"
+ "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\".*\",\"load-type\":[\"third-party\"]}},"
+ "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\".*\",\"load-type\":[\"first-party\"]}}]");
+
+ testRequest(backend, mainDocumentRequest("http://webkit.org"), { }, true);
+ testRequest(backend, {URL(URL(), "http://webkit.org"), URL(URL(), "http://not_webkit.org"), ResourceType::Document}, { ContentExtensions::ActionType::BlockCookies });
+ testRequest(backend, {URL(URL(), "http://webkit.org"), URL(URL(), "http://not_webkit.org"), ResourceType::Image}, { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::BlockLoad });
+}
+
+TEST_F(ContentExtensionTest, WideNFA)
+{
+ // Make an NFA with about 1400 nodes that won't be combined.
+ StringBuilder ruleList;
+ ruleList.append('[');
+ for (char c1 = 'A'; c1 <= 'Z'; ++c1) {
+ for (char c2 = 'A'; c2 <= 'C'; ++c2) {
+ for (char c3 = 'A'; c3 <= 'C'; ++c3) {
+ if (c1 != 'A' || c2 != 'A' || c3 != 'A')
+ ruleList.append(',');
+ ruleList.append("{\"action\":{\"type\":\"");
+
+ // Make every other rule ignore-previous-rules to not combine actions.
+ if (!((c1 + c2 + c3) % 2))
+ ruleList.append("ignore-previous-rules");
+ else {
+ ruleList.append("css-display-none");
+ ruleList.append("\",\"selector\":\"");
+ ruleList.append(c1);
+ ruleList.append(c2);
+ ruleList.append(c3);
+ }
+ ruleList.append("\"},\"trigger\":{\"url-filter\":\".*");
+ ruleList.append(c1);
+ ruleList.append(c2);
+ ruleList.append(c3);
+ ruleList.append("\", \"url-filter-is-case-sensitive\":true}}");
+ }
+ }
+ }
+ ruleList.append(']');
+
+ auto backend = makeBackend(ruleList.toString().utf8().data());
+
+ testRequest(backend, mainDocumentRequest("http://webkit.org/AAA"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/YAA"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/ZAA"), { }, true);
+ testRequest(backend, mainDocumentRequest("http://webkit.org/LAA/AAA"), { }, true);
+ testRequest(backend, mainDocumentRequest("http://webkit.org/LAA/MAA"), { ContentExtensions::ActionType::CSSDisplayNoneSelector }, true);
+ testRequest(backend, mainDocumentRequest("http://webkit.org/"), { });
+}
+
+#ifdef NDEBUG
+static uint64_t expectedIndex(char c, unsigned position)
+{
+ uint64_t index = c - 'A';
+ for (unsigned i = 1; i < position; ++i)
+ index *= (i == 1) ? ('C' - 'A' + 1) : ('Z' - 'A' + 1);
+ return index;
+}
+#endif
+
+TEST_F(ContentExtensionTest, LargeJumps)
+{
+// A large test like this is necessary to test 24 and 32 bit jumps, but it's so large it times out in debug builds.
+#ifdef NDEBUG
+ ContentExtensions::CombinedURLFilters combinedURLFilters;
+ ContentExtensions::URLFilterParser parser(combinedURLFilters);
+
+ uint64_t patternId = 0;
+ for (char c1 = 'A'; c1 <= 'Z'; ++c1) {
+ for (char c2 = 'A'; c2 <= 'Z'; ++c2) {
+ for (char c3 = 'A'; c3 <= 'Z'; ++c3) {
+ for (char c4 = 'A'; c4 <= 'C'; ++c4) {
+ StringBuilder pattern;
+ pattern.append(c1);
+ pattern.append(c2);
+ pattern.append(c3);
+ pattern.append(c4);
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern(pattern.toString(), true, patternId++));
+ }
+ }
+ }
+ }
+
+ Vector<ContentExtensions::NFA> nfas;
+ combinedURLFilters.processNFAs(std::numeric_limits<size_t>::max(), [&](ContentExtensions::NFA&& nfa) {
+ nfas.append(WTFMove(nfa));
+ });
+ EXPECT_EQ(nfas.size(), 1ull);
+
+ Vector<ContentExtensions::DFA> dfas;
+ for (auto& nfa : nfas)
+ dfas.append(ContentExtensions::NFAToDFA::convert(nfa));
+ EXPECT_EQ(dfas.size(), 1ull);
+
+ Vector<ContentExtensions::DFABytecode> combinedBytecode;
+ for (const auto& dfa : dfas) {
+ Vector<ContentExtensions::DFABytecode> bytecode;
+ ContentExtensions::DFABytecodeCompiler compiler(dfa, bytecode);
+ compiler.compile();
+ combinedBytecode.appendVector(bytecode);
+ }
+
+ ContentExtensions::DFABytecodeInterpreter interpreter(&combinedBytecode[0], combinedBytecode.size());
+
+ patternId = 0;
+ for (char c1 = 'A'; c1 <= 'Z'; ++c1) {
+ for (char c2 = 'A'; c2 <= 'Z'; ++c2) {
+ for (char c3 = 'A'; c3 <= 'Z'; ++c3) {
+ for (char c4 = 'A'; c4 <= 'C'; ++c4) {
+ StringBuilder pattern;
+ pattern.append(c1);
+ pattern.append(c2);
+ pattern.append(c3);
+ // Test different jumping patterns distributed throughout the DFA:
+ switch ((c1 + c2 + c3 + c4) % 4) {
+ case 0:
+ // This should not match.
+ pattern.append('x');
+ pattern.append(c4);
+ break;
+ case 1:
+ // This should jump back to the root, then match.
+ pattern.append('x');
+ pattern.append(c1);
+ pattern.append(c2);
+ pattern.append(c3);
+ pattern.append(c4);
+ break;
+ case 2:
+ // This should match at the end of the string.
+ pattern.append(c4);
+ break;
+ case 3:
+ // This should match then jump back to the root.
+ pattern.append(c4);
+ pattern.append('x');
+ break;
+ }
+ auto matches = interpreter.interpret(pattern.toString().utf8(), 0);
+ switch ((c1 + c2 + c3 + c4) % 4) {
+ case 0:
+ compareContents(matches, { });
+ break;
+ case 1:
+ case 2:
+ case 3:
+ compareContents(matches, {patternId});
+ break;
+ }
+ patternId++;
+ }
+ }
+ }
+ }
+
+ compareContents(interpreter.interpret("CAAAAx", 0), {expectedIndex('C', 4), expectedIndex('A', 1)});
+ compareContents(interpreter.interpret("KAAAAx", 0), {expectedIndex('K', 4), expectedIndex('A', 1)});
+ compareContents(interpreter.interpret("AKAAAx", 0), {expectedIndex('K', 3), expectedIndex('K', 4)});
+ compareContents(interpreter.interpret("AKxAAAAx", 0), {expectedIndex('A', 1)});
+ compareContents(interpreter.interpret("AKAxAAAAx", 0), {expectedIndex('A', 1)});
+ compareContents(interpreter.interpret("AKAxZKAxZKZxAAAAx", 0), {expectedIndex('A', 1)});
+ compareContents(interpreter.interpret("ZAAAA", 0), {expectedIndex('Z', 4), expectedIndex('A', 1)});
+ compareContents(interpreter.interpret("ZZxZAAAB", 0), {expectedIndex('Z', 4), expectedIndex('B', 1)});
+#endif
+}
+
+TEST_F(ContentExtensionTest, DeepNFA)
+{
+ const unsigned size = 100000;
+
+ ContentExtensions::CombinedURLFilters combinedURLFilters;
+ ContentExtensions::URLFilterParser parser(combinedURLFilters);
+
+ // FIXME: DFAToNFA::convert takes way too long on these deep NFAs. We should optimize for that case.
+
+ StringBuilder lotsOfAs;
+ for (unsigned i = 0; i < size; ++i)
+ lotsOfAs.append('A');
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern(lotsOfAs.toString().utf8().data(), false, 0));
+
+ // FIXME: Yarr ought to be able to handle 2MB regular expressions.
+ StringBuilder tooManyAs;
+ for (unsigned i = 0; i < size * 20; ++i)
+ tooManyAs.append('A');
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::YarrError, parser.addPattern(tooManyAs.toString().utf8().data(), false, 0));
+
+ StringBuilder nestedGroups;
+ for (unsigned i = 0; i < size; ++i)
+ nestedGroups.append('(');
+ for (unsigned i = 0; i < size; ++i)
+ nestedGroups.append("B)");
+ // FIXME: Add nestedGroups. Right now it also takes too long. It should be optimized.
+
+ // This should not crash and not timeout.
+ EXPECT_EQ(1ul, createNFAs(combinedURLFilters).size());
+}
+
+void checkCompilerError(const char* json, std::error_code expectedError)
+{
+ CompiledContentExtensionData extensionData;
+ InMemoryContentExtensionCompilationClient client(extensionData);
+ std::error_code compilerError = ContentExtensions::compileRuleList(client, json);
+ EXPECT_EQ(compilerError.value(), expectedError.value());
+ if (compilerError.value())
+ EXPECT_STREQ(compilerError.category().name(), expectedError.category().name());
+}
+
+TEST_F(ContentExtensionTest, MatchesEverything)
+{
+ // Only css-display-none rules with triggers that match everything, no domain rules, and no flags
+ // should go in the global display:none stylesheet. css-display-none rules with domain rules or flags
+ // are applied separately on pages where they apply.
+ auto backend1 = makeBackend("[{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\".*\"}}]");
+ EXPECT_TRUE(nullptr != backend1.globalDisplayNoneStyleSheet(ASCIILiteral("testFilter")));
+ testRequest(backend1, mainDocumentRequest("http://webkit.org"), { }); // Selector is in global stylesheet.
+
+ auto backend2 = makeBackend("[{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\".*\",\"if-domain\":[\"webkit.org\"]}}]");
+ EXPECT_EQ(nullptr, backend2.globalDisplayNoneStyleSheet(ASCIILiteral("testFilter")));
+ testRequest(backend2, mainDocumentRequest("http://webkit.org"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(backend2, mainDocumentRequest("http://w3c.org"), { });
+
+ auto backend3 = makeBackend("[{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\".*\",\"unless-domain\":[\"webkit.org\"]}}]");
+ EXPECT_EQ(nullptr, backend3.globalDisplayNoneStyleSheet(ASCIILiteral("testFilter")));
+ testRequest(backend3, mainDocumentRequest("http://webkit.org"), { });
+ testRequest(backend3, mainDocumentRequest("http://w3c.org"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+
+ auto backend4 = makeBackend("[{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\".*\",\"load-type\":[\"third-party\"]}}]");
+ EXPECT_EQ(nullptr, backend4.globalDisplayNoneStyleSheet(ASCIILiteral("testFilter")));
+ testRequest(backend4, mainDocumentRequest("http://webkit.org"), { });
+ testRequest(backend4, subResourceRequest("http://not_webkit.org", "http://webkit.org"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+
+ // css-display-none rules after ignore-previous-rules should not be put in the default stylesheet.
+ auto backend5 = makeBackend("[{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\".*\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\".*\"}}]");
+ EXPECT_EQ(nullptr, backend5.globalDisplayNoneStyleSheet(ASCIILiteral("testFilter")));
+ testRequest(backend5, mainDocumentRequest("http://webkit.org"), { ContentExtensions::ActionType::CSSDisplayNoneSelector }, true);
+
+ auto backend6 = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\".*\",\"if-domain\":[\"webkit.org\",\"*w3c.org\"],\"resource-type\":[\"document\",\"script\"]}},"
+ "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"ignore\",\"if-domain\":[\"*webkit.org\",\"w3c.org\"]}},"
+ "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\".*\",\"unless-domain\":[\"webkit.org\",\"whatwg.org\"],\"resource-type\":[\"script\",\"image\"],\"load-type\":[\"third-party\"]}}]");
+ EXPECT_EQ(nullptr, backend6.globalDisplayNoneStyleSheet(ASCIILiteral("testFilter")));
+ testRequest(backend6, mainDocumentRequest("http://webkit.org"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend6, mainDocumentRequest("http://w3c.org"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend6, mainDocumentRequest("http://whatwg.org"), { });
+ testRequest(backend6, mainDocumentRequest("http://sub.webkit.org"), { });
+ testRequest(backend6, mainDocumentRequest("http://sub.w3c.org"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend6, mainDocumentRequest("http://sub.whatwg.org"), { });
+ testRequest(backend6, mainDocumentRequest("http://webkit.org/ignore"), { }, true);
+ testRequest(backend6, mainDocumentRequest("http://w3c.org/ignore"), { }, true);
+ testRequest(backend6, mainDocumentRequest("http://whatwg.org/ignore"), { });
+ testRequest(backend6, mainDocumentRequest("http://sub.webkit.org/ignore"), { }, true);
+ testRequest(backend6, mainDocumentRequest("http://sub.w3c.org/ignore"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend6, mainDocumentRequest("http://sub.whatwg.org/ignore"), { });
+ testRequest(backend6, subResourceRequest("http://example.com/image.png", "http://webkit.org/", ResourceType::Image), { });
+ testRequest(backend6, subResourceRequest("http://example.com/image.png", "http://w3c.org/", ResourceType::Image), { ContentExtensions::ActionType::BlockCookies });
+ testRequest(backend6, subResourceRequest("http://example.com/doc.html", "http://webkit.org/", ResourceType::Document), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend6, subResourceRequest("http://example.com/script.js", "http://webkit.org/", ResourceType::Script), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend6, subResourceRequest("http://example.com/script.js", "http://w3c.org/", ResourceType::Script), { ContentExtensions::ActionType::BlockCookies, ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend6, subResourceRequest("http://example.com/script.js", "http://example.com/", ResourceType::Script), { });
+ testRequest(backend6, subResourceRequest("http://example.com/ignore/image.png", "http://webkit.org/", ResourceType::Image), { }, true);
+ testRequest(backend6, subResourceRequest("http://example.com/ignore/image.png", "http://example.com/", ResourceType::Image), { });
+ testRequest(backend6, subResourceRequest("http://example.com/ignore/image.png", "http://example.org/", ResourceType::Image), { ContentExtensions::ActionType::BlockCookies });
+ testRequest(backend6, subResourceRequest("http://example.com/doc.html", "http://example.org/", ResourceType::Document), { });
+ testRequest(backend6, subResourceRequest("http://example.com/", "http://example.com/", ResourceType::Font), { });
+ testRequest(backend6, subResourceRequest("http://example.com/ignore", "http://webkit.org/", ResourceType::Image), { }, true);
+ testRequest(backend6, subResourceRequest("http://example.com/ignore", "http://webkit.org/", ResourceType::Font), { }, true);
+ testRequest(backend6, subResourceRequest("http://example.com/", "http://example.com/", ResourceType::Script), { });
+ testRequest(backend6, subResourceRequest("http://example.com/ignore", "http://example.com/", ResourceType::Script), { });
+}
+
+TEST_F(ContentExtensionTest, InvalidJSON)
+{
+ checkCompilerError("[", ContentExtensions::ContentExtensionError::JSONInvalid);
+ checkCompilerError("123", ContentExtensions::ContentExtensionError::JSONTopLevelStructureNotAnObject);
+ checkCompilerError("{}", ContentExtensions::ContentExtensionError::JSONTopLevelStructureNotAnArray);
+ // FIXME: Add unit test for JSONInvalidRule if that is possible to hit.
+ checkCompilerError("[]", ContentExtensions::ContentExtensionError::JSONContainsNoRules);
+
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":5}]",
+ ContentExtensions::ContentExtensionError::JSONInvalidTrigger);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"\"}}]",
+ ContentExtensions::ContentExtensionError::JSONInvalidURLFilterInTrigger);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":{}}}]",
+ ContentExtensions::ContentExtensionError::JSONInvalidURLFilterInTrigger);
+
+ // FIXME: Add unit test for JSONInvalidObjectInTriggerFlagsArray if that is possible to hit.
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":{}}}]",
+ ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":[\"invalid\"]}}]",
+ ContentExtensions::ContentExtensionError::JSONInvalidStringInTriggerFlagsArray);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":[5]}}]",
+ ContentExtensions::ContentExtensionError::JSONInvalidStringInTriggerFlagsArray);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":5}}]",
+ ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":\"first-party\"}}]",
+ ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":null}}]",
+ ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"load-type\":false}}]",
+ ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"resource-type\":{}}}]",
+ ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"resource-type\":[\"invalid\"]}}]",
+ ContentExtensions::ContentExtensionError::JSONInvalidStringInTriggerFlagsArray);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"resource-type\":[5]}}]",
+ ContentExtensions::ContentExtensionError::JSONInvalidStringInTriggerFlagsArray);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"resource-type\":5}}]",
+ ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"resource-type\":\"document\"}}]",
+ ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"resource-type\":null}}]",
+ ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"resource-type\":false}}]",
+ ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
+
+ StringBuilder rules;
+ rules.append("[");
+ for (unsigned i = 0; i < 49999; ++i)
+ rules.append("{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"a\"}},");
+ String rules50000 = rules.toString();
+ String rules50001 = rules.toString();
+ rules50000.append("{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"a\"}}]");
+ rules50001.append("{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"a\"}},{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"a\"}}]");
+ checkCompilerError(rules50000.utf8().data(), { });
+ checkCompilerError(rules50001.utf8().data(), ContentExtensions::ContentExtensionError::JSONTooManyRules);
+
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":{}}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":[5]}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":[\"a\"]}}]", { });
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":\"a\"}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":false}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":null}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":{}}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":[5]}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":[\"\"]}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":\"a\"}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":null}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":false}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":[\"A\"]}}]", ContentExtensions::ContentExtensionError::JSONDomainNotLowerCaseASCII);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":[\"\\u00DC\"]}}]", ContentExtensions::ContentExtensionError::JSONDomainNotLowerCaseASCII);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":[\"0\"]}}]", { });
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":[\"a\"]}}]", { });
+
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":[],\"unless-domain\":[\"a\"]}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":[]}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":5}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"unless-domain\":5}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":5,\"unless-domain\":5}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":[]}}]", ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":[\"a\"],\"unless-domain\":[]}}]", ContentExtensions::ContentExtensionError::JSONUnlessAndIfDomain);
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\",\"if-domain\":[\"a\"],\"unless-domain\":[\"a\"]}}]", ContentExtensions::ContentExtensionError::JSONUnlessAndIfDomain);
+
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"webkit.org\", \"unexpected-identifier-should-be-ignored\":5}}]", { });
+
+ checkCompilerError("[{\"action\":5,\"trigger\":{\"url-filter\":\"webkit.org\"}}]",
+ ContentExtensions::ContentExtensionError::JSONInvalidAction);
+ checkCompilerError("[{\"action\":{\"type\":\"invalid\"},\"trigger\":{\"url-filter\":\"webkit.org\"}}]",
+ ContentExtensions::ContentExtensionError::JSONInvalidActionType);
+ checkCompilerError("[{\"action\":{\"type\":\"css-display-none\"},\"trigger\":{\"url-filter\":\"webkit.org\"}}]",
+ ContentExtensions::ContentExtensionError::JSONInvalidCSSDisplayNoneActionType);
+
+ checkCompilerError("[{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"webkit.org\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\".*\"}}]", { });
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\".*\",\"if-domain\":[\"a\"]}}]", { });
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\".*\",\"unless-domain\":[\"a\"]}}]", { });
+ checkCompilerError("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[\"}}]",
+ ContentExtensions::ContentExtensionError::JSONInvalidRegex);
+}
+
+TEST_F(ContentExtensionTest, StrictPrefixSeparatedMachines1)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^.*foo\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"bar$\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[ab]+bang\"}}]");
+
+ testRequest(backend, mainDocumentRequest("http://webkit.org/foo"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("foo://webkit.org/bar"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/bar"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("bar://webkit.org/bar"), { ContentExtensions::ActionType::BlockLoad });
+
+ testRequest(backend, mainDocumentRequest("abang://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("bbang://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("cbang://webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/bang"), { });
+ testRequest(backend, mainDocumentRequest("bang://webkit.org/"), { });
+}
+
+TEST_F(ContentExtensionTest, StrictPrefixSeparatedMachines1Partitioning)
+{
+ ContentExtensions::CombinedURLFilters combinedURLFilters;
+ ContentExtensions::URLFilterParser parser(combinedURLFilters);
+
+ // Those two share a prefix.
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("^.*foo", false, 0));
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("bar$", false, 1));
+
+ // Not this one.
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("^[ab]+bang", false, 0));
+
+ EXPECT_EQ(2ul, createNFAs(combinedURLFilters).size());
+}
+
+TEST_F(ContentExtensionTest, StrictPrefixSeparatedMachines2)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^foo\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^.*[a-c]+bar\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^webkit:\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[a-c]+b+oom\"}}]");
+
+ testRequest(backend, mainDocumentRequest("http://webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("foo://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("webkit://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+
+ testRequest(backend, mainDocumentRequest("http://bar.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://abar.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://bbar.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://cbar.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://abcbar.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://dbar.org/"), { });
+}
+
+TEST_F(ContentExtensionTest, StrictPrefixSeparatedMachines2Partitioning)
+{
+ ContentExtensions::CombinedURLFilters combinedURLFilters;
+ ContentExtensions::URLFilterParser parser(combinedURLFilters);
+
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("^foo", false, 0));
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("^.*[a-c]+bar", false, 1));
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("^webkit:", false, 2));
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("[a-c]+b+oom", false, 3));
+
+ // "^foo" and "^webkit:" can be grouped, the other two have a variable prefix.
+ EXPECT_EQ(3ul, createNFAs(combinedURLFilters).size());
+}
+
+TEST_F(ContentExtensionTest, StrictPrefixSeparatedMachines3)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"A*D\"}},"
+ "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"A*BA+\"}},"
+ "{\"action\":{\"type\":\"make-https\"},\"trigger\":{\"url-filter\":\"A*BC\"}}]");
+
+ testRequest(backend, mainDocumentRequest("http://webkit.org/D"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/AAD"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/AB"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/ABA"), { }, true);
+ testRequest(backend, mainDocumentRequest("http://webkit.org/ABAD"), { }, true);
+ testRequest(backend, mainDocumentRequest("http://webkit.org/BC"), { ContentExtensions::ActionType::MakeHTTPS });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/ABC"), { ContentExtensions::ActionType::MakeHTTPS });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/ABABC"), { ContentExtensions::ActionType::MakeHTTPS }, true);
+ testRequest(backend, mainDocumentRequest("http://webkit.org/ABABCAD"), { ContentExtensions::ActionType::MakeHTTPS }, true);
+ testRequest(backend, mainDocumentRequest("http://webkit.org/ABCAD"), { ContentExtensions::ActionType::MakeHTTPS, ContentExtensions::ActionType::BlockLoad });
+}
+
+TEST_F(ContentExtensionTest, StrictPrefixSeparatedMachines3Partitioning)
+{
+ ContentExtensions::CombinedURLFilters combinedURLFilters;
+ ContentExtensions::URLFilterParser parser(combinedURLFilters);
+
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("A*D", false, 0));
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("A*BA+", false, 1));
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("A*BC", false, 2));
+
+ // "A*A" and "A*BC" can be grouped, "A*BA+" should not.
+ EXPECT_EQ(2ul, createNFAs(combinedURLFilters).size());
+}
+
+TEST_F(ContentExtensionTest, SplittingLargeNFAs)
+{
+ const size_t expectedNFACounts[16] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1};
+
+ for (size_t i = 0; i < 16; i++) {
+ ContentExtensions::CombinedURLFilters combinedURLFilters;
+ ContentExtensions::URLFilterParser parser(combinedURLFilters);
+
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("A+BBB", false, 1));
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("A+CCC", false, 2));
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("A+DDD", false, 2));
+
+ Vector<ContentExtensions::NFA> nfas;
+ combinedURLFilters.processNFAs(i, [&](ContentExtensions::NFA&& nfa) {
+ nfas.append(WTFMove(nfa));
+ });
+ EXPECT_EQ(nfas.size(), expectedNFACounts[i]);
+
+ Vector<ContentExtensions::DFA> dfas;
+ for (auto& nfa : nfas)
+ dfas.append(ContentExtensions::NFAToDFA::convert(nfa));
+
+ Vector<ContentExtensions::DFABytecode> combinedBytecode;
+ for (const auto& dfa : dfas) {
+ Vector<ContentExtensions::DFABytecode> bytecode;
+ ContentExtensions::DFABytecodeCompiler compiler(dfa, bytecode);
+ compiler.compile();
+ combinedBytecode.appendVector(bytecode);
+ }
+
+ ContentExtensions::DFABytecodeInterpreter interpreter(&combinedBytecode[0], combinedBytecode.size());
+
+ EXPECT_EQ(interpreter.interpret("ABBBX", 0).size(), 1ull);
+ EXPECT_EQ(interpreter.interpret("ACCCX", 0).size(), 1ull);
+ EXPECT_EQ(interpreter.interpret("ADDDX", 0).size(), 1ull);
+ EXPECT_EQ(interpreter.interpret("XBBBX", 0).size(), 0ull);
+ EXPECT_EQ(interpreter.interpret("ABBX", 0).size(), 0ull);
+ EXPECT_EQ(interpreter.interpret("ACCX", 0).size(), 0ull);
+ EXPECT_EQ(interpreter.interpret("ADDX", 0).size(), 0ull);
+ }
+}
+
+TEST_F(ContentExtensionTest, QuantifierInGroup)
+{
+ ContentExtensions::CombinedURLFilters combinedURLFilters;
+ ContentExtensions::URLFilterParser parser(combinedURLFilters);
+
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(((A+)B)C)", false, 0));
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(((A)B+)C)", false, 1));
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(((A)B+)C)D", false, 2));
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(((A)B)C+)", false, 3));
+ EXPECT_EQ(ContentExtensions::URLFilterParser::ParseStatus::Ok, parser.addPattern("(((A)B)C)", false, 4));
+
+ // (((A)B+)C) and (((A)B+)C)D should be in the same NFA.
+ EXPECT_EQ(4ul, createNFAs(combinedURLFilters).size());
+}
+
+static void testPatternStatus(String pattern, ContentExtensions::URLFilterParser::ParseStatus status)
+{
+ ContentExtensions::CombinedURLFilters combinedURLFilters;
+ ContentExtensions::URLFilterParser parser(combinedURLFilters);
+ EXPECT_EQ(status, parser.addPattern(pattern, false, 0));
+}
+
+TEST_F(ContentExtensionTest, ParsingFailures)
+{
+ testPatternStatus("a*b?.*.?[a-z]?[a-z]*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
+ testPatternStatus("a*b?.*.?[a-z]?[a-z]+", ContentExtensions::URLFilterParser::ParseStatus::Ok);
+ testPatternStatus("a*b?.*.?[a-z]?[a-z]", ContentExtensions::URLFilterParser::ParseStatus::Ok);
+ testPatternStatus(".*?a", ContentExtensions::URLFilterParser::ParseStatus::Ok);
+ testPatternStatus(".*a", ContentExtensions::URLFilterParser::ParseStatus::Ok);
+
+ testPatternStatus("(?!)", ContentExtensions::URLFilterParser::ParseStatus::Group);
+ testPatternStatus("(?=)", ContentExtensions::URLFilterParser::ParseStatus::Group);
+ testPatternStatus("(?!a)", ContentExtensions::URLFilterParser::ParseStatus::Group);
+ testPatternStatus("(?=a)", ContentExtensions::URLFilterParser::ParseStatus::Group);
+ testPatternStatus("(regex)", ContentExtensions::URLFilterParser::ParseStatus::Ok);
+ testPatternStatus("(regex", ContentExtensions::URLFilterParser::ParseStatus::YarrError);
+ testPatternStatus("((regex)", ContentExtensions::URLFilterParser::ParseStatus::YarrError);
+ testPatternStatus("(?:regex)", ContentExtensions::URLFilterParser::ParseStatus::Ok);
+ testPatternStatus("(?:regex", ContentExtensions::URLFilterParser::ParseStatus::YarrError);
+ testPatternStatus("[^.]+", ContentExtensions::URLFilterParser::ParseStatus::Ok);
+
+ testPatternStatus("a++", ContentExtensions::URLFilterParser::ParseStatus::YarrError);
+ testPatternStatus("[a]++", ContentExtensions::URLFilterParser::ParseStatus::YarrError);
+ testPatternStatus("+", ContentExtensions::URLFilterParser::ParseStatus::YarrError);
+
+ testPatternStatus("[", ContentExtensions::URLFilterParser::ParseStatus::YarrError);
+ testPatternStatus("[a}", ContentExtensions::URLFilterParser::ParseStatus::YarrError);
+
+ // FIXME: Look into why these do not cause YARR parsing errors. They probably should.
+ testPatternStatus("a]", ContentExtensions::URLFilterParser::ParseStatus::Ok);
+ testPatternStatus("{", ContentExtensions::URLFilterParser::ParseStatus::Ok);
+ testPatternStatus("{[a]", ContentExtensions::URLFilterParser::ParseStatus::Ok);
+ testPatternStatus("{0", ContentExtensions::URLFilterParser::ParseStatus::Ok);
+ testPatternStatus("{0,", ContentExtensions::URLFilterParser::ParseStatus::Ok);
+ testPatternStatus("{0,1", ContentExtensions::URLFilterParser::ParseStatus::Ok);
+ testPatternStatus("a{0,1", ContentExtensions::URLFilterParser::ParseStatus::Ok);
+ testPatternStatus("a{a,b}", ContentExtensions::URLFilterParser::ParseStatus::Ok);
+
+ const char nonASCII[2] = {-1, '\0'};
+ testPatternStatus(nonASCII, ContentExtensions::URLFilterParser::ParseStatus::NonASCII);
+ testPatternStatus("\\xff", ContentExtensions::URLFilterParser::ParseStatus::NonASCII);
+
+ testPatternStatus("\\x\\r\\n", ContentExtensions::URLFilterParser::ParseStatus::Ok);
+ testPatternStatus("\\b", ContentExtensions::URLFilterParser::ParseStatus::WordBoundary);
+ testPatternStatus("[\\d]", ContentExtensions::URLFilterParser::ParseStatus::AtomCharacter);
+ testPatternStatus("\\d\\D\\w\\s\\v\\h\\i\\c", ContentExtensions::URLFilterParser::ParseStatus::UnsupportedCharacterClass);
+
+ testPatternStatus("this|that", ContentExtensions::URLFilterParser::ParseStatus::Disjunction);
+ testPatternStatus("a{0,1}b", ContentExtensions::URLFilterParser::ParseStatus::Ok);
+ testPatternStatus("a{0,2}b", ContentExtensions::URLFilterParser::ParseStatus::InvalidQuantifier);
+ testPatternStatus("", ContentExtensions::URLFilterParser::ParseStatus::EmptyPattern);
+ testPatternStatus("$$", ContentExtensions::URLFilterParser::ParseStatus::MisplacedEndOfLine);
+ testPatternStatus("a^", ContentExtensions::URLFilterParser::ParseStatus::MisplacedStartOfLine);
+ testPatternStatus("(^)", ContentExtensions::URLFilterParser::ParseStatus::MisplacedStartOfLine);
+
+ testPatternStatus("(a)\\1", ContentExtensions::URLFilterParser::ParseStatus::Ok); // This should be BackReference, right?
+}
+
+TEST_F(ContentExtensionTest, PatternMatchingTheEmptyString)
+{
+ // Simple atoms.
+ testPatternStatus(".*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
+ testPatternStatus("a*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
+ testPatternStatus(".?", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
+ testPatternStatus("a?", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
+
+ // Character sets.
+ testPatternStatus("[a-z]*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
+ testPatternStatus("[a-z]?", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
+
+ // Groups.
+ testPatternStatus("(foobar)*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
+ testPatternStatus("(foobar)?", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
+ testPatternStatus("(.*)", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
+ testPatternStatus("(a*)", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
+ testPatternStatus("(.?)", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
+ testPatternStatus("(a?)", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
+ testPatternStatus("([a-z]*)", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
+ testPatternStatus("([a-z]?)", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
+
+ testPatternStatus("(.)*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
+ testPatternStatus("(.+)*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
+ testPatternStatus("(.?)*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
+ testPatternStatus("(.*)*", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
+ testPatternStatus("(.+)?", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
+ testPatternStatus("(.?)+", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
+
+ // Nested groups.
+ testPatternStatus("((foo)?((.)*)(bar)*)", ContentExtensions::URLFilterParser::ParseStatus::MatchesEverything);
+}
+
+TEST_F(ContentExtensionTest, MinimizingWithMoreFinalStatesThanNonFinalStates)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^h[a-z://]+\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://foo.com/\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://bar.com/\"}}]");
+
+ testRequest(backend, mainDocumentRequest("http://foo.com/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("http://bar.com/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("attp://foo.com/"), { });
+ testRequest(backend, mainDocumentRequest("attp://bar.com/"), { });
+
+ testRequest(backend, mainDocumentRequest("http://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("bttp://webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("bttps://webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("http://webkit.org/b"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://webkit.org/b"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("cttp://webkit.org/B"), { });
+ testRequest(backend, mainDocumentRequest("cttps://webkit.org/B"), { });
+}
+
+TEST_F(ContentExtensionTest, StatesWithDifferentActionsAreNotUnified1)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://www.webkit.org/\"}},"
+ "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"^https://www.webkit.org/\"}},"
+ "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"^attps://www.webkit.org/\"}}]");
+
+ testRequest(backend, mainDocumentRequest("http://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://www.webkit.org/"), { ContentExtensions::ActionType::BlockCookies });
+ testRequest(backend, mainDocumentRequest("attps://www.webkit.org/"), { ContentExtensions::ActionType::BlockCookies });
+ testRequest(backend, mainDocumentRequest("http://www.webkit.org/a"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://www.webkit.org/B"), { ContentExtensions::ActionType::BlockCookies });
+ testRequest(backend, mainDocumentRequest("attps://www.webkit.org/c"), { ContentExtensions::ActionType::BlockCookies });
+ testRequest(backend, mainDocumentRequest("http://www.whatwg.org/"), { });
+ testRequest(backend, mainDocumentRequest("https://www.whatwg.org/"), { });
+ testRequest(backend, mainDocumentRequest("attps://www.whatwg.org/"), { });
+}
+
+TEST_F(ContentExtensionTest, StatesWithDifferentActionsAreNotUnified2)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^http://www.webkit.org/\"}},"
+ "{\"action\":{\"type\":\"block-cookies\"},\"trigger\":{\"url-filter\":\"^https://www.webkit.org/\"}},"
+ "{\"action\":{\"type\":\"css-display-none\", \"selector\":\"#foo\"},\"trigger\":{\"url-filter\":\"^https://www.webkit.org/\"}}]");
+
+ testRequest(backend, mainDocumentRequest("http://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("https://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockCookies });
+ testRequest(backend, mainDocumentRequest("https://www.whatwg.org/"), { });
+ testRequest(backend, mainDocumentRequest("attps://www.whatwg.org/"), { });
+}
+
+// The order in which transitions from the root will be processed is unpredictable.
+// To exercises the various options, this test exists in various version exchanging the transition to the final state.
+TEST_F(ContentExtensionTest, FallbackTransitionsWithDifferentiatorDoNotMerge1)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^a.a\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^b.a\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^bac\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^bbc\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^BCC\"}}]");
+
+ testRequest(backend, mainDocumentRequest("aza://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("bza://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("bac://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("bbc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("bcc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+
+ testRequest(backend, mainDocumentRequest("aac://www.webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("abc://www.webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("acc://www.webkit.org/"), { });
+
+ testRequest(backend, mainDocumentRequest("bzc://www.webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("bzc://www.webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("bzc://www.webkit.org/"), { });
+}
+TEST_F(ContentExtensionTest, FallbackTransitionsWithDifferentiatorDoNotMerge2)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^bac\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^bbc\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^BCC\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^a.a\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^b.a\"}}]");
+
+ testRequest(backend, mainDocumentRequest("aza://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("bza://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("bac://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("bbc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("bcc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+
+ testRequest(backend, mainDocumentRequest("aac://www.webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("abc://www.webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("acc://www.webkit.org/"), { });
+
+ testRequest(backend, mainDocumentRequest("bzc://www.webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("bzc://www.webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("bzc://www.webkit.org/"), { });
+}
+TEST_F(ContentExtensionTest, FallbackTransitionsWithDifferentiatorDoNotMerge3)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^a.c\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^b.c\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^baa\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^bba\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^BCA\"}}]");
+
+ testRequest(backend, mainDocumentRequest("azc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("bzc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("baa://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("bba://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("bca://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+
+ testRequest(backend, mainDocumentRequest("aaa://www.webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("aba://www.webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("aca://www.webkit.org/"), { });
+
+ testRequest(backend, mainDocumentRequest("bza://www.webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("bza://www.webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("bza://www.webkit.org/"), { });
+}
+TEST_F(ContentExtensionTest, FallbackTransitionsWithDifferentiatorDoNotMerge4)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^baa\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^bba\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^BCA\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^a.c\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^b.c\"}}]");
+
+ testRequest(backend, mainDocumentRequest("azc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("bzc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("baa://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("bba://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("bca://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+
+ testRequest(backend, mainDocumentRequest("aaa://www.webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("aba://www.webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("aca://www.webkit.org/"), { });
+
+ testRequest(backend, mainDocumentRequest("bza://www.webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("bza://www.webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("bza://www.webkit.org/"), { });
+}
+
+TEST_F(ContentExtensionTest, FallbackTransitionsToOtherNodeInSameGroupDoesNotDifferentiateGroup)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^aac\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^a.c\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^b.c\"}}]");
+
+ testRequest(backend, mainDocumentRequest("aac://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("abc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("bac://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("abc://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+
+ testRequest(backend, mainDocumentRequest("aaa://www.webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("aca://www.webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("baa://www.webkit.org/"), { });
+}
+
+TEST_F(ContentExtensionTest, SimpleFallBackTransitionDifferentiator1)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^a.bc.de\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^a.bd.ef\"}}]");
+
+ testRequest(backend, mainDocumentRequest("abbccde://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("aabcdde://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("aabddef://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("aabddef://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+
+ testRequest(backend, mainDocumentRequest("abcde://www.webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("abdef://www.webkit.org/"), { });
+}
+
+TEST_F(ContentExtensionTest, SimpleFallBackTransitionDifferentiator2)
+{
+ auto backend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^cb.\"}},"
+ "{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^db.b\"}}]");
+
+ testRequest(backend, mainDocumentRequest("cba://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("cbb://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("dbab://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(backend, mainDocumentRequest("dbxb://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+
+ testRequest(backend, mainDocumentRequest("cca://www.webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("dddd://www.webkit.org/"), { });
+ testRequest(backend, mainDocumentRequest("bbbb://www.webkit.org/"), { });
+}
+
+// *** We have the following ranges intersections: ***
+// Full overlap.
+// 1)
+// A: |-----|
+// B: |---|
+// 2)
+// A: |-----|
+// B: |
+// 3)
+// A: |---|
+// B: |-----|
+// 4)
+// A: |
+// B: |-----|
+// One edge in common
+// 5)
+// A: |-|
+// B: |-|
+// 6)
+// A: |
+// B: |-|
+// 7)
+// A: |-|
+// B: |
+// 8)
+// A: |-|
+// B: |-|
+// 9)
+// A: |
+// B: |-|
+// 10)
+// A: |-|
+// B: |
+// B overlap on the left side of A.
+// 11)
+// A: |---|
+// B: |---|
+// 12)
+// A: |---|
+// B: |-----|
+// A overlap on the left side of B
+// 13)
+// A: |---|
+// B: |---|
+// 14)
+// A: |-----|
+// B: |---|
+// Equal ranges
+// 15)
+// A: |---|
+// B: |---|
+// 16)
+// A: |
+// B: |
+
+TEST_F(ContentExtensionTest, RangeOverlapCase1)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[a-m]\"}},"
+ "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"^[c-e]\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { }, true);
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { }, true);
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { }, true);
+ testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("m://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("n://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[a-m]\"}},"
+ "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"[c-e]\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.b.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { }, true);
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { }, true);
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { }, true);
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.m.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.n.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, RangeOverlapCase2)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[a-m]\"}},"
+ "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"^b\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { }, true);
+ testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("m://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("n://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[a-m]\"}},"
+ "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"l\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.k.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.l.xxx/"), { }, true);
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.m.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.n.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, RangeOverlapCase3)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[b-d]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^[a-m]\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("m://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("n://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[b-d]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[a-m]\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.b.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.m.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.n.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, RangeOverlapCase4)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^l\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^[a-m]\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("k://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("l://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("m://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("n://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"l\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[a-m]\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.k.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.l.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.m.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.n.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, RangeOverlapCase5)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[a-e]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^[e-h]\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("i://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[a-e]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[e-h]\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.i.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, RangeOverlapCase6)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^e\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^[e-h]\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("i://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"e\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[e-h]\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.i.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, RangeOverlapCase7)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[a-e]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^e\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[a-e]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"e\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, RangeOverlapCase8)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[e-h]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^[a-e]\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("i://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[e-h]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[a-e]\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.i.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, RangeOverlapCase9)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^e\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^[a-e]\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"e\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[a-e]\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, RangeOverlapCase10)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[e-h]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^e\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("i://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[e-h]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"e\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.i.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, RangeOverlapCase11)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[e-g]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^[d-f]\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("g://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[e-g]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[d-f]\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.g.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { });
+}
+
+
+TEST_F(ContentExtensionTest, RangeOverlapCase12)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[e-g]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^[d-g]\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("g://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[e-g]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[d-g]\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.g.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, RangeOverlapCase13)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[b-d]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^[c-e]\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[b-d]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[c-e]\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.b.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, RangeOverlapCase14)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[b-e]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^[c-e]\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[b-e]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[c-e]\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.b.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, RangeOverlapCase15)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^[c-f]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^[c-f]\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("g://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[c-f]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[c-f]\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.b.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.g.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, RangeOverlapCase16)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^c\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^c\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"c\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"c\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.b.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, QuantifiedOneOrMoreRangesCase11And13)
+{
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"[c-e]+[g-i]+YYY\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[b-d]+[h-j]+YYY\"}}]");
+
+ // The interesting ranges only match between 'b' and 'k', plus a gap in 'f'.
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.aayyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.abyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.acyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.adyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.aeyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.afyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.agyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ahyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.aiyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ajyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.akyyy.xxx/"), { });
+
+ // 'b' is the first character of the second rule.
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.byyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bayyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bbyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bcyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bdyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.beyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bfyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bgyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bhyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.biyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bjyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bkyyy.xxx/"), { });
+
+ // 'c' is the first character of the first rule, and it overlaps the first character of the second rule.
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cayyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cbyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ccyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cdyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ceyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cfyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cgyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.chyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ciyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cjyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ckyyy.xxx/"), { });
+
+ // 'd' is in the first range of both rule. This series cover overlaps between the two rules.
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.dgyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ddgyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ddhyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ddhhyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.degyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.dehyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.dfgyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.dfhyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.djyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ddjyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ddjjyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+}
+
+TEST_F(ContentExtensionTest, QuantifiedOneOrMoreRangesCase11And13InGroups)
+{
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"([c-e])+([g-i]+YYY)\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"[b-d]+[h-j]+YYY\"}}]");
+
+ // The interesting ranges only match between 'b' and 'k', plus a gap in 'f'.
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.aayyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.abyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.acyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.adyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.aeyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.afyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.agyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ahyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.aiyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ajyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.akyyy.xxx/"), { });
+
+ // 'b' is the first character of the second rule.
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.byyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bayyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bbyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bcyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bdyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.beyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bfyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bgyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bhyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.biyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bjyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bkyyy.xxx/"), { });
+
+ // 'c' is the first character of the first rule, and it overlaps the first character of the second rule.
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cayyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cbyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ccyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cdyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ceyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cfyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cgyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.chyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ciyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cjyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ckyyy.xxx/"), { });
+
+ // 'd' is in the first range of both rule. This series cover overlaps between the two rules.
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.dgyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ddgyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ddhyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ddhhyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.degyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.dehyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.dfgyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.dfhyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.djyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ddjyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ddjjyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+}
+
+TEST_F(ContentExtensionTest, CombinedRangeOverlapCase1)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*[a-m]\"}},"
+ "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"^(bar)*[c-e]\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { }, true);
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { }, true);
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { }, true);
+ testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("m://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("n://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*[a-m]\"}},"
+ "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"(bar)*[c-e]\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.b.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { }, true);
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { }, true);
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { }, true);
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.m.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.n.xxx/"), { });
+}
+
+
+TEST_F(ContentExtensionTest, CombinedRangeOverlapCase2)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*[a-m]\"}},"
+ "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"^(bar)*b\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { }, true);
+ testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("m://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("n://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*[a-m]\"}},"
+ "{\"action\":{\"type\":\"ignore-previous-rules\"},\"trigger\":{\"url-filter\":\"(bar)*l\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.k.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.l.xxx/"), { }, true);
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.m.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.n.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, CombinedRangeOverlapCase3)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*[b-d]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*[a-m]\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("m://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("n://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*[b-d]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*[a-m]\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.b.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.m.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.n.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, CombinedRangeOverlapCase4)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*l\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*[a-m]\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("k://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("l://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("m://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("n://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*l\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*[a-m]\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.k.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.l.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.m.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.n.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, CombinedRangeOverlapCase5)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*[a-e]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*[e-h]\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("i://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*[a-e]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*[e-h]\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.i.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, CombinedRangeOverlapCase6)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*e\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*[e-h]\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("i://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*e\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*[e-h]\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.i.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, CombinedRangeOverlapCase7)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*[a-e]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*e\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*[a-e]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*e\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, CombinedRangeOverlapCase8)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*[e-h]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*[a-e]\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("i://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*[e-h]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*[a-e]\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.i.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, CombinedRangeOverlapCase9)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*e\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*[a-e]\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*e\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*[a-e]\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, CombinedRangeOverlapCase10)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*[e-h]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*e\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("i://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*[e-h]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*e\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.i.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, CombinedRangeOverlapCase11)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*[e-g]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*[d-f]\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("g://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*[e-g]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*[d-f]\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.g.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { });
+}
+
+
+TEST_F(ContentExtensionTest, CombinedRangeOverlapCase12)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*[e-g]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*[d-g]\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("g://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*[e-g]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*[d-g]\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.g.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, CombinedRangeOverlapCase13)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*[b-d]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*[c-e]\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*[b-d]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*[c-e]\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.b.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, CombinedRangeOverlapCase14)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*[b-e]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*[c-e]\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("h://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*[b-e]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*[c-e]\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.b.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.h.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, CombinedRangeOverlapCase15)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*[c-f]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*[c-f]\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("f://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("g://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*[c-f]\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*[c-f]\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.b.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.f.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.g.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, CombinedRangeOverlapCase16)
+{
+ auto matchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"^(foo)*c\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"^(bar)*c\"}}]");
+
+ testRequest(matchBackend, mainDocumentRequest("a://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("b://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("c://www.webkit.org/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(matchBackend, mainDocumentRequest("d://www.webkit.org/"), { });
+ testRequest(matchBackend, mainDocumentRequest("e://www.webkit.org/"), { });
+
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*c\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*c\"}}]");
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.a.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.b.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.c.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.d.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.e.xxx/"), { });
+}
+
+TEST_F(ContentExtensionTest, CombinedQuantifiedOneOrMoreRangesCase11And13)
+{
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*[c-e]+[g-i]+YYY\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*[b-d]+[h-j]+YYY\"}}]");
+
+ // The interesting ranges only match between 'b' and 'k', plus a gap in 'f'.
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.aayyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.abyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.acyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.adyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.aeyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.afyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.agyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ahyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.aiyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ajyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.akyyy.xxx/"), { });
+
+ // 'b' is the first character of the second rule.
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.byyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bayyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bbyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bcyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bdyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.beyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bfyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bgyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bhyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.biyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bjyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bkyyy.xxx/"), { });
+
+ // 'c' is the first character of the first rule, and it overlaps the first character of the second rule.
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cayyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cbyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ccyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cdyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ceyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cfyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cgyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.chyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ciyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cjyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ckyyy.xxx/"), { });
+
+ // 'd' is in the first range of both rule. This series cover overlaps between the two rules.
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.dgyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ddgyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ddhyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ddhhyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.degyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.dehyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.dfgyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.dfhyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.djyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ddjyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ddjjyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+}
+
+TEST_F(ContentExtensionTest, CombinedQuantifiedOneOrMoreRangesCase11And13InGroups)
+{
+ auto searchBackend = makeBackend("[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\"(foo)*([c-e])+([g-i]+YYY)\"}},"
+ "{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\"(bar)*[b-d]+[h-j]+YYY\"}}]");
+
+ // The interesting ranges only match between 'b' and 'k', plus a gap in 'f'.
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.aayyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.abyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.acyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.adyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.aeyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.afyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.agyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ahyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.aiyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ajyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.akyyy.xxx/"), { });
+
+ // 'b' is the first character of the second rule.
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.byyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bayyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bbyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bcyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bdyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.beyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bfyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bgyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bhyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.biyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bjyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.bkyyy.xxx/"), { });
+
+ // 'c' is the first character of the first rule, and it overlaps the first character of the second rule.
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cayyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cbyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ccyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cdyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ceyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cfyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cgyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.chyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ciyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.cjyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ckyyy.xxx/"), { });
+
+ // 'd' is in the first range of both rule. This series cover overlaps between the two rules.
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.dgyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ddgyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ddhyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ddhhyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.degyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.dehyyy.xxx/"), { ContentExtensions::ActionType::BlockLoad });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.dfgyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.dfhyyy.xxx/"), { });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.djyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ddjyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+ testRequest(searchBackend, mainDocumentRequest("zzz://www.ddjjyyy.xxx/"), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/DFACombiner.cpp b/Tools/TestWebKitAPI/Tests/WebCore/DFACombiner.cpp
new file mode 100644
index 000000000..d53ebb75a
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/DFACombiner.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "DFAHelpers.h"
+#include <WebCore/DFACombiner.h>
+#include <wtf/MainThread.h>
+
+using namespace WebCore;
+using namespace ContentExtensions;
+
+namespace TestWebKitAPI {
+
+class DFACombinerTest : public testing::Test {
+public:
+ virtual void SetUp()
+ {
+ WTF::initializeMainThread();
+ }
+};
+
+Vector<DFA> combine(Vector<DFA> dfas, unsigned minimumSize)
+{
+ DFACombiner combiner;
+ for (DFA& dfa : dfas)
+ combiner.addDFA(WTFMove(dfa));
+
+ Vector<DFA> output;
+ combiner.combineDFAs(minimumSize, [&output](DFA&& dfa) {
+ output.append(dfa);
+ });
+ return output;
+}
+
+TEST_F(DFACombinerTest, Basic)
+{
+ Vector<DFA> dfas = { buildDFAFromPatterns({ "foo"}), buildDFAFromPatterns({ "bar"}) };
+ Vector<DFA> combinedDFAs = combine(dfas, 10000);
+ EXPECT_EQ(static_cast<size_t>(1), combinedDFAs.size());
+
+ DFA reference = buildDFAFromPatterns({ "foo", "bar"});
+ reference.minimize();
+ EXPECT_EQ(countLiveNodes(reference), countLiveNodes(combinedDFAs.first()));
+}
+
+
+TEST_F(DFACombinerTest, IdenticalDFAs)
+{
+ Vector<DFA> dfas = { buildDFAFromPatterns({ "foo"}), buildDFAFromPatterns({ "foo"}) };
+ Vector<DFA> combinedDFAs = combine(dfas, 10000);
+ EXPECT_EQ(static_cast<size_t>(1), combinedDFAs.size());
+
+ // The result should have the exact same size as the minimized input.
+ DFA reference = buildDFAFromPatterns({ "foo"});
+ reference.minimize();
+ EXPECT_EQ(countLiveNodes(reference), countLiveNodes(combinedDFAs.first()));
+}
+
+TEST_F(DFACombinerTest, NoInput)
+{
+ DFACombiner combiner;
+ unsigned counter = 0;
+ combiner.combineDFAs(100000, [&counter](DFA&& dfa) {
+ ++counter;
+ });
+ EXPECT_EQ(static_cast<unsigned>(0), counter);
+}
+
+TEST_F(DFACombinerTest, SingleInput)
+{
+ Vector<DFA> dfas = { buildDFAFromPatterns({ "WebKit"}) };
+ Vector<DFA> combinedDFAs = combine(dfas, 10000);
+ EXPECT_EQ(static_cast<size_t>(1), combinedDFAs.size());
+
+ DFA reference = buildDFAFromPatterns({ "WebKit"});
+ reference.minimize();
+ EXPECT_EQ(countLiveNodes(reference), countLiveNodes(combinedDFAs.first()));
+}
+
+TEST_F(DFACombinerTest, InputTooLargeForMinimumSize)
+{
+ Vector<DFA> dfas = { buildDFAFromPatterns({ "foo"}), buildDFAFromPatterns({ "bar"}) };
+ Vector<DFA> combinedDFAs = combine(dfas, 2);
+ EXPECT_EQ(static_cast<size_t>(2), combinedDFAs.size());
+ EXPECT_EQ(static_cast<size_t>(4), countLiveNodes(combinedDFAs[0]));
+ EXPECT_EQ(static_cast<size_t>(4), countLiveNodes(combinedDFAs[1]));
+}
+
+TEST_F(DFACombinerTest, CombinedInputReachesMinimumSize)
+{
+ Vector<DFA> dfas = { buildDFAFromPatterns({ "foo"}), buildDFAFromPatterns({ "bar"}), buildDFAFromPatterns({ "WebKit"}) };
+ Vector<DFA> combinedDFAs = combine(dfas, 5);
+ EXPECT_EQ(static_cast<size_t>(2), combinedDFAs.size());
+ EXPECT_EQ(static_cast<size_t>(7), countLiveNodes(combinedDFAs[0]));
+ EXPECT_EQ(static_cast<size_t>(6), countLiveNodes(combinedDFAs[1]));
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/DFAHelpers.h b/Tools/TestWebKitAPI/Tests/WebCore/DFAHelpers.h
new file mode 100644
index 000000000..8c6402760
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/DFAHelpers.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <WebCore/CombinedURLFilters.h>
+#include <WebCore/NFA.h>
+#include <WebCore/NFAToDFA.h>
+#include <WebCore/URLFilterParser.h>
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+static unsigned countLiveNodes(const ContentExtensions::DFA& dfa)
+{
+ unsigned counter = 0;
+ for (const auto& node : dfa.nodes) {
+ if (!node.isKilled())
+ ++counter;
+ }
+ return counter;
+}
+
+static Vector<ContentExtensions::NFA> createNFAs(ContentExtensions::CombinedURLFilters& combinedURLFilters)
+{
+ Vector<ContentExtensions::NFA> nfas;
+
+ combinedURLFilters.processNFAs(std::numeric_limits<size_t>::max(), [&](ContentExtensions::NFA&& nfa) {
+ nfas.append(WTFMove(nfa));
+ });
+
+ return nfas;
+}
+
+static ContentExtensions::DFA buildDFAFromPatterns(Vector<const char*> patterns)
+{
+ ContentExtensions::CombinedURLFilters combinedURLFilters;
+ ContentExtensions::URLFilterParser parser(combinedURLFilters);
+
+ for (const char* pattern : patterns)
+ parser.addPattern(pattern, false, 0);
+ Vector<ContentExtensions::NFA> nfas = createNFAs(combinedURLFilters);
+ return ContentExtensions::NFAToDFA::convert(nfas[0]);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/DFAMinimizer.cpp b/Tools/TestWebKitAPI/Tests/WebCore/DFAMinimizer.cpp
new file mode 100644
index 000000000..bb3ac2e2a
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/DFAMinimizer.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "DFAHelpers.h"
+#include <wtf/MainThread.h>
+
+namespace TestWebKitAPI {
+
+class DFAMinimizerTest : public testing::Test {
+public:
+ virtual void SetUp()
+ {
+ WTF::initializeMainThread();
+ }
+};
+
+TEST_F(DFAMinimizerTest, BasicSearch)
+{
+ ContentExtensions::DFA dfa = buildDFAFromPatterns({ ".*foo", ".*bar", ".*bang"});
+ EXPECT_EQ(static_cast<size_t>(8), countLiveNodes(dfa));
+ dfa.minimize();
+ EXPECT_EQ(static_cast<size_t>(7), countLiveNodes(dfa));
+}
+
+TEST_F(DFAMinimizerTest, MergeSuffixes)
+{
+ ContentExtensions::DFA dfa = buildDFAFromPatterns({ ".*aaa", ".*aab", ".*aba", ".*abb", ".*baa", ".*bab", ".*bba", ".*bbb"});
+ EXPECT_EQ(static_cast<size_t>(12), countLiveNodes(dfa));
+ dfa.minimize();
+ EXPECT_EQ(static_cast<size_t>(4), countLiveNodes(dfa));
+}
+
+TEST_F(DFAMinimizerTest, MergeInfixes)
+{
+ ContentExtensions::DFA dfa = buildDFAFromPatterns({ ".*aaakit", ".*aabkit", ".*abakit", ".*abbkit", ".*baakit", ".*babkit", ".*bbakit", ".*bbbkit"});
+ EXPECT_EQ(static_cast<size_t>(15), countLiveNodes(dfa));
+ dfa.minimize();
+ EXPECT_EQ(static_cast<size_t>(7), countLiveNodes(dfa));
+}
+
+TEST_F(DFAMinimizerTest, FallbackTransitionsWithDifferentiatorDoNotMerge1)
+{
+ ContentExtensions::DFA dfa = buildDFAFromPatterns({ "^a.a", "^b.a", "^bac", "^bbc", "^BCC"});
+ EXPECT_EQ(static_cast<size_t>(6), countLiveNodes(dfa));
+ dfa.minimize();
+ EXPECT_EQ(static_cast<size_t>(6), countLiveNodes(dfa));
+}
+
+TEST_F(DFAMinimizerTest, FallbackTransitionsWithDifferentiatorDoNotMerge2)
+{
+ ContentExtensions::DFA dfa = buildDFAFromPatterns({ "^bbc", "^BCC", "^a.a", "^b.a"});
+ EXPECT_EQ(static_cast<size_t>(6), countLiveNodes(dfa));
+ dfa.minimize();
+ EXPECT_EQ(static_cast<size_t>(6), countLiveNodes(dfa));
+}
+
+TEST_F(DFAMinimizerTest, FallbackTransitionsWithDifferentiatorDoNotMerge3)
+{
+ ContentExtensions::DFA dfa = buildDFAFromPatterns({ "^a.c", "^b.c", "^baa", "^bba", "^BCA"});
+ EXPECT_EQ(static_cast<size_t>(6), countLiveNodes(dfa));
+ dfa.minimize();
+ EXPECT_EQ(static_cast<size_t>(6), countLiveNodes(dfa));
+}
+
+TEST_F(DFAMinimizerTest, FallbackTransitionsWithDifferentiatorDoNotMerge4)
+{
+ ContentExtensions::DFA dfa = buildDFAFromPatterns({ "^baa", "^bba", "^BCA", "^a.c", "^b.c"});
+ EXPECT_EQ(static_cast<size_t>(6), countLiveNodes(dfa));
+ dfa.minimize();
+ EXPECT_EQ(static_cast<size_t>(6), countLiveNodes(dfa));
+}
+
+TEST_F(DFAMinimizerTest, FallbackTransitionsToOtherNodeInSameGroupDoesNotDifferentiateGroup)
+{
+ ContentExtensions::DFA dfa = buildDFAFromPatterns({ "^aac", "^a.c", "^b.c"});
+ EXPECT_EQ(static_cast<size_t>(5), countLiveNodes(dfa));
+ dfa.minimize();
+ EXPECT_EQ(static_cast<size_t>(4), countLiveNodes(dfa));
+}
+
+TEST_F(DFAMinimizerTest, SimpleFallBackTransitionDifferentiator1)
+{
+ ContentExtensions::DFA dfa = buildDFAFromPatterns({ "^a.bc.de", "^a.bd.ef"});
+ EXPECT_EQ(static_cast<size_t>(11), countLiveNodes(dfa));
+ dfa.minimize();
+ EXPECT_EQ(static_cast<size_t>(11), countLiveNodes(dfa));
+}
+
+TEST_F(DFAMinimizerTest, SimpleFallBackTransitionDifferentiator2)
+{
+ ContentExtensions::DFA dfa = buildDFAFromPatterns({ "^cb.", "^db.b"});
+ EXPECT_EQ(static_cast<size_t>(7), countLiveNodes(dfa));
+ dfa.minimize();
+ EXPECT_EQ(static_cast<size_t>(7), countLiveNodes(dfa));
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/ExtendedColor.cpp b/Tools/TestWebKitAPI/Tests/WebCore/ExtendedColor.cpp
new file mode 100644
index 000000000..607777dc8
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/ExtendedColor.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "Test.h"
+#include "WTFStringUtilities.h"
+#include <WebCore/Color.h>
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+TEST(ExtendedColor, Constructor)
+{
+ Color c1(1.0, 0.5, 0.25, 1.0, ColorSpaceDisplayP3);
+ EXPECT_TRUE(c1.isExtended());
+ EXPECT_FLOAT_EQ(1.0, c1.asExtended().red());
+ EXPECT_FLOAT_EQ(0.5, c1.asExtended().green());
+ EXPECT_FLOAT_EQ(0.25, c1.asExtended().blue());
+ EXPECT_FLOAT_EQ(1.0, c1.asExtended().alpha());
+ EXPECT_EQ(1u, c1.asExtended().refCount());
+ EXPECT_EQ(c1.cssText(), "color(display-p3 1 0.5 0.25)");
+}
+
+TEST(ExtendedColor, CopyConstructor)
+{
+ Color c1(1.0, 0.5, 0.25, 1.0, ColorSpaceDisplayP3);
+ EXPECT_TRUE(c1.isExtended());
+
+ Color c2(c1);
+
+ EXPECT_FLOAT_EQ(1.0, c2.asExtended().red());
+ EXPECT_FLOAT_EQ(0.5, c2.asExtended().green());
+ EXPECT_FLOAT_EQ(0.25, c2.asExtended().blue());
+ EXPECT_FLOAT_EQ(1.0, c2.asExtended().alpha());
+ EXPECT_EQ(2u, c1.asExtended().refCount());
+ EXPECT_EQ(2u, c2.asExtended().refCount());
+ EXPECT_EQ(c2.cssText(), "color(display-p3 1 0.5 0.25)");
+}
+
+TEST(ExtendedColor, Assignment)
+{
+ Color c1(1.0, 0.5, 0.25, 1.0, ColorSpaceDisplayP3);
+ EXPECT_TRUE(c1.isExtended());
+
+ Color c2 = c1;
+
+ EXPECT_FLOAT_EQ(1.0, c2.asExtended().red());
+ EXPECT_FLOAT_EQ(0.5, c2.asExtended().green());
+ EXPECT_FLOAT_EQ(0.25, c2.asExtended().blue());
+ EXPECT_FLOAT_EQ(1.0, c2.asExtended().alpha());
+ EXPECT_EQ(2u, c1.asExtended().refCount());
+ EXPECT_EQ(2u, c2.asExtended().refCount());
+ EXPECT_EQ(c2.cssText(), "color(display-p3 1 0.5 0.25)");
+}
+
+TEST(ExtendedColor, MoveConstructor)
+{
+ Color c1(1.0, 0.5, 0.25, 1.0, ColorSpaceDisplayP3);
+ EXPECT_TRUE(c1.isExtended());
+
+ Color c2(WTFMove(c1));
+ // We should have moved the extended color pointer into c2,
+ // and set c1 to invalid so that it doesn't cause deletion.
+ EXPECT_FALSE(c1.isExtended());
+ EXPECT_FALSE(c1.isValid());
+
+ EXPECT_FLOAT_EQ(1.0, c2.asExtended().red());
+ EXPECT_FLOAT_EQ(0.5, c2.asExtended().green());
+ EXPECT_FLOAT_EQ(0.25, c2.asExtended().blue());
+ EXPECT_FLOAT_EQ(1.0, c2.asExtended().alpha());
+ EXPECT_EQ(1u, c2.asExtended().refCount());
+ EXPECT_EQ(c2.cssText(), "color(display-p3 1 0.5 0.25)");
+}
+
+TEST(ExtendedColor, MoveAssignment)
+{
+ Color c1(1.0, 0.5, 0.25, 1.0, ColorSpaceDisplayP3);
+ EXPECT_TRUE(c1.isExtended());
+
+ Color c2 = WTFMove(c1);
+
+ // We should have moved the extended color pointer into c2,
+ // and set c1 to invalid so that it doesn't cause deletion.
+ EXPECT_FALSE(c1.isExtended());
+ EXPECT_FALSE(c1.isValid());
+
+ EXPECT_FLOAT_EQ(1.0, c2.asExtended().red());
+ EXPECT_FLOAT_EQ(0.5, c2.asExtended().green());
+ EXPECT_FLOAT_EQ(0.25, c2.asExtended().blue());
+ EXPECT_FLOAT_EQ(1.0, c2.asExtended().alpha());
+ EXPECT_EQ(1u, c2.asExtended().refCount());
+ EXPECT_EQ(c2.cssText(), "color(display-p3 1 0.5 0.25)");
+}
+
+TEST(ExtendedColor, BasicReferenceCounting)
+{
+ Color* c1 = new Color(1.0, 0.5, 0.25, 1.0, ColorSpaceDisplayP3);
+ EXPECT_TRUE(c1->isExtended());
+
+ Color* c2 = new Color(*c1);
+ Color* c3 = new Color(*c2);
+
+ EXPECT_FLOAT_EQ(1.0, c2->asExtended().red());
+ EXPECT_FLOAT_EQ(0.5, c2->asExtended().green());
+ EXPECT_FLOAT_EQ(0.25, c2->asExtended().blue());
+ EXPECT_FLOAT_EQ(1.0, c2->asExtended().alpha());
+ EXPECT_EQ(3u, c2->asExtended().refCount());
+ EXPECT_EQ(c2->cssText(), "color(display-p3 1 0.5 0.25)");
+
+ delete c1;
+ EXPECT_EQ(2u, c2->asExtended().refCount());
+
+ delete c2;
+ EXPECT_EQ(1u, c3->asExtended().refCount());
+
+ delete c3;
+}
+
+Color makeColor()
+{
+ Color c1(1.0, 0.5, 0.25, 1.0, ColorSpaceDisplayP3);
+ EXPECT_TRUE(c1.isExtended());
+ EXPECT_EQ(1u, c1.asExtended().refCount());
+
+ return c1;
+}
+
+TEST(ExtendedColor, ReturnValues)
+{
+ Color c2 = makeColor();
+ EXPECT_TRUE(c2.isExtended());
+
+ EXPECT_EQ(1u, c2.asExtended().refCount());
+ EXPECT_EQ(c2.cssText(), "color(display-p3 1 0.5 0.25)");
+}
+
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/FileSystem.cpp b/Tools/TestWebKitAPI/Tests/WebCore/FileSystem.cpp
new file mode 100644
index 000000000..8a4a78c65
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/FileSystem.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2015 Canon Inc. All rights reserved.
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "Test.h"
+#include <WebCore/FileSystem.h>
+#include <wtf/MainThread.h>
+#include <wtf/StringExtras.h>
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+const char* FileSystemTestData = "This is a test";
+
+// FIXME: Refactor FileSystemTest and SharedBufferTest as a single class.
+class FileSystemTest : public testing::Test {
+public:
+ void SetUp() override
+ {
+ WTF::initializeMainThread();
+
+ // create temp file
+ PlatformFileHandle handle;
+ m_tempFilePath = openTemporaryFile("tempTestFile", handle);
+ writeToFile(handle, FileSystemTestData, strlen(FileSystemTestData));
+ closeFile(handle);
+
+ m_tempEmptyFilePath = openTemporaryFile("tempEmptyTestFile", handle);
+ closeFile(handle);
+
+ m_spaceContainingFilePath = openTemporaryFile("temp Empty Test File", handle);
+ closeFile(handle);
+
+ m_bangContainingFilePath = openTemporaryFile("temp!Empty!Test!File", handle);
+ closeFile(handle);
+
+ m_quoteContainingFilePath = openTemporaryFile("temp\"Empty\"TestFile", handle);
+ closeFile(handle);
+ }
+
+ void TearDown() override
+ {
+ deleteFile(m_tempFilePath);
+ deleteFile(m_tempEmptyFilePath);
+ deleteFile(m_spaceContainingFilePath);
+ deleteFile(m_bangContainingFilePath);
+ deleteFile(m_quoteContainingFilePath);
+ }
+
+ const String& tempFilePath() { return m_tempFilePath; }
+ const String& tempEmptyFilePath() { return m_tempEmptyFilePath; }
+ const String& spaceContainingFilePath() { return m_spaceContainingFilePath; }
+ const String& bangContainingFilePath() { return m_bangContainingFilePath; }
+ const String& quoteContainingFilePath() { return m_quoteContainingFilePath; }
+
+private:
+ String m_tempFilePath;
+ String m_tempEmptyFilePath;
+ String m_spaceContainingFilePath;
+ String m_bangContainingFilePath;
+ String m_quoteContainingFilePath;
+};
+
+TEST_F(FileSystemTest, MappingMissingFile)
+{
+ bool success;
+ MappedFileData mappedFileData(String("not_existing_file"), success);
+ EXPECT_FALSE(success);
+ EXPECT_TRUE(!mappedFileData);
+}
+
+TEST_F(FileSystemTest, MappingExistingFile)
+{
+ bool success;
+ MappedFileData mappedFileData(tempFilePath(), success);
+ EXPECT_TRUE(success);
+ EXPECT_TRUE(!!mappedFileData);
+ EXPECT_TRUE(mappedFileData.size() == strlen(FileSystemTestData));
+ EXPECT_TRUE(strnstr(FileSystemTestData, static_cast<const char*>(mappedFileData.data()), mappedFileData.size()));
+}
+
+TEST_F(FileSystemTest, MappingExistingEmptyFile)
+{
+ bool success;
+ MappedFileData mappedFileData(tempEmptyFilePath(), success);
+ EXPECT_TRUE(success);
+ EXPECT_TRUE(!mappedFileData);
+}
+
+TEST_F(FileSystemTest, FilesHaveSameVolume)
+{
+ EXPECT_TRUE(filesHaveSameVolume(tempFilePath(), spaceContainingFilePath()));
+ EXPECT_TRUE(filesHaveSameVolume(spaceContainingFilePath(), bangContainingFilePath()));
+ EXPECT_TRUE(filesHaveSameVolume(bangContainingFilePath(), quoteContainingFilePath()));
+}
+
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/FloatPoint.cpp b/Tools/TestWebKitAPI/Tests/WebCore/FloatPoint.cpp
new file mode 100644
index 000000000..24c0ff9e3
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/FloatPoint.cpp
@@ -0,0 +1,598 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <WebCore/AffineTransform.h>
+#include <WebCore/FloatPoint.h>
+#include <WebCore/FloatSize.h>
+#include <WebCore/IntPoint.h>
+#include <WebCore/IntSize.h>
+#include <WebCore/TransformationMatrix.h>
+
+#if USE(CG)
+#include <CoreGraphics/CoreGraphics.h>
+#endif
+
+#if PLATFORM(WIN)
+#include <d2d1.h>
+#endif
+
+namespace TestWebKitAPI {
+
+static void testGetAndSet(WebCore::FloatPoint point)
+{
+ point.setX(1.1f);
+ EXPECT_FLOAT_EQ(1.1f, point.x());
+ point.setY(2.2f);
+ EXPECT_FLOAT_EQ(2.2f, point.y());
+
+ point.set(9.9f, 8.8f);
+ EXPECT_FLOAT_EQ(9.9f, point.x());
+ EXPECT_FLOAT_EQ(8.8f, point.y());
+}
+
+TEST(FloatPoint, DefaultConstruction)
+{
+ WebCore::FloatPoint test;
+
+ EXPECT_FLOAT_EQ(0, test.x());
+ EXPECT_FLOAT_EQ(0, test.y());
+
+ testGetAndSet(test);
+}
+
+TEST(FloatPoint, ValueConstruction)
+{
+ WebCore::FloatPoint test(9.9f, 8.8f);
+
+ EXPECT_FLOAT_EQ(9.9f, test.x());
+ EXPECT_FLOAT_EQ(8.8f, test.y());
+
+ testGetAndSet(test);
+}
+
+TEST(FloatPoint, ZeroConstruction)
+{
+ WebCore::FloatPoint test = WebCore::FloatPoint::zero();
+
+ EXPECT_FLOAT_EQ(0, test.x());
+ EXPECT_FLOAT_EQ(0, test.y());
+}
+
+TEST(FloatPoint, IntPointConstruction)
+{
+ WebCore::IntPoint testInput(2003, 1997);
+ WebCore::FloatPoint test = WebCore::FloatPoint(testInput);
+
+ EXPECT_FLOAT_EQ(2003.0f, test.x());
+ EXPECT_FLOAT_EQ(1997.0f, test.y());
+}
+
+TEST(FloatPoint, FloatSizeConstruction)
+{
+ WebCore::FloatSize testInput(500.7f, 300.2f);
+ WebCore::FloatPoint test = WebCore::FloatPoint(testInput);
+
+ EXPECT_FLOAT_EQ(500.7, test.x());
+ EXPECT_FLOAT_EQ(300.2, test.y());
+}
+
+TEST(FloatPoint, MoveByFloat)
+{
+ WebCore::FloatPoint test(100.0f, 200.0f);
+
+ EXPECT_FLOAT_EQ(100.0f, test.x());
+ EXPECT_FLOAT_EQ(200.0f, test.y());
+
+ test.move(20.2f, 30.3f);
+
+ EXPECT_FLOAT_EQ(120.2f, test.x());
+ EXPECT_FLOAT_EQ(230.3f, test.y());
+
+ test.move(-81.3f, 10.0f);
+
+ EXPECT_FLOAT_EQ(38.9f, test.x());
+ EXPECT_FLOAT_EQ(240.3f, test.y());
+
+ test.move(11.1f, -33.2f);
+
+ EXPECT_FLOAT_EQ(50.0f, test.x());
+ EXPECT_FLOAT_EQ(207.1f, test.y());
+
+ test.move(-5.6f, -9.8f);
+
+ EXPECT_FLOAT_EQ(44.4f, test.x());
+ EXPECT_FLOAT_EQ(197.3f, test.y());
+}
+
+TEST(FloatPoint, MoveByIntSize)
+{
+ WebCore::FloatPoint test(100.0f, 200.0f);
+
+ EXPECT_FLOAT_EQ(100.0f, test.x());
+ EXPECT_FLOAT_EQ(200.0f, test.y());
+
+ WebCore::IntSize first(20, 30);
+
+ test.move(first);
+
+ EXPECT_FLOAT_EQ(120.0f, test.x());
+ EXPECT_FLOAT_EQ(230.0f, test.y());
+
+ WebCore::IntSize second(-81, 10);
+
+ test.move(second);
+
+ EXPECT_FLOAT_EQ(39.0f, test.x());
+ EXPECT_FLOAT_EQ(240.0f, test.y());
+
+ WebCore::IntSize third(11, -33);
+
+ test.move(third);
+
+ EXPECT_FLOAT_EQ(50.0f, test.x());
+ EXPECT_FLOAT_EQ(207.0f, test.y());
+
+ WebCore::IntSize fourth(-6, -10);
+
+ test.move(fourth);
+
+ EXPECT_FLOAT_EQ(44.0f, test.x());
+ EXPECT_FLOAT_EQ(197.0f, test.y());
+}
+
+TEST(FloatPoint, MoveByFloatSize)
+{
+ WebCore::FloatPoint test(100.0f, 200.0f);
+
+ EXPECT_FLOAT_EQ(100.0f, test.x());
+ EXPECT_FLOAT_EQ(200.0f, test.y());
+
+ WebCore::FloatSize first(20.2f, 30.3f);
+
+ test.move(first);
+
+ EXPECT_FLOAT_EQ(120.2f, test.x());
+ EXPECT_FLOAT_EQ(230.3f, test.y());
+
+ WebCore::FloatSize second(-81.3f, 10.0f);
+
+ test.move(second);
+
+ EXPECT_FLOAT_EQ(38.9f, test.x());
+ EXPECT_FLOAT_EQ(240.3f, test.y());
+
+ WebCore::FloatSize third(11.1f, -33.2f);
+
+ test.move(third);
+
+ EXPECT_FLOAT_EQ(50.0f, test.x());
+ EXPECT_FLOAT_EQ(207.1f, test.y());
+
+ WebCore::FloatSize fourth(-5.6f, -9.8f);
+
+ test.move(fourth);
+
+ EXPECT_FLOAT_EQ(44.4f, test.x());
+ EXPECT_FLOAT_EQ(197.3f, test.y());
+}
+
+TEST(FloatPoint, MoveByIntPoint)
+{
+ WebCore::FloatPoint test(100.0f, 200.0f);
+
+ EXPECT_FLOAT_EQ(100.0f, test.x());
+ EXPECT_FLOAT_EQ(200.0f, test.y());
+
+ WebCore::IntPoint first(20, 30);
+
+ test.moveBy(first);
+
+ EXPECT_FLOAT_EQ(120.0f, test.x());
+ EXPECT_FLOAT_EQ(230.0f, test.y());
+
+ WebCore::IntPoint second(-81, 10);
+
+ test.moveBy(second);
+
+ EXPECT_FLOAT_EQ(39.0f, test.x());
+ EXPECT_FLOAT_EQ(240.0f, test.y());
+
+ WebCore::IntPoint third(11, -33);
+
+ test.moveBy(third);
+
+ EXPECT_FLOAT_EQ(50.0f, test.x());
+ EXPECT_FLOAT_EQ(207.0f, test.y());
+
+ WebCore::IntPoint fourth(-6, -10);
+
+ test.moveBy(fourth);
+
+ EXPECT_FLOAT_EQ(44.0f, test.x());
+ EXPECT_FLOAT_EQ(197.0f, test.y());
+}
+
+TEST(FloatPoint, MoveByFloatPoint)
+{
+ WebCore::FloatPoint test(100.0f, 200.0f);
+
+ EXPECT_FLOAT_EQ(100.0f, test.x());
+ EXPECT_FLOAT_EQ(200.0f, test.y());
+
+ WebCore::FloatPoint first(20.2f, 30.3f);
+
+ test.moveBy(first);
+
+ EXPECT_FLOAT_EQ(120.2f, test.x());
+ EXPECT_FLOAT_EQ(230.3f, test.y());
+
+ WebCore::FloatPoint second(-81.3f, 10.0f);
+
+ test.moveBy(second);
+
+ EXPECT_FLOAT_EQ(38.9f, test.x());
+ EXPECT_FLOAT_EQ(240.3f, test.y());
+
+ WebCore::FloatPoint third(11.1f, -33.2f);
+
+ test.moveBy(third);
+
+ EXPECT_FLOAT_EQ(50.0f, test.x());
+ EXPECT_FLOAT_EQ(207.1f, test.y());
+
+ WebCore::FloatPoint fourth(-5.6f, -9.8f);
+
+ test.moveBy(fourth);
+
+ EXPECT_FLOAT_EQ(44.4f, test.x());
+ EXPECT_FLOAT_EQ(197.3f, test.y());
+}
+
+TEST(FloatPoint, Scale)
+{
+ WebCore::FloatPoint test(100.0f, 200.0f);
+
+ EXPECT_FLOAT_EQ(100.0f, test.x());
+ EXPECT_FLOAT_EQ(200.0f, test.y());
+
+ test.scale(2.0f, 2.0f);
+
+ EXPECT_FLOAT_EQ(200.0f, test.x());
+ EXPECT_FLOAT_EQ(400.0f, test.y());
+
+ test.scale(0.5f, 0.5f);
+
+ EXPECT_FLOAT_EQ(100.0f, test.x());
+ EXPECT_FLOAT_EQ(200.0f, test.y());
+
+ test.scale(2);
+
+ EXPECT_FLOAT_EQ(200.0f, test.x());
+ EXPECT_FLOAT_EQ(400.0f, test.y());
+
+ test.scale(1.0f, 0.5f);
+
+ EXPECT_FLOAT_EQ(200.0f, test.x());
+ EXPECT_FLOAT_EQ(200.0f, test.y());
+}
+
+TEST(FloatPoint, Normalize)
+{
+ WebCore::FloatPoint a(30.0f, 40.0f);
+
+ a.normalize();
+
+ EXPECT_FLOAT_EQ(0.6, a.x());
+ EXPECT_FLOAT_EQ(0.8, a.y());
+}
+
+TEST(FloatPoint, Dot)
+{
+ WebCore::FloatPoint a(100.0f, 200.0f);
+ WebCore::FloatPoint b(2.0f, 4.0f);
+ WebCore::FloatPoint c(1.0f, 0.5f);
+
+ EXPECT_NEAR(1000.0f, a.dot(b), 0.0001f);
+ EXPECT_NEAR(200.0f, a.dot(c), 0.0001f);
+}
+
+TEST(FloatPoint, LengthSquared)
+{
+ WebCore::FloatPoint test(100.0f, 200.0f);
+
+ EXPECT_FLOAT_EQ(100.0f, test.x());
+ EXPECT_FLOAT_EQ(200.0f, test.y());
+
+ EXPECT_FLOAT_EQ(50000.0f, test.lengthSquared());
+}
+
+TEST(FloatPoint, ConstrainedBetween)
+{
+ WebCore::FloatPoint left(10.0f, 20.0f);
+ WebCore::FloatPoint right(100.0f, 200.0f);
+
+ WebCore::FloatPoint test1(50.0f, 80.0f);
+ WebCore::FloatPoint test2(8.0f, 80.0f);
+ WebCore::FloatPoint test3(50.0f, 220.0f);
+
+ auto constrained1 = test1.constrainedBetween(left, right);
+ EXPECT_FLOAT_EQ(50.0f, constrained1.x());
+ EXPECT_FLOAT_EQ(80.0f, constrained1.y());
+
+ auto constrained2 = test2.constrainedBetween(left, right);
+ EXPECT_FLOAT_EQ(10.0f, constrained2.x());
+ EXPECT_FLOAT_EQ(80.0f, constrained2.y());
+
+ auto constrained3 = test3.constrainedBetween(left, right);
+ EXPECT_FLOAT_EQ(50.0f, constrained3.x());
+ EXPECT_FLOAT_EQ(200.0f, constrained3.y());
+}
+
+TEST(FloatPoint, ShrunkTo)
+{
+ WebCore::FloatPoint big(100.0f, 200.0f);
+ WebCore::FloatPoint smaller(10.0f, 80.0f);
+
+ auto shrunkTo = big.shrunkTo(smaller);
+
+ EXPECT_FLOAT_EQ(10.0f, shrunkTo.x());
+ EXPECT_FLOAT_EQ(80.0f, shrunkTo.y());
+
+ WebCore::FloatPoint bigish(8.0f, 200.0f);
+
+ auto shrunkTo2 = bigish.shrunkTo(smaller);
+
+ EXPECT_FLOAT_EQ(8.0f, shrunkTo2.x());
+ EXPECT_FLOAT_EQ(80.0f, shrunkTo2.y());
+}
+
+TEST(FloatPoint, ExpandedTo)
+{
+ WebCore::FloatPoint big(100.0f, 200.0f);
+ WebCore::FloatPoint smaller(10.0f, 80.0f);
+
+ auto expandedTo = smaller.expandedTo(big);
+
+ EXPECT_FLOAT_EQ(100.0f, expandedTo.x());
+ EXPECT_FLOAT_EQ(200.0f, expandedTo.y());
+
+ WebCore::FloatPoint bigish(8.0f, 300.0f);
+
+ auto expandedTo2 = bigish.expandedTo(big);
+
+ EXPECT_FLOAT_EQ(100.0f, expandedTo2.x());
+ EXPECT_FLOAT_EQ(300.0f, expandedTo2.y());
+}
+
+TEST(FloatPoint, Transpose)
+{
+ WebCore::FloatPoint test(100.0f, 200.0f);
+
+ EXPECT_FLOAT_EQ(100.0f, test.x());
+ EXPECT_FLOAT_EQ(200.0f, test.y());
+
+ auto transposed = test.transposedPoint();
+
+ EXPECT_FLOAT_EQ(200.0f, transposed.x());
+ EXPECT_FLOAT_EQ(100.0f, transposed.y());
+}
+
+TEST(FloatPoint, Transforms)
+{
+ WebCore::FloatPoint test(100.0f, 200.0f);
+
+ WebCore::AffineTransform affine;
+
+ auto transformed1 = test.matrixTransform(affine);
+
+ EXPECT_FLOAT_EQ(100.0f, transformed1.x());
+ EXPECT_FLOAT_EQ(200.0f, transformed1.y());
+
+ WebCore::AffineTransform affine2(2.0, 0.0, 0.0, 2.0, 0.0, 0.0);
+
+ auto transformed2 = test.matrixTransform(affine2);
+
+ EXPECT_FLOAT_EQ(200.0f, transformed2.x());
+ EXPECT_FLOAT_EQ(400.0f, transformed2.y());
+
+ WebCore::TransformationMatrix matrix;
+
+ auto transformed3 = test.matrixTransform(matrix);
+
+ EXPECT_FLOAT_EQ(100.0f, transformed3.x());
+ EXPECT_FLOAT_EQ(200.0f, transformed3.y());
+
+ auto transformed4 = test.matrixTransform(affine2.toTransformationMatrix());
+
+ EXPECT_FLOAT_EQ(200.0f, transformed4.x());
+ EXPECT_FLOAT_EQ(400.0f, transformed4.y());
+}
+
+TEST(FloatPoint, Math)
+{
+ WebCore::FloatPoint a(100.0f, 200.0f);
+ WebCore::FloatPoint b(100.0f, 200.0f);
+
+ a += b;
+
+ EXPECT_FLOAT_EQ(200.0f, a.x());
+ EXPECT_FLOAT_EQ(400.0f, a.y());
+
+ WebCore::FloatSize c(50.0f, 50.0f);
+
+ a += c;
+
+ EXPECT_FLOAT_EQ(250.0f, a.x());
+ EXPECT_FLOAT_EQ(450.0f, a.y());
+
+ WebCore::FloatSize d(10.0f, 200.0f);
+
+ a -= d;
+
+ EXPECT_FLOAT_EQ(240.0f, a.x());
+ EXPECT_FLOAT_EQ(250.0f, a.y());
+
+ WebCore::FloatSize e(100.0f, 200.0f);
+
+ auto f = b + e;
+
+ EXPECT_FLOAT_EQ(200.0f, f.x());
+ EXPECT_FLOAT_EQ(400.0f, f.y());
+
+ WebCore::FloatPoint g(10.0f, 20.0f);
+
+ auto h = b + g;
+
+ EXPECT_FLOAT_EQ(110.0f, h.x());
+ EXPECT_FLOAT_EQ(220.0f, h.y());
+
+ WebCore::FloatSize i = b - g;
+
+ EXPECT_FLOAT_EQ(90.0f, i.width());
+ EXPECT_FLOAT_EQ(180.0f, i.height());
+
+ WebCore::FloatPoint j = b - e;
+
+ EXPECT_FLOAT_EQ(0.0f, j.x());
+ EXPECT_FLOAT_EQ(0.0f, j.y());
+
+ WebCore::FloatPoint negated = -b;
+
+ EXPECT_FLOAT_EQ(-100.0f, negated.x());
+ EXPECT_FLOAT_EQ(-200.0f, negated.y());
+
+ float value = b * g;
+
+ EXPECT_FLOAT_EQ(5000.0f, value);
+}
+
+TEST(FloatPoint, Equality)
+{
+ WebCore::FloatPoint a(100.0f, 200.0f);
+ WebCore::FloatPoint b(100.0f, 200.0f);
+ WebCore::FloatPoint c(10.0f, 20.0f);
+
+ ASSERT_TRUE(a == b);
+ ASSERT_FALSE(a == c);
+ ASSERT_FALSE(a != b);
+ ASSERT_TRUE(a != c);
+
+ ASSERT_TRUE(WebCore::areEssentiallyEqual(a, b));
+ ASSERT_FALSE(WebCore::areEssentiallyEqual(a, c));
+}
+
+TEST(FloatPoint, Floors)
+{
+ WebCore::FloatPoint a(100.6f, 199.9f);
+
+ WebCore::IntSize flooredSize = WebCore::flooredIntSize(a);
+ EXPECT_FLOAT_EQ(100, flooredSize.width());
+ EXPECT_FLOAT_EQ(199, flooredSize.height());
+
+ WebCore::IntPoint flooredPoint = WebCore::flooredIntPoint(a);
+ EXPECT_FLOAT_EQ(100, flooredPoint.x());
+ EXPECT_FLOAT_EQ(199, flooredPoint.y());
+
+ WebCore::FloatPoint flooredPoint1x = WebCore::floorPointToDevicePixels(a, 1.0);
+ EXPECT_FLOAT_EQ(100.0f, flooredPoint1x.x());
+ EXPECT_FLOAT_EQ(199.0f, flooredPoint1x.y());
+
+ WebCore::FloatPoint flooredPoint2x = WebCore::floorPointToDevicePixels(a, 2.0);
+ EXPECT_FLOAT_EQ(100.5f, flooredPoint2x.x());
+ EXPECT_FLOAT_EQ(199.5f, flooredPoint2x.y());
+}
+
+TEST(FloatPoint, Rounding)
+{
+ WebCore::FloatPoint a(100.4f, 199.9f);
+
+ WebCore::IntPoint roundedPoint = WebCore::roundedIntPoint(a);
+ EXPECT_FLOAT_EQ(100, roundedPoint.x());
+ EXPECT_FLOAT_EQ(200, roundedPoint.y());
+}
+
+TEST(FloatPoint, Ceiling)
+{
+ WebCore::FloatPoint a(100.4f, 199.9f);
+
+ WebCore::IntPoint ceilingPoint = WebCore::ceiledIntPoint(a);
+ EXPECT_FLOAT_EQ(101, ceilingPoint.x());
+ EXPECT_FLOAT_EQ(200, ceilingPoint.y());
+
+ WebCore::FloatPoint ceilingPoint1x = WebCore::ceilPointToDevicePixels(a, 1.0);
+ EXPECT_FLOAT_EQ(101.0f, ceilingPoint1x.x());
+ EXPECT_FLOAT_EQ(200.0f, ceilingPoint1x.y());
+
+ WebCore::FloatPoint ceilingPoint2x = WebCore::ceilPointToDevicePixels(a, 2.0);
+ EXPECT_FLOAT_EQ(100.5f, ceilingPoint2x.x());
+ EXPECT_FLOAT_EQ(200.0f, ceilingPoint2x.y());
+}
+
+TEST(FloatPoint, Casting)
+{
+ WebCore::FloatPoint a(100.4f, 199.9f);
+
+ WebCore::FloatSize floatSize = WebCore::toFloatSize(a);
+ EXPECT_FLOAT_EQ(100.4f, floatSize.width());
+ EXPECT_FLOAT_EQ(199.9f, floatSize.height());
+
+ WebCore::FloatSize b(99.6f, 299.1f);
+
+ WebCore::FloatPoint floatPoint = WebCore::toFloatPoint(b);
+ EXPECT_FLOAT_EQ(99.6f, floatPoint.x());
+ EXPECT_FLOAT_EQ(299.1f, floatPoint.y());
+
+#if USE(CG)
+ CGPoint cgPoint = a;
+
+ EXPECT_FLOAT_EQ(100.4f, cgPoint.x);
+ EXPECT_FLOAT_EQ(199.9f, cgPoint.y);
+
+ CGPoint cgPoint2 = CGPointMake(-22.3f, 14.2f);
+
+ WebCore::FloatPoint testCG(cgPoint2);
+
+ EXPECT_FLOAT_EQ(-22.3f, testCG.x());
+ EXPECT_FLOAT_EQ(14.2f, testCG.y());
+#endif
+
+#if PLATFORM(WIN)
+ D2D_POINT_2F d2dPoint = a;
+
+ EXPECT_FLOAT_EQ(100.4f, d2dPoint.x);
+ EXPECT_FLOAT_EQ(199.9f, d2dPoint.y);
+
+ D2D_POINT_2F d2dPoint2 = D2D1::Point2F(-22.3f, 14.2f);
+
+ WebCore::FloatPoint testD2D(d2dPoint2);
+
+ EXPECT_FLOAT_EQ(-22.3f, testD2D.x());
+ EXPECT_FLOAT_EQ(14.2f, testD2D.y());
+#endif
+}
+
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/FloatRect.cpp b/Tools/TestWebKitAPI/Tests/WebCore/FloatRect.cpp
new file mode 100644
index 000000000..b7e100e06
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/FloatRect.cpp
@@ -0,0 +1,783 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <WebCore/FloatPoint.h>
+#include <WebCore/FloatRect.h>
+#include <WebCore/FloatSize.h>
+#include <WebCore/IntRect.h>
+
+#if USE(CG)
+#include <CoreGraphics/CoreGraphics.h>
+#endif
+
+#if PLATFORM(WIN)
+#include <d2d1.h>
+#endif
+
+namespace TestWebKitAPI {
+
+static void testGetAndSet(WebCore::FloatRect rect)
+{
+ rect.setX(1.1f);
+ EXPECT_FLOAT_EQ(1.1f, rect.x());
+ rect.setY(2.2f);
+ EXPECT_FLOAT_EQ(2.2f, rect.y());
+ rect.setWidth(203.2f);
+ EXPECT_FLOAT_EQ(203.2f, rect.width());
+ rect.setHeight(72.9f);
+ EXPECT_FLOAT_EQ(72.9f, rect.height());
+}
+
+static void testEmptyRect(const WebCore::FloatRect& rect)
+{
+ EXPECT_FLOAT_EQ(0, rect.x());
+ EXPECT_FLOAT_EQ(0, rect.y());
+ EXPECT_FLOAT_EQ(0, rect.width());
+ EXPECT_FLOAT_EQ(0, rect.height());
+ EXPECT_FLOAT_EQ(0, rect.maxX());
+ EXPECT_FLOAT_EQ(0, rect.maxY());
+ EXPECT_TRUE(rect.isEmpty());
+ EXPECT_TRUE(rect.isZero());
+ EXPECT_FALSE(rect.isInfinite());
+}
+
+TEST(FloatRect, DefaultConstruction)
+{
+ WebCore::FloatRect test;
+
+ testEmptyRect(test);
+
+ testGetAndSet(test);
+
+ auto location = test.location();
+ EXPECT_FLOAT_EQ(0, location.x());
+ EXPECT_FLOAT_EQ(0, location.y());
+
+ auto size = test.size();
+ EXPECT_FLOAT_EQ(0, size.width());
+ EXPECT_FLOAT_EQ(0, size.height());
+}
+
+TEST(FloatRect, ValueConstruction)
+{
+ WebCore::FloatRect test(10.0f, 20.0f, 100.0f, 50.0f);
+
+ EXPECT_FLOAT_EQ(10.0f, test.x());
+ EXPECT_FLOAT_EQ(20.0f, test.y());
+ EXPECT_FLOAT_EQ(100.0f, test.width());
+ EXPECT_FLOAT_EQ(50.0f, test.height());
+ EXPECT_FLOAT_EQ(110.0f, test.maxX());
+ EXPECT_FLOAT_EQ(70.0f, test.maxY());
+ EXPECT_FALSE(test.isEmpty());
+ EXPECT_FALSE(test.isZero());
+ EXPECT_FALSE(test.isInfinite());
+
+ auto location = test.location();
+ EXPECT_FLOAT_EQ(10.0f, location.x());
+ EXPECT_FLOAT_EQ(20.0f, location.y());
+
+ auto size = test.size();
+ EXPECT_FLOAT_EQ(100.0f, size.width());
+ EXPECT_FLOAT_EQ(50.0f, size.height());
+}
+
+TEST(FloatRect, PointSizeConstruction)
+{
+ WebCore::FloatPoint location(20.0f, 30.0f);
+ WebCore::FloatSize size(100.0f, 50.0f);
+
+ WebCore::FloatRect test(location, size);
+
+ EXPECT_FLOAT_EQ(20.0f, test.x());
+ EXPECT_FLOAT_EQ(30.0f, test.y());
+ EXPECT_FLOAT_EQ(100.0f, test.width());
+ EXPECT_FLOAT_EQ(50.0f, test.height());
+ EXPECT_FLOAT_EQ(120.0f, test.maxX());
+ EXPECT_FLOAT_EQ(80.0f, test.maxY());
+ EXPECT_FALSE(test.isEmpty());
+ EXPECT_FALSE(test.isZero());
+ EXPECT_FALSE(test.isInfinite());
+
+ auto location2 = test.location();
+ EXPECT_FLOAT_EQ(20.0f, location2.x());
+ EXPECT_FLOAT_EQ(30.0f, location2.y());
+
+ auto size2 = test.size();
+ EXPECT_FLOAT_EQ(100.0f, size2.width());
+ EXPECT_FLOAT_EQ(50.0f, size2.height());
+}
+
+TEST(FloatRect, TwoPointConstruction)
+{
+ WebCore::FloatPoint point1(20.0f, 30.0f);
+ WebCore::FloatPoint point2(150.0f, 250.0f);
+
+ WebCore::FloatRect test(point1, point2);
+
+ EXPECT_FLOAT_EQ(20.0f, test.x());
+ EXPECT_FLOAT_EQ(30.0f, test.y());
+ EXPECT_FLOAT_EQ(130.0f, test.width());
+ EXPECT_FLOAT_EQ(220.0f, test.height());
+ EXPECT_FLOAT_EQ(150.0f, test.maxX());
+ EXPECT_FLOAT_EQ(250.0f, test.maxY());
+ EXPECT_FALSE(test.isEmpty());
+ EXPECT_FALSE(test.isZero());
+ EXPECT_FALSE(test.isInfinite());
+
+ auto location = test.location();
+ EXPECT_FLOAT_EQ(20.0f, location.x());
+ EXPECT_FLOAT_EQ(30.0f, location.y());
+
+ auto size = test.size();
+ EXPECT_FLOAT_EQ(130.0f, size.width());
+ EXPECT_FLOAT_EQ(220.0f, size.height());
+}
+
+TEST(FloatRect, IntRectConstruction)
+{
+ WebCore::IntRect rect(20, 30, 150, 300);
+
+ WebCore::FloatRect test(rect);
+
+ EXPECT_FLOAT_EQ(20.0f, test.x());
+ EXPECT_FLOAT_EQ(30.0f, test.y());
+ EXPECT_FLOAT_EQ(150.0f, test.width());
+ EXPECT_FLOAT_EQ(300.0f, test.height());
+ EXPECT_FLOAT_EQ(170.0f, test.maxX());
+ EXPECT_FLOAT_EQ(330.0f, test.maxY());
+ EXPECT_FALSE(test.isEmpty());
+ EXPECT_FALSE(test.isZero());
+ EXPECT_FALSE(test.isInfinite());
+
+ auto location = test.location();
+ EXPECT_FLOAT_EQ(20.0f, location.x());
+ EXPECT_FLOAT_EQ(30.0f, location.y());
+
+ auto size = test.size();
+ EXPECT_FLOAT_EQ(150.0f, size.width());
+ EXPECT_FLOAT_EQ(300.0f, size.height());
+}
+
+TEST(FloatRect, SetLocationAndSize)
+{
+ WebCore::FloatRect rect;
+
+ testEmptyRect(rect);
+
+ WebCore::FloatPoint location(10.0f, 20.0f);
+
+ rect.setLocation(location);
+
+ EXPECT_FLOAT_EQ(10.0f, rect.x());
+ EXPECT_FLOAT_EQ(20.0f, rect.y());
+ EXPECT_FLOAT_EQ(0.0f, rect.width());
+ EXPECT_FLOAT_EQ(0.0f, rect.height());
+ EXPECT_FLOAT_EQ(10.0f, rect.maxX());
+ EXPECT_FLOAT_EQ(20.0f, rect.maxY());
+ EXPECT_TRUE(rect.isEmpty());
+ EXPECT_TRUE(rect.isZero());
+ EXPECT_FALSE(rect.isInfinite());
+
+ WebCore::FloatSize size(100.0f, 200.0f);
+
+ rect.setSize(size);
+
+ EXPECT_FLOAT_EQ(10.0f, rect.x());
+ EXPECT_FLOAT_EQ(20.0f, rect.y());
+ EXPECT_FLOAT_EQ(100.0f, rect.width());
+ EXPECT_FLOAT_EQ(200.0f, rect.height());
+ EXPECT_FLOAT_EQ(110.0f, rect.maxX());
+ EXPECT_FLOAT_EQ(220.0f, rect.maxY());
+ EXPECT_FALSE(rect.isEmpty());
+ EXPECT_FALSE(rect.isZero());
+ EXPECT_FALSE(rect.isInfinite());
+}
+
+TEST(FloatRect, Center)
+{
+ WebCore::FloatRect rect(20.0f, 30.0f, 100.0f, 200.0f);
+
+ auto center = rect.center();
+
+ EXPECT_FLOAT_EQ(70.0f, center.x());
+ EXPECT_FLOAT_EQ(130.0f, center.y());
+}
+
+TEST(FloatRect, Move)
+{
+ WebCore::FloatRect rect(20.0f, 30.0f, 100.0f, 200.0f);
+
+ WebCore::FloatSize delta(10.0f, 20.0f);
+
+ rect.move(delta);
+
+ EXPECT_FLOAT_EQ(30.0f, rect.x());
+ EXPECT_FLOAT_EQ(50.0f, rect.y());
+
+ WebCore::FloatPoint deltaPoint(-20.0f, -40.0f);
+
+ rect.moveBy(deltaPoint);
+
+ EXPECT_FLOAT_EQ(10.0f, rect.x());
+ EXPECT_FLOAT_EQ(10.0f, rect.y());
+
+ rect.move(-10.0f, 22.0f);
+
+ EXPECT_FLOAT_EQ(0.0f, rect.x());
+ EXPECT_FLOAT_EQ(32.0f, rect.y());
+}
+
+TEST(FloatRect, Expand)
+{
+ WebCore::FloatRect rect(20.0f, 30.0f, 100.0f, 200.0f);
+
+ WebCore::FloatSize size(100.0f, 100.0f);
+
+ rect.expand(size);
+
+ EXPECT_FLOAT_EQ(200.0f, rect.width());
+ EXPECT_FLOAT_EQ(300.0f, rect.height());
+
+ rect.expand(55.0f, 22.0f);
+
+ EXPECT_FLOAT_EQ(255.0f, rect.width());
+ EXPECT_FLOAT_EQ(322.0f, rect.height());
+
+ WebCore::FloatSize size2(-10.0f, -20.0f);
+
+ rect.expand(size2);
+
+ EXPECT_FLOAT_EQ(245.0f, rect.width());
+ EXPECT_FLOAT_EQ(302.0f, rect.height());
+
+ rect.expand(-5.0f, -2.0f);
+
+ EXPECT_FLOAT_EQ(240.0f, rect.width());
+ EXPECT_FLOAT_EQ(300.0f, rect.height());
+
+ EXPECT_FALSE(rect.isInfinite());
+}
+
+TEST(FloatRect, Contract)
+{
+ WebCore::FloatRect rect(20.0f, 30.0f, 100.0f, 200.0f);
+
+ WebCore::FloatSize size(50.0f, 100.0f);
+
+ rect.contract(size);
+
+ EXPECT_FLOAT_EQ(50.0f, rect.width());
+ EXPECT_FLOAT_EQ(100.0f, rect.height());
+
+ rect.contract(25.0f, 22.0f);
+
+ EXPECT_FLOAT_EQ(25.0f, rect.width());
+ EXPECT_FLOAT_EQ(78.0f, rect.height());
+
+ WebCore::FloatSize size2(-10.0f, -20.0f);
+
+ rect.contract(size2);
+
+ EXPECT_FLOAT_EQ(35.0f, rect.width());
+ EXPECT_FLOAT_EQ(98.0f, rect.height());
+
+ rect.contract(-5.0f, -2.0f);
+
+ EXPECT_FLOAT_EQ(40.0f, rect.width());
+ EXPECT_FLOAT_EQ(100.0f, rect.height());
+
+ EXPECT_FALSE(rect.isInfinite());
+}
+
+TEST(FloatRect, ShiftXEdge)
+{
+ WebCore::FloatRect rect(20.0f, 30.0f, 100.0f, 200.0f);
+
+ rect.shiftXEdgeTo(77.0f);
+
+ EXPECT_FLOAT_EQ(77.0f, rect.x());
+ EXPECT_FLOAT_EQ(120.0f, rect.maxX());
+ EXPECT_FLOAT_EQ(30.0f, rect.y());
+ EXPECT_FLOAT_EQ(230.0f, rect.maxY());
+ EXPECT_FLOAT_EQ(43.0f, rect.width());
+ EXPECT_FLOAT_EQ(200.0f, rect.height());
+
+ rect.shiftMaxXEdgeTo(200.0f);
+
+ EXPECT_FLOAT_EQ(77.0f, rect.x());
+ EXPECT_FLOAT_EQ(200.0f, rect.maxX());
+ EXPECT_FLOAT_EQ(30.0f, rect.y());
+ EXPECT_FLOAT_EQ(230.0f, rect.maxY());
+ EXPECT_FLOAT_EQ(123.0f, rect.width());
+ EXPECT_FLOAT_EQ(200.0f, rect.height());
+}
+
+TEST(FloatRect, ShiftYEdge)
+{
+ WebCore::FloatRect rect(20.0f, 30.0f, 100.0f, 200.0f);
+
+ rect.shiftYEdgeTo(59.0f);
+
+ EXPECT_FLOAT_EQ(20.0f, rect.x());
+ EXPECT_FLOAT_EQ(120.0f, rect.maxX());
+ EXPECT_FLOAT_EQ(59.0f, rect.y());
+ EXPECT_FLOAT_EQ(230.0f, rect.maxY());
+ EXPECT_FLOAT_EQ(100.0f, rect.width());
+ EXPECT_FLOAT_EQ(171.0f, rect.height());
+
+ rect.shiftMaxYEdgeTo(270.0f);
+
+ EXPECT_FLOAT_EQ(20.0f, rect.x());
+ EXPECT_FLOAT_EQ(120.0f, rect.maxX());
+ EXPECT_FLOAT_EQ(59.0f, rect.y());
+ EXPECT_FLOAT_EQ(270.0f, rect.maxY());
+ EXPECT_FLOAT_EQ(100.0f, rect.width());
+ EXPECT_FLOAT_EQ(211.0f, rect.height());
+}
+
+TEST(FloatRect, Inflate)
+{
+ WebCore::FloatRect rect(20.0f, 30.0f, 100.0f, 200.0f);
+
+ rect.inflateX(5.0f);
+
+ EXPECT_FLOAT_EQ(15.0f, rect.x());
+ EXPECT_FLOAT_EQ(125.0f, rect.maxX());
+
+ rect.inflateY(4.0f);
+
+ EXPECT_FLOAT_EQ(26.0f, rect.y());
+ EXPECT_FLOAT_EQ(234.0f, rect.maxY());
+
+ rect.inflate(10.0f);
+
+ EXPECT_FLOAT_EQ(5.0f, rect.x());
+ EXPECT_FLOAT_EQ(135.0f, rect.maxX());
+ EXPECT_FLOAT_EQ(16.0f, rect.y());
+ EXPECT_FLOAT_EQ(244.0f, rect.maxY());
+
+ EXPECT_FALSE(rect.isInfinite());
+}
+
+TEST(FloatRect, Corners)
+{
+ WebCore::FloatRect rect(20.0f, 30.0f, 100.0f, 200.0f);
+
+ WebCore::FloatPoint topLeft = rect.minXMinYCorner();
+ EXPECT_FLOAT_EQ(20.0f, topLeft.x());
+ EXPECT_FLOAT_EQ(30.0f, topLeft.y());
+
+ WebCore::FloatPoint topRight = rect.maxXMinYCorner();
+ EXPECT_FLOAT_EQ(120.0f, topRight.x());
+ EXPECT_FLOAT_EQ(30.0f, topRight.y());
+
+ WebCore::FloatPoint bottomLeft = rect.minXMaxYCorner();
+ EXPECT_FLOAT_EQ(20.0f, bottomLeft.x());
+ EXPECT_FLOAT_EQ(230.0f, bottomLeft.y());
+
+ WebCore::FloatPoint bottomRight = rect.maxXMaxYCorner();
+ EXPECT_FLOAT_EQ(120.0f, bottomRight.x());
+ EXPECT_FLOAT_EQ(230.0f, bottomRight.y());
+}
+
+TEST(FloatRect, Contains)
+{
+ WebCore::FloatRect rect(20.0f, 30.0f, 100.0f, 200.0f);
+
+ WebCore::FloatRect contained(30.0f, 40.0f, 50.0f, 100.0f);
+
+ ASSERT_TRUE(rect.contains(contained));
+
+ WebCore::FloatRect outside(120.0f, 230.0f, 50.0f, 100.0f);
+
+ ASSERT_FALSE(rect.contains(outside));
+
+ WebCore::FloatRect intersects(10.0f, 20.0f, 90.0f, 180.0f);
+
+ ASSERT_FALSE(rect.contains(intersects));
+
+ WebCore::FloatPoint pointInside(60.0f, 70.0f);
+
+ ASSERT_TRUE(rect.contains(pointInside));
+ ASSERT_TRUE(rect.contains(pointInside, WebCore::FloatRect::InsideButNotOnStroke));
+
+ WebCore::FloatPoint pointOutside(160.0f, 270.0f);
+
+ ASSERT_FALSE(rect.contains(pointOutside));
+ ASSERT_FALSE(rect.contains(pointOutside, WebCore::FloatRect::InsideButNotOnStroke));
+
+ WebCore::FloatPoint pointOnLine(20.0f, 30.0f);
+
+ ASSERT_TRUE(rect.contains(pointOnLine));
+ ASSERT_FALSE(rect.contains(pointOutside, WebCore::FloatRect::InsideButNotOnStroke));
+
+ ASSERT_TRUE(rect.contains(60.0f, 70.0f));
+ ASSERT_FALSE(rect.contains(160.0f, 270.0f));
+}
+
+TEST(FloatRect, Intersects)
+{
+ WebCore::FloatRect rect(20.0f, 30.0f, 100.0f, 200.0f);
+
+ WebCore::FloatRect contained(30.0f, 40.0f, 50.0f, 100.0f);
+
+ ASSERT_TRUE(rect.intersects(contained));
+
+ WebCore::FloatRect outside(120.0f, 230.0f, 50.0f, 100.0f);
+
+ ASSERT_FALSE(rect.intersects(outside));
+
+ WebCore::FloatRect intersects(10.0f, 20.0f, 90.0f, 180.0f);
+
+ ASSERT_TRUE(rect.intersects(intersects));
+}
+
+static void testIntersectResult(const WebCore::FloatRect& rect)
+{
+ EXPECT_FLOAT_EQ(70.0f, rect.x());
+ EXPECT_FLOAT_EQ(120.0f, rect.maxX());
+ EXPECT_FLOAT_EQ(80.0f, rect.y());
+ EXPECT_FLOAT_EQ(230.0f, rect.maxY());
+}
+
+TEST(FloatRect, Intersect)
+{
+ WebCore::FloatRect rectA(20.0f, 30.0f, 100.0f, 200.0f);
+ WebCore::FloatRect rectB(70.0f, 80.0f, 100.0f, 200.0f);
+
+ rectA.intersect(rectB);
+
+ testIntersectResult(rectA);
+
+ WebCore::FloatRect rectC(20.0f, 30.0f, 100.0f, 200.0f);
+
+ auto intersected = WebCore::intersection(rectC, rectB);
+
+ testIntersectResult(intersected);
+}
+
+static void testUnitedRects(const WebCore::FloatRect& united)
+{
+ EXPECT_FLOAT_EQ(20.0f, united.x());
+ EXPECT_FLOAT_EQ(170.0f, united.maxX());
+ EXPECT_FLOAT_EQ(30.0f, united.y());
+ EXPECT_FLOAT_EQ(280.0f, united.maxY());
+}
+
+TEST(FloatRect, Unite)
+{
+ WebCore::FloatRect rectA(20.0f, 30.0f, 100.0f, 200.0f);
+ WebCore::FloatRect rectB(70.0f, 80.0f, 100.0f, 200.0f);
+
+ rectA.unite(rectB);
+
+ testUnitedRects(rectA);
+
+ WebCore::FloatRect rectC(20.0f, 30.0f, 100.0f, 200.0f);
+
+ auto united = WebCore::unionRect(rectC, rectB);
+
+ testUnitedRects(united);
+}
+
+TEST(FloatRect, Extend)
+{
+ WebCore::FloatRect rect(20.0f, 30.0f, 100.0f, 200.0f);
+ WebCore::FloatPoint point(170.0f, 280.0f);
+
+ rect.extend(point);
+
+ EXPECT_FLOAT_EQ(20.0f, rect.x());
+ EXPECT_FLOAT_EQ(170.0f, rect.maxX());
+ EXPECT_FLOAT_EQ(30.0f, rect.y());
+ EXPECT_FLOAT_EQ(280.0f, rect.maxY());
+}
+
+TEST(FloatRect, Overlaps)
+{
+ WebCore::FloatRect rect(20.0f, 30.0f, 100.0f, 200.0f);
+
+ ASSERT_FALSE(rect.overlapsXRange(0.0f, 10.0f));
+ ASSERT_TRUE(rect.overlapsXRange(10.0f, 30.0f));
+ ASSERT_TRUE(rect.overlapsXRange(40.0f, 70.0f));
+ ASSERT_TRUE(rect.overlapsXRange(110.0f, 130.0f));
+ ASSERT_FALSE(rect.overlapsXRange(140.0f, 600.0f));
+
+ ASSERT_FALSE(rect.overlapsYRange(0.0f, 10.0f));
+ ASSERT_TRUE(rect.overlapsYRange(10.0f, 40.0f));
+ ASSERT_TRUE(rect.overlapsYRange(40.0f, 70.0f));
+ ASSERT_TRUE(rect.overlapsYRange(220.0f, 250.0f));
+ ASSERT_FALSE(rect.overlapsYRange(250.0f, 600.0f));
+}
+
+TEST(FloatRect, Scale)
+{
+ WebCore::FloatRect rect(20.0f, 30.0f, 100.0f, 200.0f);
+
+ rect.scale(2.0f);
+
+ EXPECT_FLOAT_EQ(40.0f, rect.x());
+ EXPECT_FLOAT_EQ(240.0f, rect.maxX());
+ EXPECT_FLOAT_EQ(60.0f, rect.y());
+ EXPECT_FLOAT_EQ(460.0f, rect.maxY());
+
+ rect.scale(0.5f, 2.0f);
+
+ EXPECT_FLOAT_EQ(20.0f, rect.x());
+ EXPECT_FLOAT_EQ(120.0f, rect.maxX());
+ EXPECT_FLOAT_EQ(120.0f, rect.y());
+ EXPECT_FLOAT_EQ(920.0f, rect.maxY());
+
+ rect.scale(1.0f, 0.25f);
+
+ EXPECT_FLOAT_EQ(20.0f, rect.x());
+ EXPECT_FLOAT_EQ(120.0f, rect.maxX());
+ EXPECT_FLOAT_EQ(30.0f, rect.y());
+ EXPECT_FLOAT_EQ(230.0f, rect.maxY());
+}
+
+TEST(FloatRect, Transpose)
+{
+ WebCore::FloatRect rect(20.0f, 30.0f, 100.0f, 200.0f);
+
+ auto transposed = rect.transposedRect();
+
+ EXPECT_FLOAT_EQ(30.0f, transposed.x());
+ EXPECT_FLOAT_EQ(230.0f, transposed.maxX());
+ EXPECT_FLOAT_EQ(20.0f, transposed.y());
+ EXPECT_FLOAT_EQ(120.0f, transposed.maxY());
+}
+
+TEST(FloatRect, FitToPoints)
+{
+ WebCore::FloatRect rect(10.0f, 20.0f, 30.0f, 40.0f);
+
+ WebCore::FloatPoint p0(20.0f, 30.0f);
+ WebCore::FloatPoint p1(70.0f, 130.0f);
+ WebCore::FloatPoint p2(50.0f, 20.0f);
+ WebCore::FloatPoint p3(90.0f, 190.0f);
+
+ rect.fitToPoints(p0, p1);
+
+ EXPECT_FLOAT_EQ(20.0f, rect.x());
+ EXPECT_FLOAT_EQ(70.0f, rect.maxX());
+ EXPECT_FLOAT_EQ(30.0f, rect.y());
+ EXPECT_FLOAT_EQ(130.0f, rect.maxY());
+
+ rect.fitToPoints(p0, p1, p2);
+
+ EXPECT_FLOAT_EQ(20.0f, rect.x());
+ EXPECT_FLOAT_EQ(70.0f, rect.maxX());
+ EXPECT_FLOAT_EQ(20.0f, rect.y());
+ EXPECT_FLOAT_EQ(130.0f, rect.maxY());
+
+ rect.fitToPoints(p0, p1, p2, p3);
+
+ EXPECT_FLOAT_EQ(20.0f, rect.x());
+ EXPECT_FLOAT_EQ(90.0f, rect.maxX());
+ EXPECT_FLOAT_EQ(20.0f, rect.y());
+ EXPECT_FLOAT_EQ(190.0f, rect.maxY());
+}
+
+static void checkCastRect(const WebCore::FloatRect& rect)
+{
+ EXPECT_FLOAT_EQ(10.0f, rect.x());
+ EXPECT_FLOAT_EQ(40.0f, rect.maxX());
+ EXPECT_FLOAT_EQ(20.0f, rect.y());
+ EXPECT_FLOAT_EQ(60.0f, rect.maxY());
+ EXPECT_FLOAT_EQ(30.0f, rect.width());
+ EXPECT_FLOAT_EQ(40.0f, rect.height());
+}
+
+TEST(FloatRect, Casting)
+{
+ WebCore::FloatRect rect(10.0f, 20.0f, 30.0f, 40.0f);
+
+#if USE(CG)
+ CGRect cgRect = rect;
+
+ EXPECT_FLOAT_EQ(10.0f, cgRect.origin.x);
+ EXPECT_FLOAT_EQ(20.0f, cgRect.origin.y);
+ EXPECT_FLOAT_EQ(30.0f, cgRect.size.width);
+ EXPECT_FLOAT_EQ(40.0f, cgRect.size.height);
+
+ WebCore::FloatRect rectFromCGRect(cgRect);
+
+ checkCastRect(rectFromCGRect);
+#endif
+
+#if PLATFORM(WIN)
+ D2D1_RECT_F d2dRect = rect;
+
+ EXPECT_FLOAT_EQ(10.0f, d2dRect.left);
+ EXPECT_FLOAT_EQ(20.0f, d2dRect.top);
+ EXPECT_FLOAT_EQ(40.0f, d2dRect.right);
+ EXPECT_FLOAT_EQ(60.0f, d2dRect.bottom);
+
+ WebCore::FloatRect rectFromD2DRect(d2dRect);
+
+ checkCastRect(rectFromD2DRect);
+#endif
+}
+
+static void checkAdditionResult1(const WebCore::FloatRect& rect)
+{
+ EXPECT_FLOAT_EQ(10.0f, rect.x());
+ EXPECT_FLOAT_EQ(130.0f, rect.maxX());
+ EXPECT_FLOAT_EQ(20.0f, rect.y());
+ EXPECT_FLOAT_EQ(220.0f, rect.maxY());
+ EXPECT_FLOAT_EQ(120.0f, rect.width());
+ EXPECT_FLOAT_EQ(200.0f, rect.height());
+}
+
+static void checkAdditionResult2(const WebCore::FloatRect& rect)
+{
+ EXPECT_FLOAT_EQ(10.0f, rect.x());
+ EXPECT_FLOAT_EQ(250.0f, rect.maxX());
+ EXPECT_FLOAT_EQ(20.0f, rect.y());
+ EXPECT_FLOAT_EQ(240.0f, rect.maxY());
+ EXPECT_FLOAT_EQ(240.0f, rect.width());
+ EXPECT_FLOAT_EQ(220.0f, rect.height());
+}
+
+TEST(FloatRect, Addition)
+{
+ WebCore::FloatRect rect(10.0f, 20.0f, 100.0f, 100.0f);
+ WebCore::FloatRect rightSide(0.0f, 0.0f, 20.0f, 100.0f);
+ WebCore::FloatRect bottom(0.0f, 0.0f, 120.0f, 20.0f);
+
+ auto combined = rect + rightSide;
+
+ checkAdditionResult1(combined);
+
+ auto combined2 = combined + bottom;
+
+ checkAdditionResult2(combined2);
+
+ rect += rightSide;
+ rect += bottom;
+
+ checkAdditionResult2(rect);
+}
+
+TEST(FloatRect, Equality)
+{
+ WebCore::FloatRect rect(10.0f, 20.0f, 100.0f, 100.0f);
+ WebCore::FloatRect rect2(10.0f, 20.0f, 100.0f, 100.0f);
+ WebCore::FloatRect rightSide(110.0f, 20.0f, 20.0f, 100.0f);
+
+ ASSERT_TRUE(rect == rect2);
+ ASSERT_FALSE(rect != rect2);
+ ASSERT_TRUE(rect != rightSide);
+ ASSERT_FALSE(rect == rightSide);
+}
+
+TEST(FloatRect, InfiniteRect)
+{
+ WebCore::FloatRect infinite = WebCore::FloatRect::infiniteRect();
+
+ EXPECT_FLOAT_EQ(-std::numeric_limits<float>::max() / 2, infinite.x());
+ EXPECT_FLOAT_EQ(-std::numeric_limits<float>::max() / 2, infinite.y());
+ EXPECT_FLOAT_EQ(std::numeric_limits<float>::max(), infinite.width());
+ EXPECT_FLOAT_EQ(std::numeric_limits<float>::max(), infinite.height());
+
+ // FIXME: We have an unusual representation for our infinite rect.
+ // WebCore::Float::infiniteRect is (negative infinity)/2 for the upper left corner,
+ // while CoreGraphics and D2D use (negative infinity).
+
+#if USE(CG)
+ CGRect cgInfiniteRect = CGRectInfinite;
+
+#if PLATFORM(WIN)
+ EXPECT_FLOAT_EQ(-std::numeric_limits<float>::max() / 2, cgInfiniteRect.origin.x);
+ EXPECT_FLOAT_EQ(-std::numeric_limits<float>::max() / 2, cgInfiniteRect.origin.y);
+ EXPECT_FLOAT_EQ(std::numeric_limits<float>::max(), cgInfiniteRect.size.width);
+ EXPECT_FLOAT_EQ(std::numeric_limits<float>::max(), cgInfiniteRect.size.height);
+#else
+ EXPECT_FLOAT_EQ(-std::numeric_limits<float>::max(), cgInfiniteRect.origin.x);
+ EXPECT_FLOAT_EQ(-std::numeric_limits<float>::max(), cgInfiniteRect.origin.y);
+ EXPECT_FLOAT_EQ(std::numeric_limits<float>::max(), cgInfiniteRect.origin.x + cgInfiniteRect.size.width);
+ EXPECT_FLOAT_EQ(std::numeric_limits<float>::max(), cgInfiniteRect.origin.y + cgInfiniteRect.size.height);
+#endif
+ // ASSERT_TRUE(infinite == cgInfiniteRect);
+#endif
+
+#if PLATFORM(WIN)
+ D2D1_RECT_F d2dInfiniteRect = D2D1::InfiniteRect();
+
+ EXPECT_FLOAT_EQ(-std::numeric_limits<float>::max(), d2dInfiniteRect.left);
+ EXPECT_FLOAT_EQ(-std::numeric_limits<float>::max(), d2dInfiniteRect.top);
+ EXPECT_FLOAT_EQ(std::numeric_limits<float>::max(), d2dInfiniteRect.right);
+ EXPECT_FLOAT_EQ(std::numeric_limits<float>::max(), d2dInfiniteRect.bottom);
+ // ASSERT_TRUE(infinite == d2dInfiniteRect);
+#endif
+}
+
+TEST(FloatRect, EnclosingAndRounding)
+{
+ WebCore::FloatRect rect(10.0f, 20.0f, 1024.3f, 768.3f);
+
+ auto enclosed = WebCore::encloseRectToDevicePixels(rect, 1.0f);
+
+ EXPECT_FLOAT_EQ(10.0f, enclosed.x());
+ EXPECT_FLOAT_EQ(20.0f, enclosed.y());
+ EXPECT_FLOAT_EQ(1035.0f, enclosed.maxX());
+ EXPECT_FLOAT_EQ(789.0f, enclosed.maxY());
+
+ auto enclosed2 = WebCore::encloseRectToDevicePixels(rect, 2.0f);
+
+ EXPECT_FLOAT_EQ(10.0f, enclosed2.x());
+ EXPECT_FLOAT_EQ(20.0f, enclosed2.y());
+ EXPECT_FLOAT_EQ(1034.5f, enclosed2.maxX());
+ EXPECT_FLOAT_EQ(788.5f, enclosed2.maxY());
+}
+
+TEST(FloatRect, EnclosingIntRect)
+{
+ WebCore::FloatRect rect(10.0f, 20.0f, 1024.3f, 768.6f);
+
+ auto enclosed = WebCore::enclosingIntRect(rect);
+
+ EXPECT_FLOAT_EQ(10, enclosed.x());
+ EXPECT_FLOAT_EQ(20, enclosed.y());
+ EXPECT_FLOAT_EQ(1035, enclosed.maxX());
+ EXPECT_FLOAT_EQ(789, enclosed.maxY());
+}
+
+TEST(FloatRect, RoundedIntRect)
+{
+ WebCore::FloatRect rect(10.0f, 20.0f, 1024.3f, 768.6f);
+
+ auto enclosed = WebCore::roundedIntRect(rect);
+
+ EXPECT_FLOAT_EQ(10, enclosed.x());
+ EXPECT_FLOAT_EQ(20, enclosed.y());
+ EXPECT_FLOAT_EQ(1034, enclosed.maxX());
+ EXPECT_FLOAT_EQ(789, enclosed.maxY());
+}
+
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/FloatSize.cpp b/Tools/TestWebKitAPI/Tests/WebCore/FloatSize.cpp
new file mode 100644
index 000000000..756e76f1d
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/FloatSize.cpp
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <WebCore/FloatSize.h>
+#include <WebCore/IntPoint.h>
+#include <WebCore/IntSize.h>
+
+#if USE(CG)
+#include <CoreGraphics/CoreGraphics.h>
+#endif
+
+#if PLATFORM(WIN)
+#include <d2d1.h>
+#endif
+
+namespace TestWebKitAPI {
+
+static void testGetAndSet(WebCore::FloatSize size)
+{
+ size.setWidth(101.1f);
+ EXPECT_FLOAT_EQ(101.1f, size.width());
+ size.setHeight(218.2f);
+ EXPECT_FLOAT_EQ(218.2f, size.height());
+}
+
+TEST(FloatSize, DefaultConstruction)
+{
+ WebCore::FloatSize test;
+
+ EXPECT_FLOAT_EQ(0, test.width());
+ EXPECT_FLOAT_EQ(0, test.height());
+
+ ASSERT_TRUE(test.isEmpty());
+ ASSERT_TRUE(test.isZero());
+
+ testGetAndSet(test);
+}
+
+TEST(FloatSize, ValueConstruction)
+{
+ WebCore::FloatSize test(1024.0f, 768.0f);
+
+ EXPECT_FLOAT_EQ(1024.0f, test.width());
+ EXPECT_FLOAT_EQ(768.0f, test.height());
+
+ ASSERT_FALSE(test.isEmpty());
+ ASSERT_FALSE(test.isZero());
+
+ static const float epsilon = 0.0001f;
+ EXPECT_NEAR(1.3333f, test.aspectRatio(), epsilon);
+
+ testGetAndSet(test);
+}
+
+TEST(FloatSize, IntSizeConstruction)
+{
+ WebCore::IntSize size(1024, 768);
+ WebCore::FloatSize test(size);
+
+ EXPECT_FLOAT_EQ(1024.0f, test.width());
+ EXPECT_FLOAT_EQ(768.0f, test.height());
+
+ ASSERT_FALSE(test.isEmpty());
+ ASSERT_FALSE(test.isZero());
+
+ static const double epsilon = 0.0001;
+ EXPECT_NEAR(1.3333f, test.aspectRatio(), epsilon);
+
+ testGetAndSet(test);
+}
+
+TEST(FloatSize, Scale)
+{
+ WebCore::FloatSize test(1024.0f, 768.0f);
+
+ test.scale(2.0f);
+
+ EXPECT_FLOAT_EQ(2048.0f, test.width());
+ EXPECT_FLOAT_EQ(1536.0f, test.height());
+
+ test.scale(0.5f);
+
+ EXPECT_FLOAT_EQ(1024.0f, test.width());
+ EXPECT_FLOAT_EQ(768.0f, test.height());
+
+ test.scale(2.0f, 0.5f);
+
+ EXPECT_FLOAT_EQ(2048.0f, test.width());
+ EXPECT_FLOAT_EQ(384.0f, test.height());
+}
+
+TEST(FloatSize, Expand)
+{
+ WebCore::FloatSize test(1024.0f, 768.0f);
+
+ EXPECT_FLOAT_EQ(1024.0f, test.width());
+ EXPECT_FLOAT_EQ(768.0f, test.height());
+
+ test.expand(100.0f, 50.0f);
+
+ EXPECT_FLOAT_EQ(1124.0f, test.width());
+ EXPECT_FLOAT_EQ(818.0f, test.height());
+
+ WebCore::FloatSize other(2048.0f, 700.0f);
+
+ auto expanded = test.expandedTo(other);
+
+ EXPECT_FLOAT_EQ(2048.0f, expanded.width());
+ EXPECT_FLOAT_EQ(818.0f, expanded.height());
+}
+
+TEST(FloatSize, Shrink)
+{
+ WebCore::FloatSize test(1024.0f, 768.0f);
+ WebCore::FloatSize other(1000.0f, 700.0f);
+
+ auto shrunken = test.shrunkTo(other);
+
+ EXPECT_FLOAT_EQ(1000.0f, shrunken.width());
+ EXPECT_FLOAT_EQ(700.0f, shrunken.height());
+
+ WebCore::FloatSize other2(2000.0f, 700.0f);
+
+ auto shrunken2 = test.shrunkTo(other2);
+
+ EXPECT_FLOAT_EQ(1024.0f, shrunken2.width());
+ EXPECT_FLOAT_EQ(700.0f, shrunken2.height());
+}
+
+TEST(FloatSize, DiagonalLengthAndArea)
+{
+ WebCore::FloatSize test(1024.0f, 768.0f);
+
+ EXPECT_FLOAT_EQ(1280.0f, test.diagonalLength());
+ EXPECT_FLOAT_EQ(1638400.0f, test.diagonalLengthSquared());
+ EXPECT_FLOAT_EQ(786432.0f, test.area());
+}
+
+TEST(FloatSize, TransposedSize)
+{
+ WebCore::FloatSize test(1024.0f, 768.0f);
+
+ auto transposedSize = test.transposedSize();
+
+ EXPECT_FLOAT_EQ(768.0f, transposedSize.width());
+ EXPECT_FLOAT_EQ(1024.0f, transposedSize.height());
+}
+
+TEST(FloatSize, Casting)
+{
+ WebCore::FloatSize test(1024.0f, 768.0f);
+
+#if USE(CG)
+ CGSize cgSize = test;
+
+ EXPECT_FLOAT_EQ(1024.0f, cgSize.width);
+ EXPECT_FLOAT_EQ(768.0f, cgSize.height);
+
+ CGSize cgSize2 = CGSizeMake(-22.3f, 14.2f);
+
+ WebCore::FloatSize testCG(cgSize2);
+
+ EXPECT_FLOAT_EQ(-22.3f, testCG.width());
+ EXPECT_FLOAT_EQ(14.2f, testCG.height());
+#endif
+
+#if PLATFORM(WIN)
+ D2D1_SIZE_F d2dSize = test;
+
+ EXPECT_FLOAT_EQ(1024.0f, d2dSize.width);
+ EXPECT_FLOAT_EQ(768.0f, d2dSize.height);
+
+ D2D1_SIZE_F d2dSize2 = D2D1::SizeF(-22.3f, 14.2f);
+
+ WebCore::FloatSize testD2D(d2dSize2);
+
+ EXPECT_FLOAT_EQ(-22.3f, testD2D.width());
+ EXPECT_FLOAT_EQ(14.2f, testD2D.height());
+#endif
+}
+
+TEST(FloatSize, AddSubtract)
+{
+ WebCore::FloatSize a(512.0f, 384.0f);
+ WebCore::FloatSize b(100.0f, 100.0f);
+
+ WebCore::FloatSize c = a + b;
+
+ EXPECT_FLOAT_EQ(612.0f, c.width());
+ EXPECT_FLOAT_EQ(484.0f, c.height());
+
+ a += b;
+
+ EXPECT_FLOAT_EQ(612.0f, a.width());
+ EXPECT_FLOAT_EQ(484.0f, a.height());
+
+ WebCore::FloatSize a2(512.0f, 384.0f);
+
+ WebCore::FloatSize d = a2 - b;
+
+ EXPECT_FLOAT_EQ(412.0f, d.width());
+ EXPECT_FLOAT_EQ(284.0f, d.height());
+
+ a2 -= b;
+
+ EXPECT_FLOAT_EQ(412.0f, a2.width());
+ EXPECT_FLOAT_EQ(284.0f, a2.height());
+}
+
+TEST(FloatSize, Negation)
+{
+ WebCore::FloatSize a(512.0f, 384.0f);
+
+ WebCore::FloatSize negated = -a;
+
+ EXPECT_FLOAT_EQ(-512.0f, negated.width());
+ EXPECT_FLOAT_EQ(-384.0f, negated.height());
+}
+
+TEST(FloatSize, Multiply)
+{
+ WebCore::FloatSize a(512.0f, 384.0f);
+
+ WebCore::FloatSize multiplied = a * 2.0f;
+
+ EXPECT_FLOAT_EQ(1024.0f, multiplied.width());
+ EXPECT_FLOAT_EQ(768.0f, multiplied.height());
+
+ WebCore::FloatSize multiplied2 = 3.0f * a;
+
+ EXPECT_FLOAT_EQ(1536.0f, multiplied2.width());
+ EXPECT_FLOAT_EQ(1152.0f, multiplied2.height());
+
+ WebCore::FloatSize b(1024.0f, 768.0f);
+
+ WebCore::FloatSize multiplied3 = a * b;
+
+ EXPECT_FLOAT_EQ(524288.0f, multiplied3.width());
+ EXPECT_FLOAT_EQ(294912.0f, multiplied3.height());
+}
+
+TEST(FloatSize, Divide)
+{
+ WebCore::FloatSize a(1024.0f, 768.0f);
+
+ WebCore::FloatSize divided = a / 2.0f;
+
+ EXPECT_FLOAT_EQ(512.0f, divided.width());
+ EXPECT_FLOAT_EQ(384.0f, divided.height());
+
+ WebCore::FloatSize b(512.0f, 256.0f);
+
+ WebCore::FloatSize divided2 = 1024.0f / b;
+
+ EXPECT_FLOAT_EQ(2.0f, divided2.width());
+ EXPECT_FLOAT_EQ(4.0f, divided2.height());
+}
+
+TEST(FloatSize, Equality)
+{
+ WebCore::FloatSize a(1024.0f, 768.0f);
+ WebCore::FloatSize b(1024.0f, 768.0f);
+ WebCore::FloatSize c(768.0f, 534.0F);
+
+ ASSERT_TRUE(a == b);
+ ASSERT_FALSE(a != b);
+ ASSERT_FALSE(a == c);
+ ASSERT_TRUE(a != c);
+
+ ASSERT_TRUE(WebCore::areEssentiallyEqual(a, b));
+ ASSERT_FALSE(WebCore::areEssentiallyEqual(a, c));
+}
+
+TEST(FloatSize, Floors)
+{
+ WebCore::FloatSize a(1024.4f, 768.8f);
+
+ WebCore::IntSize floorSize = WebCore::flooredIntSize(a);
+
+ EXPECT_EQ(1024, floorSize.width());
+ EXPECT_EQ(768, floorSize.height());
+
+ WebCore::IntPoint floorPoint = WebCore::flooredIntPoint(a);
+
+ EXPECT_EQ(1024, floorPoint.x());
+ EXPECT_EQ(768, floorPoint.y());
+}
+
+TEST(FloatSize, Rounded)
+{
+ WebCore::FloatSize a(1024.4f, 768.8f);
+
+ WebCore::IntSize roundedSize = WebCore::roundedIntSize(a);
+
+ EXPECT_EQ(1024, roundedSize.width());
+ EXPECT_EQ(769, roundedSize.height());
+
+ WebCore::IntSize expandedSize = WebCore::expandedIntSize(a);
+
+ EXPECT_EQ(1025, expandedSize.width());
+ EXPECT_EQ(769, expandedSize.height());
+}
+
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/GridPosition.cpp b/Tools/TestWebKitAPI/Tests/WebCore/GridPosition.cpp
new file mode 100644
index 000000000..416ebd1f7
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/GridPosition.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 Igalia, S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <WebCore/GridPosition.h>
+
+namespace TestWebKitAPI {
+
+TEST(GridPositionTest, GridPositionLimits)
+{
+
+ WebCore::GridPosition gridPosition;
+
+ gridPosition.setExplicitPosition(999999, "");
+ EXPECT_EQ(gridPosition.integerPosition(), 999999);
+ gridPosition.setExplicitPosition(1000000, "");
+ EXPECT_EQ(gridPosition.integerPosition(), 1000000);
+ gridPosition.setExplicitPosition(1000001, "");
+ EXPECT_EQ(gridPosition.integerPosition(), 1000000);
+ gridPosition.setExplicitPosition(INT_MAX, "");
+ EXPECT_EQ(gridPosition.integerPosition(), 1000000);
+ gridPosition.setExplicitPosition(-999999, "");
+ EXPECT_EQ(gridPosition.integerPosition(), -999999);
+ gridPosition.setExplicitPosition(-1000000, "");
+ EXPECT_EQ(gridPosition.integerPosition(), -1000000);
+ gridPosition.setExplicitPosition(-1000001, "");
+ EXPECT_EQ(gridPosition.integerPosition(), -1000000);
+ gridPosition.setExplicitPosition(INT_MIN, "");
+ EXPECT_EQ(gridPosition.integerPosition(), -1000000);
+
+ gridPosition.setSpanPosition(999999, "");
+ EXPECT_EQ(gridPosition.spanPosition(), 999999);
+ gridPosition.setSpanPosition(1000000, "");
+ EXPECT_EQ(gridPosition.spanPosition(), 1000000);
+ gridPosition.setSpanPosition(1000001, "");
+ EXPECT_EQ(gridPosition.spanPosition(), 1000000);
+ gridPosition.setSpanPosition(INT_MAX, "");
+ EXPECT_EQ(gridPosition.spanPosition(), 1000000);
+ gridPosition.setSpanPosition(-999999, "");
+ EXPECT_EQ(gridPosition.spanPosition(), -999999);
+ gridPosition.setSpanPosition(-1000000, "");
+ EXPECT_EQ(gridPosition.spanPosition(), -1000000);
+ gridPosition.setSpanPosition(-1000001, "");
+ EXPECT_EQ(gridPosition.spanPosition(), -1000000);
+ gridPosition.setSpanPosition(INT_MIN, "");
+ EXPECT_EQ(gridPosition.spanPosition(), -1000000);
+
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/HTMLParserIdioms.cpp b/Tools/TestWebKitAPI/Tests/WebCore/HTMLParserIdioms.cpp
new file mode 100644
index 000000000..6e9e738ab
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/HTMLParserIdioms.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "Test.h"
+#include <WebCore/HTMLParserIdioms.h>
+#include <wtf/text/WTFString.h>
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+static int testParseHTMLInteger(const String& input)
+{
+ auto optionalResult = parseHTMLInteger(input);
+ EXPECT_TRUE(!!optionalResult);
+ return optionalResult.value_or(0);
+}
+
+static bool parseHTMLIntegerFails(const String& input)
+{
+ return !parseHTMLInteger(input);
+}
+
+TEST(WebCoreHTMLParserIdioms, parseHTMLInteger)
+{
+ EXPECT_EQ(0, testParseHTMLInteger("0"));
+ EXPECT_EQ(0, testParseHTMLInteger("-0"));
+ EXPECT_EQ(0, testParseHTMLInteger("+0"));
+ EXPECT_EQ(123, testParseHTMLInteger("123"));
+ EXPECT_EQ(123, testParseHTMLInteger("+123"));
+ EXPECT_EQ(-123, testParseHTMLInteger("-123"));
+ EXPECT_EQ(123, testParseHTMLInteger(" 123"));
+ EXPECT_EQ(123, testParseHTMLInteger("123 "));
+ EXPECT_EQ(123, testParseHTMLInteger(" 123 "));
+ EXPECT_EQ(123, testParseHTMLInteger("123abc"));
+ EXPECT_EQ(-123, testParseHTMLInteger("-123abc"));
+ EXPECT_EQ(123, testParseHTMLInteger(" +123"));
+ EXPECT_EQ(-123, testParseHTMLInteger(" -123"));
+ EXPECT_EQ(12, testParseHTMLInteger(" 12 3"));
+ EXPECT_EQ(1, testParseHTMLInteger("1.0"));
+ EXPECT_EQ(1, testParseHTMLInteger("1."));
+ EXPECT_EQ(1, testParseHTMLInteger("1e1"));
+
+ // All HTML whitespaces.
+ EXPECT_EQ(123, testParseHTMLInteger(" \t\r\n\f123"));
+
+ // Boundaries.
+ EXPECT_EQ(-2147483648, testParseHTMLInteger("-2147483648"));
+ EXPECT_EQ(2147483647, testParseHTMLInteger("2147483647"));
+
+ // Failure cases.
+ EXPECT_TRUE(parseHTMLIntegerFails("-2147483649"));
+ EXPECT_TRUE(parseHTMLIntegerFails("2147483648"));
+ EXPECT_TRUE(parseHTMLIntegerFails("111111111111111111"));
+ EXPECT_TRUE(parseHTMLIntegerFails(""));
+ EXPECT_TRUE(parseHTMLIntegerFails(" "));
+ EXPECT_TRUE(parseHTMLIntegerFails(" "));
+ EXPECT_TRUE(parseHTMLIntegerFails("+"));
+ EXPECT_TRUE(parseHTMLIntegerFails("+ 123"));
+ EXPECT_TRUE(parseHTMLIntegerFails("-"));
+ EXPECT_TRUE(parseHTMLIntegerFails("- 123"));
+ EXPECT_TRUE(parseHTMLIntegerFails("a"));
+ EXPECT_TRUE(parseHTMLIntegerFails("-a"));
+ EXPECT_TRUE(parseHTMLIntegerFails("+-123"));
+ EXPECT_TRUE(parseHTMLIntegerFails("-+123"));
+ EXPECT_TRUE(parseHTMLIntegerFails("++123"));
+ EXPECT_TRUE(parseHTMLIntegerFails("--123"));
+ EXPECT_TRUE(parseHTMLIntegerFails("\v123")); // '\v' is an ASCII space but not an HTML whitespace.
+ EXPECT_TRUE(parseHTMLIntegerFails("a123"));
+ EXPECT_TRUE(parseHTMLIntegerFails("+a123"));
+ EXPECT_TRUE(parseHTMLIntegerFails("-a123"));
+ EXPECT_TRUE(parseHTMLIntegerFails(".1"));
+ EXPECT_TRUE(parseHTMLIntegerFails("infinity"));
+}
+
+static unsigned testParseHTMLNonNegativeInteger(const String& input)
+{
+ auto optionalResult = parseHTMLNonNegativeInteger(input);
+ EXPECT_TRUE(!!optionalResult);
+ return optionalResult.value_or(0);
+}
+
+static bool parseHTMLNonNegativeIntegerFails(const String& input)
+{
+ return !parseHTMLNonNegativeInteger(input);
+}
+
+TEST(WebCoreHTMLParserIdioms, parseHTMLNonNegativeInteger)
+{
+ EXPECT_EQ(123u, testParseHTMLNonNegativeInteger("123"));
+ EXPECT_EQ(123u, testParseHTMLNonNegativeInteger("+123"));
+ EXPECT_EQ(123u, testParseHTMLNonNegativeInteger(" 123"));
+ EXPECT_EQ(123u, testParseHTMLNonNegativeInteger("123 "));
+ EXPECT_EQ(123u, testParseHTMLNonNegativeInteger(" 123 "));
+ EXPECT_EQ(123u, testParseHTMLNonNegativeInteger("123abc"));
+ EXPECT_EQ(123u, testParseHTMLNonNegativeInteger(" +123"));
+ EXPECT_EQ(12u, testParseHTMLNonNegativeInteger(" 12 3"));
+ EXPECT_EQ(1u, testParseHTMLNonNegativeInteger("1.0"));
+ EXPECT_EQ(1u, testParseHTMLNonNegativeInteger("1."));
+ EXPECT_EQ(1u, testParseHTMLNonNegativeInteger("1e1"));
+
+ // All HTML whitespaces.
+ EXPECT_EQ(123u, testParseHTMLNonNegativeInteger(" \t\r\n\f123"));
+
+ // Boundaries.
+ EXPECT_EQ(0u, testParseHTMLNonNegativeInteger("+0"));
+ EXPECT_EQ(0u, testParseHTMLNonNegativeInteger("0"));
+ EXPECT_EQ(0u, testParseHTMLNonNegativeInteger("-0"));
+ EXPECT_EQ(2147483647u, testParseHTMLNonNegativeInteger("2147483647"));
+
+ // Failure cases.
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails("-1"));
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails("2147483648"));
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails("2147483649"));
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails("111111111111111111"));
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails(" -123"));
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails("-123"));
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails("-123abc"));
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails(""));
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails(" "));
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails(" "));
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails("+"));
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails("+ 123"));
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails("-"));
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails("- 123"));
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails("a"));
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails("-a"));
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails("+-123"));
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails("-+123"));
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails("++123"));
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails("--123"));
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails("\v123")); // '\v' is an ASCII space but not an HTML whitespace.
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails("a123"));
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails("+a123"));
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails("-a123"));
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails(".1"));
+ EXPECT_TRUE(parseHTMLNonNegativeIntegerFails("infinity"));
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/IntPoint.cpp b/Tools/TestWebKitAPI/Tests/WebCore/IntPoint.cpp
new file mode 100644
index 000000000..aa332e5c3
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/IntPoint.cpp
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <WebCore/FloatPoint.h>
+#include <WebCore/IntPoint.h>
+#include <WebCore/IntSize.h>
+
+#if USE(CG)
+#include <CoreGraphics/CoreGraphics.h>
+#endif
+
+#if PLATFORM(WIN)
+#include <d2d1.h>
+#endif
+
+namespace TestWebKitAPI {
+
+static void testGetAndSet(WebCore::IntPoint point)
+{
+ point.setX(1);
+ EXPECT_EQ(1, point.x());
+ point.setY(2);
+ EXPECT_EQ(2, point.y());
+}
+
+TEST(IntPoint, DefaultConstruction)
+{
+ WebCore::IntPoint test;
+
+ EXPECT_EQ(0, test.x());
+ EXPECT_EQ(0, test.y());
+ ASSERT_TRUE(test.isZero());
+
+ testGetAndSet(test);
+}
+
+TEST(IntPoint, ValueConstruction)
+{
+ WebCore::IntPoint test(10, 9);
+
+ EXPECT_EQ(10, test.x());
+ EXPECT_EQ(9, test.y());
+
+ testGetAndSet(test);
+}
+
+TEST(IntPoint, ZeroConstruction)
+{
+ WebCore::IntPoint test = WebCore::IntPoint::zero();
+
+ EXPECT_EQ(0, test.x());
+ EXPECT_EQ(0, test.y());
+ ASSERT_TRUE(test.isZero());
+}
+
+TEST(IntPoint, IntSizeConstruction)
+{
+ WebCore::IntSize testInput(2003, 1997);
+ WebCore::IntPoint test(testInput);
+
+ EXPECT_EQ(2003, test.x());
+ EXPECT_EQ(1997, test.y());
+ ASSERT_FALSE(test.isZero());
+}
+
+TEST(IntPoint, FloatPointConstruction)
+{
+ WebCore::FloatPoint testInput(2003.2f, 1997.3f);
+ WebCore::IntPoint test(testInput);
+
+ EXPECT_EQ(2003, test.x());
+ EXPECT_EQ(1997, test.y());
+ ASSERT_FALSE(test.isZero());
+}
+
+TEST(IntPoint, Move)
+{
+ WebCore::IntPoint test(10, 20);
+ WebCore::IntSize size(30, 50);
+
+ test.move(size);
+
+ EXPECT_EQ(40, test.x());
+ EXPECT_EQ(70, test.y());
+
+ test.move(-2, 8);
+
+ EXPECT_EQ(38, test.x());
+ EXPECT_EQ(78, test.y());
+
+ WebCore::IntPoint offset(100, 100);
+
+ test.moveBy(offset);
+
+ EXPECT_EQ(138, test.x());
+ EXPECT_EQ(178, test.y());
+}
+
+TEST(IntPoint, Scale)
+{
+ WebCore::IntPoint test(10, 20);
+
+ test.scale(2.0);
+
+ EXPECT_EQ(20, test.x());
+ EXPECT_EQ(40, test.y());
+
+ test.scale(3.0, 1.5);
+
+ EXPECT_EQ(60, test.x());
+ EXPECT_EQ(60, test.y());
+}
+
+TEST(IntPoint, Expand)
+{
+ WebCore::IntPoint a(10, 20);
+ WebCore::IntPoint b(20, 40);
+
+ auto c = a.expandedTo(b);
+
+ EXPECT_EQ(20, c.x());
+ EXPECT_EQ(40, c.y());
+}
+
+TEST(IntPoint, Shrink)
+{
+ WebCore::IntPoint a(10, 20);
+ WebCore::IntPoint b(20, 40);
+
+ auto c = b.shrunkTo(a);
+
+ EXPECT_EQ(10, c.x());
+ EXPECT_EQ(20, c.y());
+}
+
+TEST(IntPoint, Transpose)
+{
+ WebCore::IntPoint a(10, 20);
+
+ auto b = a.transposedPoint();
+
+ EXPECT_EQ(20, b.x());
+ EXPECT_EQ(10, b.y());
+}
+
+TEST(IntPoint, Cast)
+{
+ WebCore::IntPoint a(10, 20);
+
+ WebCore::IntSize as = WebCore::toIntSize(a);
+ EXPECT_EQ(10, as.width());
+ EXPECT_EQ(20, as.height());
+
+#if USE(CG)
+ CGPoint cgPoint = a;
+
+ ASSERT_FLOAT_EQ(10.0f, cgPoint.x);
+ ASSERT_FLOAT_EQ(20.0f, cgPoint.y);
+
+ WebCore::IntPoint fromCGPoint(cgPoint);
+ EXPECT_EQ(10, fromCGPoint.x());
+ EXPECT_EQ(20, fromCGPoint.y());
+ ASSERT_TRUE(a == fromCGPoint);
+#endif
+
+#if PLATFORM(WIN)
+ POINT gdiPoint = a;
+
+ ASSERT_FLOAT_EQ(10.0f, gdiPoint.x);
+ ASSERT_FLOAT_EQ(20.0f, gdiPoint.y);
+
+ WebCore::IntPoint fromGDIPoint(gdiPoint);
+ EXPECT_EQ(10, fromGDIPoint.x());
+ EXPECT_EQ(20, fromGDIPoint.y());
+ ASSERT_TRUE(a == fromGDIPoint);
+
+ D2D1_POINT_2F d2dPointF = a;
+
+ ASSERT_FLOAT_EQ(10.0f, d2dPointF.x);
+ ASSERT_FLOAT_EQ(20.0f, d2dPointF.y);
+
+ WebCore::IntPoint fromD2DPointF(d2dPointF);
+ EXPECT_EQ(10, fromD2DPointF.x());
+ EXPECT_EQ(20, fromD2DPointF.y());
+ ASSERT_TRUE(a == fromD2DPointF);
+
+ D2D1_POINT_2U d2dPointU = a;
+
+ ASSERT_FLOAT_EQ(10.0f, d2dPointU.x);
+ ASSERT_FLOAT_EQ(20.0f, d2dPointU.y);
+
+ WebCore::IntPoint fromD2DPointU(d2dPointU);
+ EXPECT_EQ(10, fromD2DPointU.x());
+ EXPECT_EQ(20, fromD2DPointU.y());
+ ASSERT_TRUE(a == fromD2DPointU);
+#endif
+}
+
+TEST(IntPoint, Addition)
+{
+ WebCore::IntPoint a(10, 20);
+ WebCore::IntPoint b(50, 60);
+ WebCore::IntSize bs(50, 60);
+
+ auto c = a + b;
+
+ EXPECT_EQ(60, c.x());
+ EXPECT_EQ(80, c.y());
+
+ a += bs;
+
+ EXPECT_EQ(60, a.x());
+ EXPECT_EQ(80, a.y());
+}
+
+TEST(IntPoint, Subtraction)
+{
+ WebCore::IntPoint a(100, 80);
+ WebCore::IntPoint b(50, 60);
+ WebCore::IntSize bs(50, 60);
+
+ WebCore::IntSize c = a - b;
+
+ EXPECT_EQ(50, c.width());
+ EXPECT_EQ(20, c.height());
+
+ WebCore::IntPoint d = a - bs;
+
+ EXPECT_EQ(50, d.x());
+ EXPECT_EQ(20, d.y());
+
+ a -= bs;
+
+ EXPECT_EQ(50, a.x());
+ EXPECT_EQ(20, a.y());
+}
+
+TEST(IntPoint, Negation)
+{
+ WebCore::IntPoint a(100, 80);
+ auto b = -a;
+
+ EXPECT_EQ(-100, b.x());
+ EXPECT_EQ(-80, b.y());
+}
+
+TEST(IntPoint, Equality)
+{
+ WebCore::IntPoint a(100, 80);
+ WebCore::IntPoint b(70, 50);
+ WebCore::IntPoint c(100, 80);
+
+ ASSERT_TRUE(a == c);
+ ASSERT_FALSE(a == b);
+ ASSERT_FALSE(a != c);
+ ASSERT_TRUE(a != b);
+}
+
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/IntRect.cpp b/Tools/TestWebKitAPI/Tests/WebCore/IntRect.cpp
new file mode 100644
index 000000000..7392f06a7
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/IntRect.cpp
@@ -0,0 +1,615 @@
+/*
+ * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <WebCore/FloatRect.h>
+#include <WebCore/IntPoint.h>
+#include <WebCore/IntRect.h>
+#include <WebCore/IntSize.h>
+
+#if USE(CG)
+#include <CoreGraphics/CoreGraphics.h>
+#endif
+
+#if PLATFORM(WIN)
+#include <d2d1.h>
+#endif
+
+namespace TestWebKitAPI {
+
+static void testGetAndSet(WebCore::IntRect rect)
+{
+ rect.setX(1);
+ EXPECT_EQ(1, rect.x());
+ rect.setY(2);
+ EXPECT_EQ(2, rect.y());
+ rect.setWidth(203);
+ EXPECT_EQ(203, rect.width());
+ rect.setHeight(73);
+ EXPECT_EQ(73, rect.height());
+}
+
+static void testEmptyRect(const WebCore::IntRect& rect)
+{
+ EXPECT_EQ(0, rect.x());
+ EXPECT_EQ(0, rect.y());
+ EXPECT_EQ(0, rect.width());
+ EXPECT_EQ(0, rect.height());
+ EXPECT_EQ(0, rect.maxX());
+ EXPECT_EQ(0, rect.maxY());
+ EXPECT_TRUE(rect.isEmpty());
+}
+
+TEST(IntRect, DefaultConstruction)
+{
+ WebCore::IntRect test;
+
+ testEmptyRect(test);
+
+ testGetAndSet(test);
+
+ auto location = test.location();
+ EXPECT_EQ(0, location.x());
+ EXPECT_EQ(0, location.y());
+
+ auto size = test.size();
+ EXPECT_EQ(0, size.width());
+ EXPECT_EQ(0, size.height());
+}
+
+TEST(IntRect, ValueConstruction)
+{
+ WebCore::IntRect test(10, 20, 100, 50);
+
+ EXPECT_EQ(10, test.x());
+ EXPECT_EQ(20, test.y());
+ EXPECT_EQ(100, test.width());
+ EXPECT_EQ(50, test.height());
+ EXPECT_EQ(110, test.maxX());
+ EXPECT_EQ(70, test.maxY());
+ EXPECT_FALSE(test.isEmpty());
+
+ auto location = test.location();
+ EXPECT_EQ(10, location.x());
+ EXPECT_EQ(20, location.y());
+
+ auto size = test.size();
+ EXPECT_EQ(100, size.width());
+ EXPECT_EQ(50, size.height());
+}
+
+TEST(IntRect, PointSizeConstruction)
+{
+ WebCore::IntPoint location(20, 30);
+ WebCore::IntSize size(100, 50);
+
+ WebCore::IntRect test(location, size);
+
+ EXPECT_EQ(20, test.x());
+ EXPECT_EQ(30, test.y());
+ EXPECT_EQ(100, test.width());
+ EXPECT_EQ(50, test.height());
+ EXPECT_EQ(120, test.maxX());
+ EXPECT_EQ(80, test.maxY());
+ EXPECT_FALSE(test.isEmpty());
+
+ auto location2 = test.location();
+ EXPECT_EQ(20, location2.x());
+ EXPECT_EQ(30, location2.y());
+
+ auto size2 = test.size();
+ EXPECT_EQ(100, size2.width());
+ EXPECT_EQ(50, size2.height());
+}
+
+TEST(IntRect, FloatRectConstruction)
+{
+ WebCore::FloatRect rect(20.0f, 30.0f, 150.0f, 300.0f);
+
+ WebCore::IntRect test(rect);
+
+ EXPECT_EQ(20, test.x());
+ EXPECT_EQ(30, test.y());
+ EXPECT_EQ(150, test.width());
+ EXPECT_EQ(300, test.height());
+ EXPECT_EQ(170, test.maxX());
+ EXPECT_EQ(330, test.maxY());
+ EXPECT_FALSE(test.isEmpty());
+
+ auto location = test.location();
+ EXPECT_EQ(20, location.x());
+ EXPECT_EQ(30, location.y());
+
+ auto size = test.size();
+ EXPECT_EQ(150, size.width());
+ EXPECT_EQ(300, size.height());
+}
+
+TEST(IntRect, SetLocationAndSize)
+{
+ WebCore::IntRect rect;
+
+ testEmptyRect(rect);
+
+ WebCore::IntPoint location(10, 20);
+
+ rect.setLocation(location);
+
+ EXPECT_EQ(10, rect.x());
+ EXPECT_EQ(20, rect.y());
+ EXPECT_EQ(0, rect.width());
+ EXPECT_EQ(0, rect.height());
+ EXPECT_EQ(10, rect.maxX());
+ EXPECT_EQ(20, rect.maxY());
+ EXPECT_TRUE(rect.isEmpty());
+
+ WebCore::IntSize size(100, 200);
+
+ rect.setSize(size);
+
+ EXPECT_EQ(10, rect.x());
+ EXPECT_EQ(20, rect.y());
+ EXPECT_EQ(100, rect.width());
+ EXPECT_EQ(200, rect.height());
+ EXPECT_EQ(110, rect.maxX());
+ EXPECT_EQ(220, rect.maxY());
+ EXPECT_FALSE(rect.isEmpty());
+}
+
+TEST(IntRect, Center)
+{
+ WebCore::IntRect rect(20, 40, 100, 200);
+
+ auto center = rect.center();
+
+ EXPECT_EQ(70, center.x());
+ EXPECT_EQ(140, center.y());
+}
+
+TEST(IntRect, Move)
+{
+ WebCore::IntRect rect(20, 30, 100, 200);
+
+ WebCore::IntSize delta(10, 20);
+
+ rect.move(delta);
+
+ EXPECT_EQ(30, rect.x());
+ EXPECT_EQ(50, rect.y());
+
+ WebCore::IntPoint deltaPoint(-20, -40);
+
+ rect.moveBy(deltaPoint);
+
+ EXPECT_EQ(10, rect.x());
+ EXPECT_EQ(10, rect.y());
+
+ rect.move(-10, 22);
+
+ EXPECT_EQ(0, rect.x());
+ EXPECT_EQ(32, rect.y());
+}
+
+TEST(IntRect, Expand)
+{
+ WebCore::IntRect rect(20, 30, 100, 200);
+
+ WebCore::IntSize size(100, 100);
+
+ rect.expand(size);
+
+ EXPECT_EQ(200, rect.width());
+ EXPECT_EQ(300, rect.height());
+
+ rect.expand(55, 22);
+
+ EXPECT_EQ(255, rect.width());
+ EXPECT_EQ(322, rect.height());
+
+ WebCore::IntSize size2(-10, -20);
+
+ rect.expand(size2);
+
+ EXPECT_EQ(245, rect.width());
+ EXPECT_EQ(302, rect.height());
+
+ rect.expand(-5, -2);
+
+ EXPECT_EQ(240, rect.width());
+ EXPECT_EQ(300, rect.height());
+}
+
+TEST(IntRect, Contract)
+{
+ WebCore::IntRect rect(20, 30, 100, 200);
+
+ WebCore::IntSize size(50, 100);
+
+ rect.contract(size);
+
+ EXPECT_EQ(50, rect.width());
+ EXPECT_EQ(100, rect.height());
+
+ rect.contract(25, 22);
+
+ EXPECT_EQ(25, rect.width());
+ EXPECT_EQ(78, rect.height());
+
+ WebCore::IntSize size2(-10, -20);
+
+ rect.contract(size2);
+
+ EXPECT_EQ(35, rect.width());
+ EXPECT_EQ(98, rect.height());
+
+ rect.contract(-5, -2);
+
+ EXPECT_EQ(40, rect.width());
+ EXPECT_EQ(100, rect.height());
+}
+
+TEST(IntRect, ShiftXEdge)
+{
+ WebCore::IntRect rect(20, 30, 100, 200);
+
+ rect.shiftXEdgeTo(77);
+
+ EXPECT_EQ(77, rect.x());
+ EXPECT_EQ(120, rect.maxX());
+ EXPECT_EQ(30, rect.y());
+ EXPECT_EQ(230, rect.maxY());
+ EXPECT_EQ(43, rect.width());
+ EXPECT_EQ(200, rect.height());
+
+ rect.shiftMaxXEdgeTo(200);
+
+ EXPECT_EQ(77, rect.x());
+ EXPECT_EQ(200, rect.maxX());
+ EXPECT_EQ(30, rect.y());
+ EXPECT_EQ(230, rect.maxY());
+ EXPECT_EQ(123, rect.width());
+ EXPECT_EQ(200, rect.height());
+}
+
+TEST(IntRect, ShiftYEdge)
+{
+ WebCore::IntRect rect(20, 30, 100, 200);
+
+ rect.shiftYEdgeTo(59.0f);
+
+ EXPECT_EQ(20, rect.x());
+ EXPECT_EQ(120, rect.maxX());
+ EXPECT_EQ(59, rect.y());
+ EXPECT_EQ(230, rect.maxY());
+ EXPECT_EQ(100, rect.width());
+ EXPECT_EQ(171, rect.height());
+
+ rect.shiftMaxYEdgeTo(270.0f);
+
+ EXPECT_EQ(20, rect.x());
+ EXPECT_EQ(120, rect.maxX());
+ EXPECT_EQ(59, rect.y());
+ EXPECT_EQ(270, rect.maxY());
+ EXPECT_EQ(100, rect.width());
+ EXPECT_EQ(211, rect.height());
+}
+
+TEST(IntRect, Inflate)
+{
+ WebCore::IntRect rect(20, 30, 100, 200);
+
+ rect.inflateX(5);
+
+ EXPECT_EQ(15, rect.x());
+ EXPECT_EQ(125, rect.maxX());
+
+ rect.inflateY(4);
+
+ EXPECT_EQ(26, rect.y());
+ EXPECT_EQ(234, rect.maxY());
+
+ rect.inflate(10);
+
+ EXPECT_EQ(5, rect.x());
+ EXPECT_EQ(135, rect.maxX());
+ EXPECT_EQ(16, rect.y());
+ EXPECT_EQ(244, rect.maxY());
+}
+
+TEST(IntRect, Corners)
+{
+ WebCore::IntRect rect(20, 30, 100, 200);
+
+ WebCore::FloatPoint topLeft = rect.minXMinYCorner();
+ EXPECT_EQ(20, topLeft.x());
+ EXPECT_EQ(30, topLeft.y());
+
+ WebCore::FloatPoint topRight = rect.maxXMinYCorner();
+ EXPECT_EQ(120, topRight.x());
+ EXPECT_EQ(30, topRight.y());
+
+ WebCore::FloatPoint bottomLeft = rect.minXMaxYCorner();
+ EXPECT_EQ(20, bottomLeft.x());
+ EXPECT_EQ(230, bottomLeft.y());
+
+ WebCore::FloatPoint bottomRight = rect.maxXMaxYCorner();
+ EXPECT_EQ(120, bottomRight.x());
+ EXPECT_EQ(230, bottomRight.y());
+}
+
+TEST(IntRect, Contains)
+{
+ WebCore::IntRect rect(20, 30, 100, 200);
+
+ WebCore::IntRect contained(30, 40, 50, 100);
+
+ ASSERT_TRUE(rect.contains(contained));
+
+ WebCore::IntRect outside(120, 230, 50, 100);
+
+ ASSERT_FALSE(rect.contains(outside));
+
+ WebCore::IntRect intersects(10, 20, 90, 180);
+
+ ASSERT_FALSE(rect.contains(intersects));
+
+ WebCore::IntPoint pointInside(60, 70);
+
+ ASSERT_TRUE(rect.contains(pointInside));
+
+ WebCore::IntPoint pointOutside(160, 270);
+
+ ASSERT_FALSE(rect.contains(pointOutside));
+
+ WebCore::IntPoint pointOnLine(20, 30);
+
+ ASSERT_TRUE(rect.contains(pointOnLine));
+
+ ASSERT_TRUE(rect.contains(60, 70));
+ ASSERT_FALSE(rect.contains(160, 270));
+}
+
+TEST(IntRect, Intersects)
+{
+ WebCore::IntRect rect(20, 30, 100, 200);
+
+ WebCore::IntRect contained(30, 40, 50, 100);
+
+ ASSERT_TRUE(rect.intersects(contained));
+
+ WebCore::IntRect outside(120, 230, 50, 100);
+
+ ASSERT_FALSE(rect.intersects(outside));
+
+ WebCore::IntRect intersects(10, 20, 90, 180);
+
+ ASSERT_TRUE(rect.intersects(intersects));
+}
+
+static void testIntersectResult(const WebCore::IntRect& rect)
+{
+ EXPECT_EQ(70, rect.x());
+ EXPECT_EQ(120, rect.maxX());
+ EXPECT_EQ(80, rect.y());
+ EXPECT_EQ(230, rect.maxY());
+}
+
+TEST(IntRect, Intersect)
+{
+ WebCore::IntRect rectA(20, 30, 100, 200);
+ WebCore::IntRect rectB(70, 80, 100, 200);
+
+ rectA.intersect(rectB);
+
+ testIntersectResult(rectA);
+
+ WebCore::IntRect rectC(20, 30, 100, 200);
+
+ auto intersected = WebCore::intersection(rectC, rectB);
+
+ testIntersectResult(intersected);
+}
+
+static void testUnitedRects(const WebCore::IntRect& united)
+{
+ EXPECT_EQ(20, united.x());
+ EXPECT_EQ(170, united.maxX());
+ EXPECT_EQ(30, united.y());
+ EXPECT_EQ(280, united.maxY());
+}
+
+TEST(IntRect, Unite)
+{
+ WebCore::IntRect rectA(20, 30, 100, 200);
+ WebCore::IntRect rectB(70, 80, 100, 200);
+
+ rectA.unite(rectB);
+
+ testUnitedRects(rectA);
+
+ WebCore::IntRect rectC(20, 30, 100, 200);
+
+ auto united = WebCore::unionRect(rectC, rectB);
+
+ testUnitedRects(united);
+}
+
+TEST(IntRect, Scale)
+{
+ WebCore::IntRect rect(20, 30, 100, 200);
+
+ rect.scale(2.0f);
+
+ EXPECT_EQ(40, rect.x());
+ EXPECT_EQ(240, rect.maxX());
+ EXPECT_EQ(60, rect.y());
+ EXPECT_EQ(460, rect.maxY());
+}
+
+TEST(IntRect, Transpose)
+{
+ WebCore::IntRect rect(20, 30, 100, 200);
+
+ auto transposed = rect.transposedRect();
+
+ EXPECT_EQ(30, transposed.x());
+ EXPECT_EQ(230, transposed.maxX());
+ EXPECT_EQ(20, transposed.y());
+ EXPECT_EQ(120, transposed.maxY());
+}
+
+static void checkCastRect(const WebCore::IntRect& rect)
+{
+ EXPECT_EQ(10, rect.x());
+ EXPECT_EQ(40, rect.maxX());
+ EXPECT_EQ(20, rect.y());
+ EXPECT_EQ(60, rect.maxY());
+ EXPECT_EQ(30, rect.width());
+ EXPECT_EQ(40, rect.height());
+}
+
+TEST(IntRect, Casting)
+{
+ WebCore::IntRect rect(10, 20, 30, 40);
+
+#if USE(CG)
+ CGRect cgRect = CGRectMake(10.0, 20.0, 30.0, 40.0);
+
+ WebCore::IntRect rectFromCGRect(cgRect);
+
+ checkCastRect(rectFromCGRect);
+#endif
+
+#if PLATFORM(WIN)
+ RECT gdiRect = rect;
+
+ EXPECT_EQ(10, gdiRect.left);
+ EXPECT_EQ(20, gdiRect.top);
+ EXPECT_EQ(40, gdiRect.right);
+ EXPECT_EQ(60, gdiRect.bottom);
+
+ WebCore::IntRect rectFromGDIRect(gdiRect);
+
+ checkCastRect(rectFromGDIRect);
+
+ D2D1_RECT_U d2dRectU = rect;
+
+ EXPECT_EQ(10, d2dRectU.left);
+ EXPECT_EQ(20, d2dRectU.top);
+ EXPECT_EQ(40, d2dRectU.right);
+ EXPECT_EQ(60, d2dRectU.bottom);
+
+ WebCore::IntRect rectFromD2DRectU(d2dRectU);
+
+ checkCastRect(rectFromD2DRectU);
+
+ D2D1_RECT_F d2dRectF = rect;
+
+ EXPECT_FLOAT_EQ(10.0f, d2dRectF.left);
+ EXPECT_FLOAT_EQ(20.0f, d2dRectF.top);
+ EXPECT_FLOAT_EQ(40.0f, d2dRectF.right);
+ EXPECT_FLOAT_EQ(60.0f, d2dRectF.bottom);
+
+ WebCore::IntRect rectFromD2DRectF(d2dRectF);
+
+ checkCastRect(rectFromD2DRectF);
+#endif
+}
+
+static void checkSubtractionResult1(const WebCore::IntRect& rect)
+{
+ EXPECT_EQ(-10, rect.x());
+ EXPECT_EQ(90, rect.maxX());
+ EXPECT_EQ(-10, rect.y());
+ EXPECT_EQ(90, rect.maxY());
+ EXPECT_EQ(100, rect.width());
+ EXPECT_EQ(100, rect.height());
+}
+
+static void checkSubtractionResult2(const WebCore::IntRect& rect)
+{
+ EXPECT_EQ(-40, rect.x());
+ EXPECT_EQ(60, rect.maxX());
+ EXPECT_EQ(-50, rect.y());
+ EXPECT_EQ(50, rect.maxY());
+ EXPECT_EQ(100, rect.width());
+ EXPECT_EQ(100, rect.height());
+}
+
+TEST(IntRect, Subtraction)
+{
+ WebCore::IntRect rect(10, 20, 100, 100);
+ WebCore::IntPoint rightSide(20, 30);
+
+ rect -= rightSide;
+
+ checkSubtractionResult1(rect);
+
+ auto rect2 = rect - WebCore::IntPoint(30, 40);
+ checkSubtractionResult2(rect2);
+}
+
+TEST(IntRect, Equality)
+{
+ WebCore::IntRect rect(10, 20, 100, 100);
+ WebCore::IntRect rect2(10, 20, 100, 100);
+ WebCore::IntRect rightSide(110, 20, 20, 100);
+
+ ASSERT_TRUE(rect == rect2);
+ ASSERT_FALSE(rect != rect2);
+ ASSERT_TRUE(rect != rightSide);
+ ASSERT_FALSE(rect == rightSide);
+}
+
+static void checkEnclosingIntRect(const WebCore::IntRect& rect)
+{
+ EXPECT_EQ(10, rect.x());
+ EXPECT_EQ(41, rect.maxX());
+ EXPECT_EQ(21, rect.y());
+ EXPECT_EQ(62, rect.maxY());
+ EXPECT_EQ(31, rect.width());
+ EXPECT_EQ(41, rect.height());
+}
+
+TEST(IntRect, EnclosingIntRect)
+{
+#if USE(CG)
+ CGRect cgRect = CGRectMake(10.5, 21.3, 30.1, 40.0);
+
+ WebCore::IntRect enclosingCG = WebCore::enclosingIntRect(cgRect);
+
+ checkEnclosingIntRect(enclosingCG);
+#endif
+}
+
+TEST(IntRect, AreaAndDistances)
+{
+ WebCore::IntRect rect(10, 20, 100, 100);
+
+ EXPECT_EQ(10000U, rect.area().unsafeGet());
+}
+
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/IntSize.cpp b/Tools/TestWebKitAPI/Tests/WebCore/IntSize.cpp
new file mode 100644
index 000000000..a55942f74
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/IntSize.cpp
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <WebCore/FloatSize.h>
+#include <WebCore/IntSize.h>
+
+#if USE(CG)
+#include <CoreGraphics/CoreGraphics.h>
+#endif
+
+#if PLATFORM(WIN)
+#include <d2d1.h>
+#endif
+
+namespace TestWebKitAPI {
+
+static void testGetAndSet(WebCore::IntSize rect)
+{
+ rect.setWidth(203);
+ EXPECT_EQ(203, rect.width());
+ rect.setHeight(73);
+ EXPECT_EQ(73, rect.height());
+}
+
+static void testEmptySize(const WebCore::IntSize& rect)
+{
+ EXPECT_EQ(0, rect.width());
+ EXPECT_EQ(0, rect.height());
+ EXPECT_TRUE(rect.isEmpty());
+ EXPECT_TRUE(rect.isZero());
+}
+
+TEST(IntSize, DefaultConstruction)
+{
+ WebCore::IntSize test;
+
+ testEmptySize(test);
+
+ testGetAndSet(test);
+}
+
+TEST(IntSize, ValueConstruction)
+{
+ WebCore::IntSize test(100, 200);
+
+ EXPECT_EQ(100, test.width());
+ EXPECT_EQ(200, test.height());
+ EXPECT_FALSE(test.isEmpty());
+ EXPECT_FALSE(test.isZero());
+
+ static const float epsilon = 0.0001f;
+ EXPECT_NEAR(0.5f, test.aspectRatio(), epsilon);
+}
+
+TEST(IntSize, FloatSizeConstruction)
+{
+ WebCore::FloatSize size(1024.2, 767.8);
+ WebCore::IntSize test(size);
+
+ EXPECT_EQ(1024, test.width());
+ EXPECT_EQ(767, test.height());
+
+ ASSERT_FALSE(test.isEmpty());
+ ASSERT_FALSE(test.isZero());
+
+ static const double epsilon = 0.001;
+ EXPECT_NEAR(1.335f, test.aspectRatio(), epsilon);
+
+ testGetAndSet(test);
+}
+
+TEST(IntSize, DiagonalLengthAndArea)
+{
+ WebCore::IntSize test(1024, 768);
+
+ EXPECT_EQ(1638400, test.diagonalLengthSquared());
+ EXPECT_EQ(786432U, test.area().unsafeGet());
+}
+
+TEST(IntSize, Scale)
+{
+ WebCore::IntSize test(1024, 768);
+
+ test.scale(2.0f);
+
+ EXPECT_EQ(2048, test.width());
+ EXPECT_EQ(1536, test.height());
+
+ test.scale(0.5f);
+
+ EXPECT_EQ(1024, test.width());
+ EXPECT_EQ(768, test.height());
+
+ test.scale(2.0f, 0.5f);
+
+ EXPECT_EQ(2048, test.width());
+ EXPECT_EQ(384, test.height());
+}
+
+TEST(IntSize, Expand)
+{
+ WebCore::IntSize test(1024, 768);
+
+ EXPECT_EQ(1024, test.width());
+ EXPECT_EQ(768, test.height());
+
+ test.expand(100, 50);
+
+ EXPECT_EQ(1124, test.width());
+ EXPECT_EQ(818, test.height());
+
+ WebCore::IntSize other(2048, 700);
+
+ auto expanded = test.expandedTo(other);
+
+ EXPECT_EQ(2048, expanded.width());
+ EXPECT_EQ(818, expanded.height());
+}
+
+TEST(IntSize, Shrink)
+{
+ WebCore::IntSize test(1024, 768);
+ WebCore::IntSize other(1000, 700);
+
+ auto shrunken = test.shrunkTo(other);
+
+ EXPECT_EQ(1000, shrunken.width());
+ EXPECT_EQ(700, shrunken.height());
+
+ WebCore::IntSize other2(2000.0f, 700.0f);
+
+ auto shrunken2 = test.shrunkTo(other2);
+
+ EXPECT_EQ(1024, shrunken2.width());
+ EXPECT_EQ(700, shrunken2.height());
+}
+
+TEST(IntSize, TransposedSize)
+{
+ WebCore::IntSize test(1024, 768);
+
+ auto transposedSize = test.transposedSize();
+
+ EXPECT_EQ(768, transposedSize.width());
+ EXPECT_EQ(1024, transposedSize.height());
+}
+
+TEST(IntSize, Casting)
+{
+ WebCore::IntSize test(1024, 768);
+
+#if USE(CG)
+ CGSize cgSize = test;
+
+ EXPECT_FLOAT_EQ(1024.0f, cgSize.width);
+ EXPECT_FLOAT_EQ(768.0f, cgSize.height);
+
+ CGSize cgSize2 = CGSizeMake(-22.3f, 14.6f);
+
+ WebCore::IntSize testCG(cgSize2);
+
+ EXPECT_EQ(-22, testCG.width());
+ EXPECT_EQ(14, testCG.height());
+#endif
+
+#if PLATFORM(WIN)
+ D2D1_SIZE_U d2dSizeU = test;
+ EXPECT_EQ(1024, d2dSizeU.width);
+ EXPECT_EQ(768, d2dSizeU.height);
+
+ D2D1_SIZE_F d2dSizeF = test;
+ EXPECT_FLOAT_EQ(1024.0f, d2dSizeF.width);
+ EXPECT_FLOAT_EQ(768.0f, d2dSizeF.height);
+
+ D2D1_SIZE_F d2dSizeF2 = D2D1::SizeF(-22.3f, 14.6f);
+
+ WebCore::IntSize testD2D(d2dSizeF2);
+
+ EXPECT_EQ(-22, testD2D.width());
+ EXPECT_EQ(14, testD2D.height());
+
+ D2D1_SIZE_F d2dSizeU2 = D2D1::SizeF(-23, 16);
+
+ WebCore::IntSize testD2D2(d2dSizeU2);
+
+ EXPECT_EQ(-23, testD2D2.width());
+ EXPECT_EQ(16, testD2D2.height());
+#endif
+}
+
+TEST(IntSize, AddSubtract)
+{
+ WebCore::IntSize a(512, 384);
+ WebCore::IntSize b(100, 100);
+
+ WebCore::IntSize c = a + b;
+
+ EXPECT_EQ(612, c.width());
+ EXPECT_EQ(484, c.height());
+
+ a += b;
+
+ EXPECT_EQ(612, a.width());
+ EXPECT_EQ(484, a.height());
+
+ WebCore::IntSize a2(512, 384);
+
+ WebCore::IntSize d = a2 - b;
+
+ EXPECT_EQ(412, d.width());
+ EXPECT_EQ(284, d.height());
+
+ a2 -= b;
+
+ EXPECT_EQ(412, a2.width());
+ EXPECT_EQ(284, a2.height());
+}
+
+TEST(IntSize, Negation)
+{
+ WebCore::IntSize a(512, 384);
+
+ WebCore::IntSize negated = -a;
+
+ EXPECT_EQ(-512, negated.width());
+ EXPECT_EQ(-384, negated.height());
+}
+
+TEST(IntSize, Equality)
+{
+ WebCore::IntSize a(1024, 768);
+ WebCore::IntSize b(1024, 768);
+ WebCore::IntSize c(768, 534);
+
+ ASSERT_TRUE(a == b);
+ ASSERT_FALSE(a != b);
+ ASSERT_FALSE(a == c);
+ ASSERT_TRUE(a != c);
+}
+
+TEST(IntSize, Contract)
+{
+ WebCore::IntSize a(1024, 768);
+
+ a.contract(100, 50);
+
+ EXPECT_EQ(924, a.width());
+ EXPECT_EQ(718, a.height());
+}
+
+TEST(IntSize, Clamp)
+{
+ WebCore::IntSize a(1024, 768);
+
+ a.clampNegativeToZero();
+
+ EXPECT_EQ(1024, a.width());
+ EXPECT_EQ(768, a.height());
+
+ WebCore::IntSize b(-1024, -768);
+
+ b.clampNegativeToZero();
+
+ EXPECT_EQ(0, b.width());
+ EXPECT_EQ(0, b.height());
+
+ WebCore::IntSize minimumSize(1024, 1000);
+
+ a.clampToMinimumSize(minimumSize);
+
+ EXPECT_EQ(1024, a.width());
+ EXPECT_EQ(1000, a.height());
+}
+
+TEST(IntSize, ConstrainedBetween)
+{
+ WebCore::IntSize minimumSize(384, 256);
+ WebCore::IntSize maximumSize(2048, 1536);
+
+ WebCore::IntSize a(1024, 768);
+
+ auto constrained1 = a.constrainedBetween(minimumSize, maximumSize);
+
+ EXPECT_EQ(1024, constrained1.width());
+ EXPECT_EQ(768, constrained1.height());
+
+ WebCore::IntSize b(200, 100);
+
+ auto constrained2 = b.constrainedBetween(minimumSize, maximumSize);
+
+ EXPECT_EQ(384, constrained2.width());
+ EXPECT_EQ(256, constrained2.height());
+
+ WebCore::IntSize c(5000, 2000);
+
+ auto constrained3 = c.constrainedBetween(minimumSize, maximumSize);
+
+ EXPECT_EQ(2048, constrained3.width());
+ EXPECT_EQ(1536, constrained3.height());
+}
+
+/*
+
+IntSize constrainedBetween(const IntSize& min, const IntSize& max) const;
+
+*/
+
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/LayoutUnit.cpp b/Tools/TestWebKitAPI/Tests/WebCore/LayoutUnit.cpp
index ceafb039c..f904c96a1 100644
--- a/Tools/TestWebKitAPI/Tests/WebCore/LayoutUnit.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebCore/LayoutUnit.cpp
@@ -28,8 +28,6 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#define ENABLE_SUBPIXEL_LAYOUT 1
-#define ENABLE_SATURATED_LAYOUT_ARITHMETIC 1
#include "config.h"
#include <WebCore/LayoutUnit.h>
@@ -77,6 +75,10 @@ TEST(WebCoreLayoutUnit, LayoutUnitFloat)
ASSERT_NEAR(LayoutUnit(345634.12335f).toFloat(), 345634.12335f, tolerance);
ASSERT_NEAR(LayoutUnit(-345634.12335f).toFloat(), -345634.12335f, tolerance);
ASSERT_NEAR(LayoutUnit(-345634).toFloat(), -345634.0f, tolerance);
+ ASSERT_NEAR(LayoutUnit(33554432.f).toFloat(), 33554432.f, tolerance);
+ ASSERT_NEAR(LayoutUnit(-33554432.f).toFloat(), -33554432.f, tolerance);
+ ASSERT_NEAR(LayoutUnit(33554432.f).toDouble(), 33554432.f, tolerance);
+ ASSERT_NEAR(LayoutUnit(-33554432.f).toDouble(), -33554432.f, tolerance);
}
TEST(WebCoreLayoutUnit, LayoutUnitRounding)
@@ -104,28 +106,6 @@ TEST(WebCoreLayoutUnit, LayoutUnitRounding)
ASSERT_EQ(LayoutUnit::fromFloatRound(1.51f).round(), 2);
}
-TEST(WebCoreLayoutUnit, LayoutUnitSnapSizeToPixel)
-{
- ASSERT_EQ(snapSizeToPixel(LayoutUnit(1), LayoutUnit(0)), 1);
- ASSERT_EQ(snapSizeToPixel(LayoutUnit(1), LayoutUnit(0.5)), 1);
- ASSERT_EQ(snapSizeToPixel(LayoutUnit(1.5), LayoutUnit(0)), 2);
- ASSERT_EQ(snapSizeToPixel(LayoutUnit(1.5), LayoutUnit(0.49)), 2);
- ASSERT_EQ(snapSizeToPixel(LayoutUnit(1.5), LayoutUnit(0.5)), 1);
- ASSERT_EQ(snapSizeToPixel(LayoutUnit(1.5), LayoutUnit(0.75)), 1);
- ASSERT_EQ(snapSizeToPixel(LayoutUnit(1.5), LayoutUnit(0.99)), 1);
- ASSERT_EQ(snapSizeToPixel(LayoutUnit(1.5), LayoutUnit(1)), 2);
-
- ASSERT_EQ(snapSizeToPixel(LayoutUnit(0.5), LayoutUnit(1.5)), 0);
- ASSERT_EQ(snapSizeToPixel(LayoutUnit(0.99), LayoutUnit(1.5)), 0);
- ASSERT_EQ(snapSizeToPixel(LayoutUnit(1.0), LayoutUnit(1.5)), 1);
- ASSERT_EQ(snapSizeToPixel(LayoutUnit(1.49), LayoutUnit(1.5)), 1);
- ASSERT_EQ(snapSizeToPixel(LayoutUnit(1.5), LayoutUnit(1.5)), 1);
-
- ASSERT_EQ(snapSizeToPixel(LayoutUnit(100.5), LayoutUnit(100)), 101);
- ASSERT_EQ(snapSizeToPixel(LayoutUnit(intMaxForLayoutUnit), LayoutUnit(0.3)), intMaxForLayoutUnit);
- ASSERT_EQ(snapSizeToPixel(LayoutUnit(intMinForLayoutUnit), LayoutUnit(-0.3)), intMinForLayoutUnit);
-}
-
TEST(WebCoreLayoutUnit, LayoutUnitMultiplication)
{
ASSERT_EQ((LayoutUnit(1) * LayoutUnit(1)).toInt(), 1);
@@ -250,5 +230,19 @@ TEST(WebCoreLayoutUnit, LayoutUnitFloor)
ASSERT_EQ((LayoutUnit(intMinForLayoutUnit) + LayoutUnit(1)).floor(), intMinForLayoutUnit + 1);
}
+TEST(WebCoreLayoutUnit, LayoutUnitPixelSnapping)
+{
+ for (int i = -100000; i <= 100000; ++i) {
+ ASSERT_EQ(roundToDevicePixel(LayoutUnit(i), 1), i);
+ ASSERT_EQ(roundToDevicePixel(LayoutUnit(i), 2), i);
+ ASSERT_EQ(roundToDevicePixel(LayoutUnit(i), 3), i);
+ }
+
+ for (float i = -10000; i < 0; i = i + 0.5)
+ ASSERT_FLOAT_EQ(roundToDevicePixel(LayoutUnit(i), 2), i);
+
+ for (float i = -10000.25; i < 0; i = i + 0.5)
+ ASSERT_FLOAT_EQ(roundToDevicePixel(LayoutUnit(i), 2), i + 0.25);
+}
} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/ParsedContentRange.cpp b/Tools/TestWebKitAPI/Tests/WebCore/ParsedContentRange.cpp
new file mode 100644
index 000000000..986388302
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/ParsedContentRange.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <WebCore/ParsedContentRange.h>
+#include <wtf/text/WTFString.h>
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+TEST(WebCore, ParsedContentRangeFromString)
+{
+ // Basic parsing
+ ASSERT_TRUE(ParsedContentRange("bytes 0-1/2").isValid());
+ ASSERT_TRUE(ParsedContentRange("bytes 0-1/*").isValid());
+ ASSERT_EQ(0, ParsedContentRange("bytes 0-1/2").firstBytePosition());
+ ASSERT_EQ(1, ParsedContentRange("bytes 0-1/2").lastBytePosition());
+ ASSERT_EQ(2, ParsedContentRange("bytes 0-1/2").instanceLength());
+ ASSERT_EQ(ParsedContentRange::UnknownLength, ParsedContentRange("bytes 0-1/*").instanceLength());
+
+ // Whitespace errors
+ ASSERT_FALSE(ParsedContentRange("bytes 0-1/*").isValid());
+ ASSERT_FALSE(ParsedContentRange("bytes 0 -1/*").isValid());
+ ASSERT_FALSE(ParsedContentRange("bytes 0- 1/*").isValid());
+ ASSERT_FALSE(ParsedContentRange("bytes 0-1 /*").isValid());
+ ASSERT_FALSE(ParsedContentRange("bytes 0-1/ *").isValid());
+ ASSERT_FALSE(ParsedContentRange("bytes 0-1/* ").isValid());
+ ASSERT_FALSE(ParsedContentRange("bytes 0-1/ 2").isValid());
+ ASSERT_FALSE(ParsedContentRange("bytes 0-1/2 ").isValid());
+
+ // Non-digit errors
+ ASSERT_FALSE(ParsedContentRange("bytes abcd-1/2").isValid());
+ ASSERT_FALSE(ParsedContentRange("bytes 0-abcd/2").isValid());
+ ASSERT_FALSE(ParsedContentRange("bytes 0-1/abcd").isValid());
+
+ // Range requirement errors
+ ASSERT_FALSE(ParsedContentRange("bytes 1-0/2").isValid());
+ ASSERT_FALSE(ParsedContentRange("bytes 0-2/1").isValid());
+ ASSERT_FALSE(ParsedContentRange("bytes 2/0-1").isValid());
+ ASSERT_FALSE(ParsedContentRange("abcd 0/1-2").isValid());
+
+ // Negative value errors
+ ASSERT_FALSE(ParsedContentRange("bytes -0-1/*").isValid());
+ ASSERT_FALSE(ParsedContentRange("bytes -1/*").isValid());
+ ASSERT_FALSE(ParsedContentRange("bytes 0--0/2").isValid());
+ ASSERT_FALSE(ParsedContentRange("bytes 0-1/-2").isValid());
+
+ // Edge cases
+ ASSERT_TRUE(ParsedContentRange("bytes 9223372036854775805-9223372036854775806/9223372036854775807").isValid());
+ ASSERT_FALSE(ParsedContentRange("bytes 9223372036854775808-9223372036854775809/9223372036854775810").isValid());
+}
+
+TEST(WebCore, ParsedContentRangeFromValues)
+{
+ ASSERT_TRUE(ParsedContentRange(0, 1, 2).isValid());
+ ASSERT_TRUE(ParsedContentRange(0, 1, ParsedContentRange::UnknownLength).isValid());
+ ASSERT_FALSE(ParsedContentRange().isValid());
+ ASSERT_FALSE(ParsedContentRange(1, 0, 2).isValid());
+ ASSERT_FALSE(ParsedContentRange(0, 2, 1).isValid());
+ ASSERT_FALSE(ParsedContentRange(0, 0, 0).isValid());
+ ASSERT_FALSE(ParsedContentRange(-1, 1, 2).isValid());
+ ASSERT_FALSE(ParsedContentRange(0, -1, 2).isValid());
+ ASSERT_FALSE(ParsedContentRange(0, 1, -2).isValid());
+ ASSERT_FALSE(ParsedContentRange(-2, -1, 2).isValid());
+}
+
+TEST(WebCore, ParsedContentRangeToString)
+{
+ ASSERT_STREQ("bytes 0-1/2", ParsedContentRange(0, 1, 2).headerValue().utf8().data());
+ ASSERT_STREQ("bytes 0-1/*", ParsedContentRange(0, 1, ParsedContentRange::UnknownLength).headerValue().utf8().data());
+ ASSERT_STREQ("", ParsedContentRange().headerValue().utf8().data());
+}
+
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/PublicSuffix.cpp b/Tools/TestWebKitAPI/Tests/WebCore/PublicSuffix.cpp
new file mode 100644
index 000000000..f87ba63eb
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/PublicSuffix.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(PUBLIC_SUFFIX_LIST)
+
+#include "WTFStringUtilities.h"
+#include <WebCore/PublicSuffix.h>
+#include <wtf/MainThread.h>
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+class PublicSuffix: public testing::Test {
+public:
+ virtual void SetUp()
+ {
+ WTF::initializeMainThread();
+ }
+};
+
+TEST_F(PublicSuffix, IsPublicSuffix)
+{
+ EXPECT_TRUE(isPublicSuffix("com"));
+ EXPECT_FALSE(isPublicSuffix("test.com"));
+ EXPECT_FALSE(isPublicSuffix("com.com"));
+ EXPECT_TRUE(isPublicSuffix("net"));
+ EXPECT_TRUE(isPublicSuffix("org"));
+ EXPECT_TRUE(isPublicSuffix("co.uk"));
+ EXPECT_FALSE(isPublicSuffix("bl.uk"));
+ EXPECT_FALSE(isPublicSuffix("test.co.uk"));
+ EXPECT_TRUE(isPublicSuffix("xn--zf0ao64a.tw"));
+}
+
+TEST_F(PublicSuffix, TopPrivatelyControlledDomain)
+{
+ EXPECT_EQ(String("test.com"), topPrivatelyControlledDomain("test.com"));
+ EXPECT_EQ(String("test.com"), topPrivatelyControlledDomain("com.test.com"));
+ EXPECT_EQ(String("test.com"), topPrivatelyControlledDomain("subdomain.test.com"));
+ EXPECT_EQ(String("com.com"), topPrivatelyControlledDomain("www.com.com"));
+ EXPECT_EQ(String("test.co.uk"), topPrivatelyControlledDomain("test.co.uk"));
+ EXPECT_EQ(String("test.co.uk"), topPrivatelyControlledDomain("subdomain.test.co.uk"));
+ EXPECT_EQ(String("bl.uk"), topPrivatelyControlledDomain("bl.uk"));
+ EXPECT_EQ(String("bl.uk"), topPrivatelyControlledDomain("subdomain.bl.uk"));
+ EXPECT_EQ(String("test.xn--zf0ao64a.tw"), topPrivatelyControlledDomain("test.xn--zf0ao64a.tw"));
+ EXPECT_EQ(String("test.xn--zf0ao64a.tw"), topPrivatelyControlledDomain("www.test.xn--zf0ao64a.tw"));
+ EXPECT_EQ(String("127.0.0.1"), topPrivatelyControlledDomain("127.0.0.1"));
+ EXPECT_EQ(String(), topPrivatelyControlledDomain("1"));
+ EXPECT_EQ(String(), topPrivatelyControlledDomain("com"));
+}
+
+}
+
+#endif // ENABLE(PUBLIC_SUFFIX_LIST)
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/SampleMap.cpp b/Tools/TestWebKitAPI/Tests/WebCore/SampleMap.cpp
new file mode 100644
index 000000000..f7e91c6fd
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/SampleMap.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(MEDIA_SOURCE)
+
+#include "Test.h"
+#include <WebCore/MediaSample.h>
+#include <WebCore/SampleMap.h>
+
+namespace WTF {
+inline std::ostream& operator<<(std::ostream& os, const MediaTime& time)
+{
+ if (time.hasDoubleValue())
+ os << "{ " << time.toDouble() << " }";
+ else
+ os << "{ " << time.timeValue() << " / " << time.timeScale() << ", " << time.toDouble() << " }";
+ return os;
+}
+}
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+class TestSample : public MediaSample {
+public:
+ static Ref<TestSample> create(const MediaTime& presentationTime, const MediaTime& decodeTime, const MediaTime& duration, SampleFlags flags)
+ {
+ return adoptRef(*new TestSample(presentationTime, decodeTime, duration, flags));
+ }
+
+ MediaTime presentationTime() const final { return m_presentationTime; }
+ MediaTime decodeTime() const final { return m_decodeTime; }
+ MediaTime duration() const final { return m_duration; }
+ AtomicString trackID() const final { return m_trackID; }
+ void setTrackID(const String& trackID) final { m_trackID = trackID; }
+ size_t sizeInBytes() const final { return m_sizeInBytes; }
+ FloatSize presentationSize() const final { return m_presentationSize; }
+ void offsetTimestampsBy(const MediaTime& offset) final { m_presentationTime += offset; m_decodeTime += offset; }
+ void setTimestamps(const MediaTime& presentationTime, const MediaTime& decodeTime) final {
+ m_presentationTime = presentationTime;
+ m_decodeTime = decodeTime;
+ };
+ bool isDivisable() const final { return false; }
+ std::pair<RefPtr<MediaSample>, RefPtr<MediaSample>> divide(const MediaTime& presentationTime) final { return { }; }
+ Ref<MediaSample> createNonDisplayingCopy() const final {
+ return create(m_presentationTime, m_decodeTime, m_duration, static_cast<SampleFlags>(m_flags | IsNonDisplaying));
+ }
+ SampleFlags flags() const final { return m_flags; }
+ PlatformSample platformSample() final { return { PlatformSample::None, {nullptr}}; }
+ void dump(PrintStream&) const final { }
+
+private:
+ TestSample(const MediaTime& presentationTime, const MediaTime& decodeTime, const MediaTime& duration, SampleFlags flags)
+ : m_presentationTime(presentationTime)
+ , m_decodeTime(decodeTime)
+ , m_duration(duration)
+ , m_flags(flags)
+ {
+ }
+
+ MediaTime m_presentationTime;
+ MediaTime m_decodeTime;
+ MediaTime m_duration;
+ FloatSize m_presentationSize;
+ AtomicString m_trackID;
+ size_t m_sizeInBytes { 0 };
+ SampleFlags m_flags { None };
+};
+
+class SampleMapTest : public testing::Test {
+public:
+ void SetUp() final {
+ map.addSample(TestSample::create(MediaTime(0, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::IsSync));
+ map.addSample(TestSample::create(MediaTime(1, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+ map.addSample(TestSample::create(MediaTime(2, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+ map.addSample(TestSample::create(MediaTime(3, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+ map.addSample(TestSample::create(MediaTime(4, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+ map.addSample(TestSample::create(MediaTime(5, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::IsSync));
+ map.addSample(TestSample::create(MediaTime(6, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+ map.addSample(TestSample::create(MediaTime(7, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+ map.addSample(TestSample::create(MediaTime(8, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+ map.addSample(TestSample::create(MediaTime(9, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+ // Gap at MediaTime(10, 1) -> MediaTime(11, 1);
+ map.addSample(TestSample::create(MediaTime(11, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::IsSync));
+ map.addSample(TestSample::create(MediaTime(12, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+ map.addSample(TestSample::create(MediaTime(13, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+ map.addSample(TestSample::create(MediaTime(14, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+ map.addSample(TestSample::create(MediaTime(15, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::IsSync));
+ map.addSample(TestSample::create(MediaTime(16, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+ map.addSample(TestSample::create(MediaTime(17, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+ map.addSample(TestSample::create(MediaTime(18, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+ map.addSample(TestSample::create(MediaTime(19, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+ }
+
+ SampleMap map;
+};
+
+TEST_F(SampleMapTest, findSampleWithPresentationTime)
+{
+ auto& presentationMap = map.presentationOrder();
+ EXPECT_EQ(MediaTime(0, 1), presentationMap.findSampleWithPresentationTime(MediaTime(0, 1))->second->presentationTime());
+ EXPECT_EQ(MediaTime(19, 1), presentationMap.findSampleWithPresentationTime(MediaTime(19, 1))->second->presentationTime());
+ EXPECT_TRUE(presentationMap.end() == presentationMap.findSampleWithPresentationTime(MediaTime(-1, 1)));
+ EXPECT_TRUE(presentationMap.end() == presentationMap.findSampleWithPresentationTime(MediaTime(10, 1)));
+ EXPECT_TRUE(presentationMap.end() == presentationMap.findSampleWithPresentationTime(MediaTime(20, 1)));
+ EXPECT_TRUE(presentationMap.end() == presentationMap.findSampleWithPresentationTime(MediaTime(1, 2)));
+}
+
+TEST_F(SampleMapTest, findSampleContainingPresentationTime)
+{
+ auto& presentationMap = map.presentationOrder();
+ EXPECT_EQ(MediaTime(0, 1), presentationMap.findSampleContainingPresentationTime(MediaTime(0, 1))->second->presentationTime());
+ EXPECT_EQ(MediaTime(19, 1), presentationMap.findSampleContainingPresentationTime(MediaTime(19, 1))->second->presentationTime());
+ EXPECT_EQ(MediaTime(0, 1), presentationMap.findSampleContainingPresentationTime(MediaTime(1, 2))->second->presentationTime());
+ EXPECT_TRUE(presentationMap.end() == presentationMap.findSampleContainingPresentationTime(MediaTime(-1, 1)));
+ EXPECT_TRUE(presentationMap.end() == presentationMap.findSampleContainingPresentationTime(MediaTime(10, 1)));
+ EXPECT_TRUE(presentationMap.end() == presentationMap.findSampleContainingPresentationTime(MediaTime(20, 1)));
+}
+
+TEST_F(SampleMapTest, findSampleStartingOnOrAfterPresentationTime)
+{
+ auto& presentationMap = map.presentationOrder();
+ EXPECT_EQ(MediaTime(0, 1), presentationMap.findSampleStartingOnOrAfterPresentationTime(MediaTime(0, 1))->second->presentationTime());
+ EXPECT_EQ(MediaTime(19, 1), presentationMap.findSampleStartingOnOrAfterPresentationTime(MediaTime(19, 1))->second->presentationTime());
+ EXPECT_EQ(MediaTime(1, 1), presentationMap.findSampleStartingOnOrAfterPresentationTime(MediaTime(1, 2))->second->presentationTime());
+ EXPECT_EQ(MediaTime(0, 1), presentationMap.findSampleStartingOnOrAfterPresentationTime(MediaTime(-1, 1))->second->presentationTime());
+ EXPECT_EQ(MediaTime(11, 1), presentationMap.findSampleStartingOnOrAfterPresentationTime(MediaTime(10, 1))->second->presentationTime());
+ EXPECT_TRUE(presentationMap.end() == presentationMap.findSampleContainingPresentationTime(MediaTime(20, 1)));
+}
+
+TEST_F(SampleMapTest, findSamplesBetweenPresentationTimes)
+{
+ auto& presentationMap = map.presentationOrder();
+ auto iterator_range = presentationMap.findSamplesBetweenPresentationTimes(MediaTime(0, 1), MediaTime(1, 1));
+ EXPECT_EQ(MediaTime(0, 1), iterator_range.first->second->presentationTime());
+ EXPECT_EQ(MediaTime(1, 1), iterator_range.second->second->presentationTime());
+
+ iterator_range = presentationMap.findSamplesBetweenPresentationTimes(MediaTime(1, 2), MediaTime(3, 2));
+ EXPECT_EQ(MediaTime(1, 1), iterator_range.first->second->presentationTime());
+ EXPECT_EQ(MediaTime(2, 1), iterator_range.second->second->presentationTime());
+
+ iterator_range = presentationMap.findSamplesBetweenPresentationTimes(MediaTime(9, 1), MediaTime(21, 1));
+ EXPECT_EQ(MediaTime(9, 1), iterator_range.first->second->presentationTime());
+ EXPECT_TRUE(presentationMap.end() == iterator_range.second);
+
+ iterator_range = presentationMap.findSamplesBetweenPresentationTimes(MediaTime(-1, 1), MediaTime(0, 1));
+ EXPECT_TRUE(presentationMap.end() == iterator_range.first);
+ EXPECT_TRUE(presentationMap.end() == iterator_range.second);
+
+ iterator_range = presentationMap.findSamplesBetweenPresentationTimes(MediaTime(19, 2), MediaTime(10, 1));
+ EXPECT_TRUE(presentationMap.end() == iterator_range.first);
+ EXPECT_TRUE(presentationMap.end() == iterator_range.second);
+
+ iterator_range = presentationMap.findSamplesBetweenPresentationTimes(MediaTime(20, 1), MediaTime(21, 1));
+ EXPECT_TRUE(presentationMap.end() == iterator_range.first);
+ EXPECT_TRUE(presentationMap.end() == iterator_range.second);
+}
+
+TEST_F(SampleMapTest, findSamplesWithinPresentationRange)
+{
+ auto& presentationMap = map.presentationOrder();
+ auto iterator_range = presentationMap.findSamplesWithinPresentationRange(MediaTime(0, 1), MediaTime(1, 1));
+ EXPECT_EQ(MediaTime(1, 1), iterator_range.first->second->presentationTime());
+ EXPECT_EQ(MediaTime(2, 1), iterator_range.second->second->presentationTime());
+
+ iterator_range = presentationMap.findSamplesWithinPresentationRange(MediaTime(1, 2), MediaTime(3, 2));
+ EXPECT_EQ(MediaTime(1, 1), iterator_range.first->second->presentationTime());
+ EXPECT_EQ(MediaTime(2, 1), iterator_range.second->second->presentationTime());
+
+ iterator_range = presentationMap.findSamplesWithinPresentationRange(MediaTime(9, 1), MediaTime(21, 1));
+ EXPECT_EQ(MediaTime(11, 1), iterator_range.first->second->presentationTime());
+ EXPECT_TRUE(presentationMap.end() == iterator_range.second);
+
+ iterator_range = presentationMap.findSamplesWithinPresentationRange(MediaTime(-1, 1), MediaTime(0, 1));
+ EXPECT_EQ(MediaTime(0, 1), iterator_range.first->second->presentationTime());
+ EXPECT_EQ(MediaTime(1, 1), iterator_range.second->second->presentationTime());
+
+ iterator_range = presentationMap.findSamplesWithinPresentationRange(MediaTime(10, 1), MediaTime(21, 2));
+ EXPECT_TRUE(presentationMap.end() == iterator_range.first);
+ EXPECT_TRUE(presentationMap.end() == iterator_range.second);
+
+ iterator_range = presentationMap.findSamplesWithinPresentationRange(MediaTime(20, 1), MediaTime(21, 1));
+ EXPECT_TRUE(presentationMap.end() == iterator_range.first);
+ EXPECT_TRUE(presentationMap.end() == iterator_range.second);
+}
+
+TEST_F(SampleMapTest, reverseFindSampleBeforePresentationTime)
+{
+ auto& presentationMap = map.presentationOrder();
+ EXPECT_EQ(MediaTime(0, 1), presentationMap.reverseFindSampleBeforePresentationTime(MediaTime(0, 1))->second->presentationTime());
+ EXPECT_EQ(MediaTime(9, 1), presentationMap.reverseFindSampleBeforePresentationTime(MediaTime(10, 1))->second->presentationTime());
+ EXPECT_EQ(MediaTime(19, 1), presentationMap.reverseFindSampleBeforePresentationTime(MediaTime(19, 1))->second->presentationTime());
+ EXPECT_EQ(MediaTime(19, 1), presentationMap.reverseFindSampleBeforePresentationTime(MediaTime(21, 1))->second->presentationTime());
+ EXPECT_TRUE(presentationMap.rend() == presentationMap.reverseFindSampleBeforePresentationTime(MediaTime(-1, 1)));
+}
+
+}
+
+#endif // ENABLE(MEDIA_SOURCE)
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/SecurityOrigin.cpp b/Tools/TestWebKitAPI/Tests/WebCore/SecurityOrigin.cpp
new file mode 100644
index 000000000..9f9cc9cca
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/SecurityOrigin.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2016 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WTFStringUtilities.h"
+#include <WebCore/FileSystem.h>
+#include <WebCore/SecurityOrigin.h>
+#include <WebCore/URL.h>
+#include <wtf/MainThread.h>
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+class SecurityOriginTest : public testing::Test {
+public:
+ void SetUp() final {
+ WTF::initializeMainThread();
+
+ // create temp file
+ PlatformFileHandle handle;
+ m_tempFilePath = openTemporaryFile("tempTestFile", handle);
+ closeFile(handle);
+
+ m_spaceContainingFilePath = openTemporaryFile("temp Empty Test File", handle);
+ closeFile(handle);
+
+ m_bangContainingFilePath = openTemporaryFile("temp!Empty!Test!File", handle);
+ closeFile(handle);
+
+ m_quoteContainingFilePath = openTemporaryFile("temp\"Empty\"TestFile", handle);
+ closeFile(handle);
+ }
+
+ void TearDown() override
+ {
+ deleteFile(m_tempFilePath);
+ deleteFile(m_spaceContainingFilePath);
+ deleteFile(m_bangContainingFilePath);
+ deleteFile(m_quoteContainingFilePath);
+ }
+
+ const String& tempFilePath() { return m_tempFilePath; }
+ const String& spaceContainingFilePath() { return m_spaceContainingFilePath; }
+ const String& bangContainingFilePath() { return m_bangContainingFilePath; }
+ const String& quoteContainingFilePath() { return m_quoteContainingFilePath; }
+
+private:
+ String m_tempFilePath;
+ String m_spaceContainingFilePath;
+ String m_bangContainingFilePath;
+ String m_quoteContainingFilePath;
+};
+
+TEST_F(SecurityOriginTest, SecurityOriginConstructors)
+{
+ Ref<SecurityOrigin> o1 = SecurityOrigin::create("http", "example.com", std::optional<uint16_t>(80));
+ Ref<SecurityOrigin> o2 = SecurityOrigin::create("http", "example.com", std::optional<uint16_t>());
+ Ref<SecurityOrigin> o3 = SecurityOrigin::createFromString("http://example.com");
+ Ref<SecurityOrigin> o4 = SecurityOrigin::createFromString("http://example.com:80");
+ Ref<SecurityOrigin> o5 = SecurityOrigin::create(URL(URL(), "http://example.com"));
+ Ref<SecurityOrigin> o6 = SecurityOrigin::create(URL(URL(), "http://example.com:80"));
+
+ EXPECT_EQ(String("http"), o1->protocol());
+ EXPECT_EQ(String("http"), o2->protocol());
+ EXPECT_EQ(String("http"), o3->protocol());
+ EXPECT_EQ(String("http"), o4->protocol());
+ EXPECT_EQ(String("http"), o5->protocol());
+ EXPECT_EQ(String("http"), o6->protocol());
+
+ EXPECT_EQ(String("example.com"), o1->host());
+ EXPECT_EQ(String("example.com"), o2->host());
+ EXPECT_EQ(String("example.com"), o3->host());
+ EXPECT_EQ(String("example.com"), o4->host());
+ EXPECT_EQ(String("example.com"), o5->host());
+ EXPECT_EQ(String("example.com"), o6->host());
+
+ EXPECT_FALSE(o1->port());
+ EXPECT_FALSE(o2->port());
+ EXPECT_FALSE(o3->port());
+ EXPECT_FALSE(o4->port());
+ EXPECT_FALSE(o5->port());
+ EXPECT_FALSE(o6->port());
+
+ EXPECT_EQ("http://example.com", o1->toString());
+ EXPECT_EQ("http://example.com", o2->toString());
+ EXPECT_EQ("http://example.com", o3->toString());
+ EXPECT_EQ("http://example.com", o4->toString());
+ EXPECT_EQ("http://example.com", o5->toString());
+ EXPECT_EQ("http://example.com", o6->toString());
+
+ EXPECT_TRUE(o1->isSameOriginAs(o2.get()));
+ EXPECT_TRUE(o1->isSameOriginAs(o3.get()));
+ EXPECT_TRUE(o1->isSameOriginAs(o4.get()));
+ EXPECT_TRUE(o1->isSameOriginAs(o5.get()));
+ EXPECT_TRUE(o1->isSameOriginAs(o6.get()));
+}
+
+TEST_F(SecurityOriginTest, SecurityOriginFileBasedConstructors)
+{
+ auto tempFileOrigin = SecurityOrigin::create(URL(URL(), "file:///" + tempFilePath()));
+ auto spaceContainingOrigin = SecurityOrigin::create(URL(URL(), "file:///" + spaceContainingFilePath()));
+ auto bangContainingOrigin = SecurityOrigin::create(URL(URL(), "file:///" + bangContainingFilePath()));
+ auto quoteContainingOrigin = SecurityOrigin::create(URL(URL(), "file:///" + quoteContainingFilePath()));
+
+ EXPECT_EQ(String("file"), tempFileOrigin->protocol());
+ EXPECT_EQ(String("file"), spaceContainingOrigin->protocol());
+ EXPECT_EQ(String("file"), bangContainingOrigin->protocol());
+ EXPECT_EQ(String("file"), quoteContainingOrigin->protocol());
+
+ EXPECT_TRUE(tempFileOrigin->isSameOriginAs(spaceContainingOrigin.get()));
+ EXPECT_TRUE(tempFileOrigin->isSameOriginAs(bangContainingOrigin.get()));
+ EXPECT_TRUE(tempFileOrigin->isSameOriginAs(quoteContainingOrigin.get()));
+
+ EXPECT_TRUE(tempFileOrigin->isSameSchemeHostPort(spaceContainingOrigin.get()));
+ EXPECT_TRUE(tempFileOrigin->isSameSchemeHostPort(bangContainingOrigin.get()));
+ EXPECT_TRUE(tempFileOrigin->isSameSchemeHostPort(quoteContainingOrigin.get()));
+
+ EXPECT_TRUE(tempFileOrigin->canAccess(spaceContainingOrigin.get()));
+ EXPECT_TRUE(tempFileOrigin->canAccess(bangContainingOrigin.get()));
+ EXPECT_TRUE(tempFileOrigin->canAccess(quoteContainingOrigin.get()));
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/SharedBuffer.cpp b/Tools/TestWebKitAPI/Tests/WebCore/SharedBuffer.cpp
new file mode 100644
index 000000000..543ef2316
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/SharedBuffer.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2015 Canon Inc. All rights reserved.
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "SharedBufferTest.h"
+#include "Test.h"
+#include <WebCore/SharedBuffer.h>
+#include <wtf/MainThread.h>
+#include <wtf/StringExtras.h>
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+TEST_F(SharedBufferTest, createWithContentsOfMissingFile)
+{
+ RefPtr<SharedBuffer> buffer = SharedBuffer::createWithContentsOfFile(String("not_existing_file"));
+ ASSERT_NULL(buffer);
+}
+
+TEST_F(SharedBufferTest, createWithContentsOfExistingFile)
+{
+ RefPtr<SharedBuffer> buffer = SharedBuffer::createWithContentsOfFile(tempFilePath());
+ ASSERT_NOT_NULL(buffer);
+ EXPECT_TRUE(buffer->size() == strlen(SharedBufferTest::testData()));
+ EXPECT_TRUE(String(SharedBufferTest::testData()) == String(buffer->data(), buffer->size()));
+}
+
+TEST_F(SharedBufferTest, createWithContentsOfExistingEmptyFile)
+{
+ RefPtr<SharedBuffer> buffer = SharedBuffer::createWithContentsOfFile(tempEmptyFilePath());
+ ASSERT_NOT_NULL(buffer);
+ EXPECT_TRUE(buffer->isEmpty());
+}
+
+TEST_F(SharedBufferTest, copyBufferCreatedWithContentsOfExistingFile)
+{
+ RefPtr<SharedBuffer> buffer = SharedBuffer::createWithContentsOfFile(tempFilePath());
+ ASSERT_NOT_NULL(buffer);
+ RefPtr<SharedBuffer> copy = buffer->copy();
+ EXPECT_GT(buffer->size(), 0U);
+ EXPECT_TRUE(buffer->size() == copy->size());
+ EXPECT_TRUE(!memcmp(buffer->data(), copy->data(), buffer->size()));
+}
+
+TEST_F(SharedBufferTest, clearBufferCreatedWithContentsOfExistingFile)
+{
+ RefPtr<SharedBuffer> buffer = SharedBuffer::createWithContentsOfFile(tempFilePath());
+ ASSERT_NOT_NULL(buffer);
+ buffer->clear();
+ EXPECT_TRUE(!buffer->size());
+ EXPECT_TRUE(!buffer->data());
+}
+
+TEST_F(SharedBufferTest, appendBufferCreatedWithContentsOfExistingFile)
+{
+ RefPtr<SharedBuffer> buffer = SharedBuffer::createWithContentsOfFile(tempFilePath());
+ ASSERT_NOT_NULL(buffer);
+ buffer->append("a", 1);
+ EXPECT_TRUE(buffer->size() == (strlen(SharedBufferTest::testData()) + 1));
+ EXPECT_TRUE(!memcmp(buffer->data(), SharedBufferTest::testData(), strlen(SharedBufferTest::testData())));
+ EXPECT_EQ('a', buffer->data()[strlen(SharedBufferTest::testData())]);
+}
+
+TEST_F(SharedBufferTest, createArrayBuffer)
+{
+ char testData0[] = "Hello";
+ char testData1[] = "World";
+ char testData2[] = "Goodbye";
+ RefPtr<SharedBuffer> sharedBuffer = SharedBuffer::create(testData0, strlen(testData0));
+ sharedBuffer->append(testData1, strlen(testData1));
+ sharedBuffer->append(testData2, strlen(testData2));
+ RefPtr<ArrayBuffer> arrayBuffer = sharedBuffer->createArrayBuffer();
+ char expectedConcatenation[] = "HelloWorldGoodbye";
+ ASSERT_EQ(strlen(expectedConcatenation), arrayBuffer->byteLength());
+ EXPECT_EQ(0, memcmp(expectedConcatenation, arrayBuffer->data(), strlen(expectedConcatenation)));
+}
+
+TEST_F(SharedBufferTest, createArrayBufferLargeSegments)
+{
+ Vector<char> vector0(0x4000, 'a');
+ Vector<char> vector1(0x4000, 'b');
+ Vector<char> vector2(0x4000, 'c');
+
+ RefPtr<SharedBuffer> sharedBuffer = SharedBuffer::adoptVector(vector0);
+ sharedBuffer->append(vector1);
+ sharedBuffer->append(vector2);
+ RefPtr<ArrayBuffer> arrayBuffer = sharedBuffer->createArrayBuffer();
+ ASSERT_EQ(0x4000U + 0x4000U + 0x4000U, arrayBuffer->byteLength());
+ int position = 0;
+ for (int i = 0; i < 0x4000; ++i) {
+ EXPECT_EQ('a', static_cast<char*>(arrayBuffer->data())[position]);
+ ++position;
+ }
+ for (int i = 0; i < 0x4000; ++i) {
+ EXPECT_EQ('b', static_cast<char*>(arrayBuffer->data())[position]);
+ ++position;
+ }
+ for (int i = 0; i < 0x4000; ++i) {
+ EXPECT_EQ('c', static_cast<char*>(arrayBuffer->data())[position]);
+ ++position;
+ }
+}
+
+TEST_F(SharedBufferTest, copy)
+{
+ char testData[] = "Habitasse integer eros tincidunt a scelerisque! Enim elit? Scelerisque magnis,"
+ "et montes ultrices tristique a! Pid. Velit turpis, dapibus integer rhoncus sociis amet facilisis,"
+ "adipiscing pulvinar nascetur magnis tempor sit pulvinar, massa urna enim porttitor sociis sociis proin enim?"
+ "Lectus, platea dolor, integer a. A habitasse hac nunc, nunc, nec placerat vut in sit nunc nec, sed. Sociis,"
+ "vut! Hac, velit rhoncus facilisis. Rhoncus et, enim, sed et in tristique nunc montes,"
+ "natoque nunc sagittis elementum parturient placerat dolor integer? Pulvinar,"
+ "magnis dignissim porttitor ac pulvinar mid tempor. A risus sed mid! Magnis elit duis urna,"
+ "cras massa, magna duis. Vut magnis pid a! Penatibus aliquet porttitor nunc, adipiscing massa odio lundium,"
+ "risus elementum ac turpis massa pellentesque parturient augue. Purus amet turpis pid aliquam?"
+ "Dolor est tincidunt? Dolor? Dignissim porttitor sit in aliquam! Tincidunt, non nunc, rhoncus dictumst!"
+ "Porta augue etiam. Cursus augue nunc lacus scelerisque. Rhoncus lectus, integer hac, nec pulvinar augue massa,"
+ "integer amet nisi facilisis? A! A, enim velit pulvinar elit in non scelerisque in et ultricies amet est!"
+ "in porttitor montes lorem et, hac aliquet pellentesque a sed? Augue mid purus ridiculus vel dapibus,"
+ "sagittis sed, tortor auctor nascetur rhoncus nec, rhoncus, magna integer. Sit eu massa vut?"
+ "Porta augue porttitor elementum, enim, rhoncus pulvinar duis integer scelerisque rhoncus natoque,"
+ "mattis dignissim massa ac pulvinar urna, nunc ut. Sagittis, aliquet penatibus proin lorem, pulvinar lectus,"
+ "augue proin! Ac, arcu quis. Placerat habitasse, ridiculus ridiculus.";
+ unsigned length = strlen(testData);
+ RefPtr<SharedBuffer> sharedBuffer = SharedBuffer::create(testData, length);
+ sharedBuffer->append(testData, length);
+ sharedBuffer->append(testData, length);
+ sharedBuffer->append(testData, length);
+ // sharedBuffer must contain data more than segmentSize (= 0x1000) to check copy().
+ ASSERT_EQ(length * 4, sharedBuffer->size());
+ RefPtr<SharedBuffer> clone = sharedBuffer->copy();
+ ASSERT_EQ(length * 4, clone->size());
+ ASSERT_EQ(0, memcmp(clone->data(), sharedBuffer->data(), clone->size()));
+ clone->append(testData, length);
+ ASSERT_EQ(length * 5, clone->size());
+}
+
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/SharedBufferTest.cpp b/Tools/TestWebKitAPI/Tests/WebCore/SharedBufferTest.cpp
new file mode 100644
index 000000000..a297a55b8
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/SharedBufferTest.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "SharedBufferTest.h"
+
+#include <WebCore/FileSystem.h>
+#include <wtf/MainThread.h>
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+void SharedBufferTest::SetUp()
+{
+ WTF::initializeMainThread();
+
+ // create temp file
+ PlatformFileHandle handle;
+ m_tempFilePath = openTemporaryFile("tempTestFile", handle);
+ writeToFile(handle, testData(), strlen(testData()));
+ closeFile(handle);
+
+ m_tempEmptyFilePath = openTemporaryFile("tempEmptyTestFile", handle);
+ closeFile(handle);
+}
+
+void SharedBufferTest::TearDown()
+{
+ deleteFile(m_tempFilePath);
+ deleteFile(m_tempEmptyFilePath);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/SharedBufferTest.h b/Tools/TestWebKitAPI/Tests/WebCore/SharedBufferTest.h
new file mode 100644
index 000000000..e5d90935d
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/SharedBufferTest.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/text/WTFString.h>
+
+namespace TestWebKitAPI {
+
+class SharedBufferTest : public testing::Test {
+public:
+ void SetUp() override;
+ void TearDown() override;
+
+ static const char* testData() { return "This is a test"; }
+ const String& tempFilePath() { return m_tempFilePath; }
+ const String& tempEmptyFilePath() { return m_tempEmptyFilePath; }
+
+private:
+ String m_tempFilePath;
+ String m_tempEmptyFilePath;
+};
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/TimeRanges.cpp b/Tools/TestWebKitAPI/Tests/WebCore/TimeRanges.cpp
new file mode 100644
index 000000000..c6dca0115
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/TimeRanges.cpp
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2013, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include <WebCore/TimeRanges.h>
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+static std::string ToString(const TimeRanges& ranges)
+{
+ std::stringstream ss;
+ ss << "{";
+ for (unsigned i = 0; i < ranges.length(); ++i)
+ ss << " [" << ranges.start(i).releaseReturnValue() << "," << ranges.end(i).releaseReturnValue() << ")";
+ ss << " }";
+
+ return ss.str();
+}
+
+#define ASSERT_RANGE(expected, range) EXPECT_EQ(expected, ToString(*range))
+
+TEST(TimeRanges, Empty)
+{
+ ASSERT_RANGE("{ }", TimeRanges::create().ptr());
+}
+
+TEST(TimeRanges, SingleRange)
+{
+ ASSERT_RANGE("{ [1,2) }", TimeRanges::create(1, 2).ptr());
+}
+
+TEST(TimeRanges, AddOrder)
+{
+ RefPtr<TimeRanges> rangeA = TimeRanges::create();
+ RefPtr<TimeRanges> rangeB = TimeRanges::create();
+
+ rangeA->add(0, 2);
+ rangeA->add(3, 4);
+ rangeA->add(5, 100);
+
+ std::string expected = "{ [0,2) [3,4) [5,100) }";
+ ASSERT_RANGE(expected, rangeA);
+
+ // Add the values in rangeA to rangeB in reverse order.
+ for (int i = rangeA->length() - 1; i >= 0; --i)
+ rangeB->add(rangeA->start(i).releaseReturnValue(), rangeA->end(i).releaseReturnValue());
+
+ ASSERT_RANGE(expected, rangeB);
+}
+
+TEST(TimeRanges, OverlappingAdds)
+{
+ RefPtr<TimeRanges> ranges = TimeRanges::create();
+
+ ranges->add(0, 2);
+ ranges->add(10, 11);
+ ASSERT_RANGE("{ [0,2) [10,11) }", ranges);
+
+ ranges->add(0, 2);
+ ASSERT_RANGE("{ [0,2) [10,11) }", ranges);
+
+ ranges->add(2, 3);
+ ASSERT_RANGE("{ [0,3) [10,11) }", ranges);
+
+ ranges->add(2, 6);
+ ASSERT_RANGE("{ [0,6) [10,11) }", ranges);
+
+ ranges->add(9, 10);
+ ASSERT_RANGE("{ [0,6) [9,11) }", ranges);
+
+ ranges->add(8, 10);
+ ASSERT_RANGE("{ [0,6) [8,11) }", ranges);
+
+ ranges->add(-1, 7);
+ ASSERT_RANGE("{ [-1,7) [8,11) }", ranges);
+
+ ranges->add(6, 9);
+ ASSERT_RANGE("{ [-1,11) }", ranges);
+}
+
+TEST(TimeRanges, IntersectWith_Self)
+{
+ RefPtr<TimeRanges> ranges = TimeRanges::create(0, 2);
+
+ ASSERT_RANGE("{ [0,2) }", ranges);
+
+ ranges->intersectWith(*ranges.get());
+
+ ASSERT_RANGE("{ [0,2) }", ranges);
+}
+
+TEST(TimeRanges, IntersectWith_IdenticalRange)
+{
+ RefPtr<TimeRanges> rangesA = TimeRanges::create(0, 2);
+ RefPtr<TimeRanges> rangesB = rangesA->copy();
+
+ ASSERT_RANGE("{ [0,2) }", rangesA);
+ ASSERT_RANGE("{ [0,2) }", rangesB);
+
+ rangesA->intersectWith(*rangesB.get());
+
+ ASSERT_RANGE("{ [0,2) }", rangesA);
+ ASSERT_RANGE("{ [0,2) }", rangesB);
+}
+
+TEST(TimeRanges, IntersectWith_Empty)
+{
+ RefPtr<TimeRanges> rangesA = TimeRanges::create(0, 2);
+ RefPtr<TimeRanges> rangesB = TimeRanges::create();
+
+ ASSERT_RANGE("{ [0,2) }", rangesA);
+ ASSERT_RANGE("{ }", rangesB);
+
+ rangesA->intersectWith(*rangesB.get());
+
+ ASSERT_RANGE("{ }", rangesA);
+ ASSERT_RANGE("{ }", rangesB);
+}
+
+TEST(TimeRanges, IntersectWith_DisjointRanges1)
+{
+
+ RefPtr<TimeRanges> rangesA = TimeRanges::create();
+ RefPtr<TimeRanges> rangesB = TimeRanges::create();
+
+ rangesA->add(0, 1);
+ rangesA->add(4, 5);
+
+ rangesB->add(2, 3);
+ rangesB->add(6, 7);
+
+ ASSERT_RANGE("{ [0,1) [4,5) }", rangesA);
+ ASSERT_RANGE("{ [2,3) [6,7) }", rangesB);
+
+ rangesA->intersectWith(*rangesB.get());
+
+ ASSERT_RANGE("{ }", rangesA);
+ ASSERT_RANGE("{ [2,3) [6,7) }", rangesB);
+}
+
+TEST(TimeRanges, IntersectWith_DisjointRanges2)
+{
+ RefPtr<TimeRanges> rangesA = TimeRanges::create();
+ RefPtr<TimeRanges> rangesB = TimeRanges::create();
+
+ rangesA->add(0, 1);
+ rangesA->add(4, 5);
+
+ rangesB->add(1, 4);
+ rangesB->add(5, 7);
+
+ ASSERT_RANGE("{ [0,1) [4,5) }", rangesA);
+ ASSERT_RANGE("{ [1,4) [5,7) }", rangesB);
+
+ rangesA->intersectWith(*rangesB.get());
+
+ ASSERT_RANGE("{ }", rangesA);
+ ASSERT_RANGE("{ [1,4) [5,7) }", rangesB);
+}
+
+TEST(TimeRanges, IntersectWith_CompleteOverlap1)
+{
+ RefPtr<TimeRanges> rangesA = TimeRanges::create();
+ RefPtr<TimeRanges> rangesB = TimeRanges::create();
+
+ rangesA->add(1, 3);
+ rangesA->add(4, 5);
+ rangesA->add(6, 9);
+
+ rangesB->add(0, 10);
+
+ ASSERT_RANGE("{ [1,3) [4,5) [6,9) }", rangesA);
+ ASSERT_RANGE("{ [0,10) }", rangesB);
+
+ rangesA->intersectWith(*rangesB.get());
+
+ ASSERT_RANGE("{ [1,3) [4,5) [6,9) }", rangesA);
+ ASSERT_RANGE("{ [0,10) }", rangesB);
+}
+
+TEST(TimeRanges, IntersectWith_CompleteOverlap2)
+{
+ RefPtr<TimeRanges> rangesA = TimeRanges::create();
+ RefPtr<TimeRanges> rangesB = TimeRanges::create();
+
+ rangesA->add(1, 3);
+ rangesA->add(4, 5);
+ rangesA->add(6, 9);
+
+ rangesB->add(1, 9);
+
+ ASSERT_RANGE("{ [1,3) [4,5) [6,9) }", rangesA);
+ ASSERT_RANGE("{ [1,9) }", rangesB);
+
+ rangesA->intersectWith(*rangesB.get());
+
+ ASSERT_RANGE("{ [1,3) [4,5) [6,9) }", rangesA);
+ ASSERT_RANGE("{ [1,9) }", rangesB);
+}
+
+TEST(TimeRanges, IntersectWith_Gaps1)
+{
+ RefPtr<TimeRanges> rangesA = TimeRanges::create();
+ RefPtr<TimeRanges> rangesB = TimeRanges::create();
+
+ rangesA->add(0, 2);
+ rangesA->add(4, 6);
+
+ rangesB->add(1, 5);
+
+ ASSERT_RANGE("{ [0,2) [4,6) }", rangesA);
+ ASSERT_RANGE("{ [1,5) }", rangesB);
+
+ rangesA->intersectWith(*rangesB.get());
+
+ ASSERT_RANGE("{ [1,2) [4,5) }", rangesA);
+ ASSERT_RANGE("{ [1,5) }", rangesB);
+}
+
+TEST(TimeRanges, IntersectWith_Gaps2)
+{
+ RefPtr<TimeRanges> rangesA = TimeRanges::create();
+ RefPtr<TimeRanges> rangesB = TimeRanges::create();
+
+ rangesA->add(0, 2);
+ rangesA->add(4, 6);
+ rangesA->add(8, 10);
+
+ rangesB->add(1, 9);
+
+ ASSERT_RANGE("{ [0,2) [4,6) [8,10) }", rangesA);
+ ASSERT_RANGE("{ [1,9) }", rangesB);
+
+ rangesA->intersectWith(*rangesB.get());
+
+ ASSERT_RANGE("{ [1,2) [4,6) [8,9) }", rangesA);
+ ASSERT_RANGE("{ [1,9) }", rangesB);
+}
+
+TEST(TimeRanges, IntersectWith_Gaps3)
+{
+ RefPtr<TimeRanges> rangesA = TimeRanges::create();
+ RefPtr<TimeRanges> rangesB = TimeRanges::create();
+
+ rangesA->add(0, 2);
+ rangesA->add(4, 7);
+ rangesA->add(8, 10);
+
+ rangesB->add(1, 5);
+ rangesB->add(6, 9);
+
+ ASSERT_RANGE("{ [0,2) [4,7) [8,10) }", rangesA);
+ ASSERT_RANGE("{ [1,5) [6,9) }", rangesB);
+
+ rangesA->intersectWith(*rangesB.get());
+
+ ASSERT_RANGE("{ [1,2) [4,5) [6,7) [8,9) }", rangesA);
+ ASSERT_RANGE("{ [1,5) [6,9) }", rangesB);
+}
+
+}
+
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/TransformationMatrix.cpp b/Tools/TestWebKitAPI/Tests/WebCore/TransformationMatrix.cpp
new file mode 100644
index 000000000..9315b75a5
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/TransformationMatrix.cpp
@@ -0,0 +1,1317 @@
+/*
+ * Copyright (c) 2013, Google Inc. All rights reserved.
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <WebCore/AffineTransform.h>
+#include <WebCore/FloatPoint.h>
+#include <WebCore/FloatQuad.h>
+#include <WebCore/FloatRect.h>
+#include <WebCore/IntPoint.h>
+#include <WebCore/IntRect.h>
+#include <WebCore/TransformationMatrix.h>
+
+#if USE(CG)
+#include <CoreGraphics/CoreGraphics.h>
+#endif
+
+#if USE(CA)
+#include <QuartzCore/QuartzCore.h>
+#endif
+
+#if PLATFORM(WIN)
+#include <d2d1.h>
+#endif
+
+namespace TestWebKitAPI {
+
+static void testIdentity(const WebCore::TransformationMatrix& transform)
+{
+ EXPECT_DOUBLE_EQ(1.0, transform.m11());
+ EXPECT_DOUBLE_EQ(0.0, transform.m12());
+ EXPECT_DOUBLE_EQ(0.0, transform.m13());
+ EXPECT_DOUBLE_EQ(0.0, transform.m14());
+ EXPECT_DOUBLE_EQ(0.0, transform.m21());
+ EXPECT_DOUBLE_EQ(1.0, transform.m22());
+ EXPECT_DOUBLE_EQ(0.0, transform.m23());
+ EXPECT_DOUBLE_EQ(0.0, transform.m24());
+ EXPECT_DOUBLE_EQ(0.0, transform.m31());
+ EXPECT_DOUBLE_EQ(0.0, transform.m32());
+ EXPECT_DOUBLE_EQ(1.0, transform.m33());
+ EXPECT_DOUBLE_EQ(0.0, transform.m34());
+ EXPECT_DOUBLE_EQ(0.0, transform.m41());
+ EXPECT_DOUBLE_EQ(0.0, transform.m42());
+ EXPECT_DOUBLE_EQ(0.0, transform.m43());
+ EXPECT_DOUBLE_EQ(1.0, transform.m44());
+}
+
+static void testGetAndSet(WebCore::TransformationMatrix& transform)
+{
+ transform.setA(1.1);
+ EXPECT_DOUBLE_EQ(1.1, transform.a());
+ transform.setB(2.2);
+ EXPECT_DOUBLE_EQ(2.2, transform.b());
+ transform.setC(3.3);
+ EXPECT_DOUBLE_EQ(3.3, transform.c());
+ transform.setD(4.4);
+ EXPECT_DOUBLE_EQ(4.4, transform.d());
+ transform.setE(5.5);
+ EXPECT_DOUBLE_EQ(5.5, transform.e());
+ transform.setF(6.6);
+ EXPECT_DOUBLE_EQ(6.6, transform.f());
+
+ transform.setM11(1.1);
+ EXPECT_DOUBLE_EQ(1.1, transform.m11());
+ transform.setM12(2.2);
+ EXPECT_DOUBLE_EQ(2.2, transform.m12());
+ transform.setM13(3.3);
+ EXPECT_DOUBLE_EQ(3.3, transform.m13());
+ transform.setM14(4.4);
+ EXPECT_DOUBLE_EQ(4.4, transform.m14());
+ transform.setM21(5.5);
+ EXPECT_DOUBLE_EQ(5.5, transform.m21());
+ transform.setM22(6.6);
+ EXPECT_DOUBLE_EQ(6.6, transform.m22());
+ transform.setM23(7.7);
+ EXPECT_DOUBLE_EQ(7.7, transform.m23());
+ transform.setM24(8.8);
+ EXPECT_DOUBLE_EQ(8.8, transform.m24());
+ transform.setM31(9.9);
+ EXPECT_DOUBLE_EQ(9.9, transform.m31());
+ transform.setM32(10.10);
+ EXPECT_DOUBLE_EQ(10.10, transform.m32());
+ transform.setM33(11.11);
+ EXPECT_DOUBLE_EQ(11.11, transform.m33());
+ transform.setM34(12.12);
+ EXPECT_DOUBLE_EQ(12.12, transform.m34());
+ transform.setM41(13.13);
+ EXPECT_DOUBLE_EQ(13.13, transform.m41());
+ transform.setM42(14.14);
+ EXPECT_DOUBLE_EQ(14.14, transform.m42());
+ transform.setM43(15.15);
+ EXPECT_DOUBLE_EQ(15.15, transform.m43());
+ transform.setM44(16.16);
+ EXPECT_DOUBLE_EQ(16.16, transform.m44());
+}
+
+TEST(TransformationMatrix, DefaultConstruction)
+{
+ WebCore::TransformationMatrix test;
+
+ testIdentity(test);
+
+ testGetAndSet(test);
+
+ ASSERT_FALSE(test.isIdentity());
+}
+
+static void testAffineLikeConstruction(const WebCore::TransformationMatrix& transform)
+{
+ EXPECT_DOUBLE_EQ(6.0, transform.a());
+ EXPECT_DOUBLE_EQ(5.0, transform.b());
+ EXPECT_DOUBLE_EQ(4.0, transform.c());
+ EXPECT_DOUBLE_EQ(3.0, transform.d());
+ EXPECT_DOUBLE_EQ(2.0, transform.e());
+ EXPECT_DOUBLE_EQ(1.0, transform.f());
+}
+
+static void testValueConstruction(const WebCore::TransformationMatrix& transform)
+{
+ EXPECT_DOUBLE_EQ(16.0, transform.m11());
+ EXPECT_DOUBLE_EQ(15.0, transform.m12());
+ EXPECT_DOUBLE_EQ(14.0, transform.m13());
+ EXPECT_DOUBLE_EQ(13.0, transform.m14());
+ EXPECT_DOUBLE_EQ(12.0, transform.m21());
+ EXPECT_DOUBLE_EQ(11.0, transform.m22());
+ EXPECT_DOUBLE_EQ(10.0, transform.m23());
+ EXPECT_DOUBLE_EQ(9.0, transform.m24());
+ EXPECT_DOUBLE_EQ(8.0, transform.m31());
+ EXPECT_DOUBLE_EQ(7.0, transform.m32());
+ EXPECT_DOUBLE_EQ(6.0, transform.m33());
+ EXPECT_DOUBLE_EQ(5.0, transform.m34());
+ EXPECT_DOUBLE_EQ(4.0, transform.m41());
+ EXPECT_DOUBLE_EQ(3.0, transform.m42());
+ EXPECT_DOUBLE_EQ(2.0, transform.m43());
+ EXPECT_DOUBLE_EQ(1.0, transform.m44());
+ ASSERT_FALSE(transform.isAffine());
+}
+
+TEST(TransformationMatrix, ValueConstruction)
+{
+ WebCore::TransformationMatrix test1(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ testAffineLikeConstruction(test1);
+
+ ASSERT_FALSE(test1.isIdentity());
+ ASSERT_TRUE(test1.isAffine());
+
+ WebCore::TransformationMatrix test2(16.0, 15.0, 14.0, 13.0, 12.0, 11.0, 10.0,
+ 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ testValueConstruction(test2);
+
+ testGetAndSet(test2);
+
+ ASSERT_FALSE(test2.isIdentity());
+ ASSERT_FALSE(test2.isAffine());
+
+ test2.makeIdentity();
+
+ testIdentity(test2);
+
+ ASSERT_TRUE(test2.isIdentity());
+}
+
+#if USE(CG)
+TEST(TransformationMatrix, CGAffineTransformConstruction)
+{
+ CGAffineTransform cgTransform = CGAffineTransformMake(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+ WebCore::TransformationMatrix test(cgTransform);
+
+ testAffineLikeConstruction(test);
+ testGetAndSet(test);
+
+ ASSERT_FALSE(test.isIdentity());
+}
+#endif
+
+#if PLATFORM(WIN)
+TEST(TransformationMatrix, D2D1MatrixConstruction)
+{
+ D2D1_MATRIX_3X2_F d2dTransform = D2D1::Matrix3x2F(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+ WebCore::TransformationMatrix test(d2dTransform);
+
+ testAffineLikeConstruction(test);
+ testGetAndSet(test);
+
+ ASSERT_FALSE(test.isIdentity());
+}
+#endif
+
+TEST(TransformationMatrix, AffineTransformConstruction)
+{
+ WebCore::AffineTransform affineTransform(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+ WebCore::TransformationMatrix test(affineTransform);
+
+ testAffineLikeConstruction(test);
+ testGetAndSet(test);
+
+ ASSERT_FALSE(test.isIdentity());
+}
+
+TEST(TransformationMatrix, TransformMatrixConstruction)
+{
+ WebCore::TransformationMatrix matrix(16.0, 15.0, 14.0, 13.0, 12.0, 11.0, 10.0,
+ 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+ WebCore::TransformationMatrix test(matrix);
+
+ testValueConstruction(test);
+}
+
+TEST(TransformationMatrix, Assignment)
+{
+ WebCore::TransformationMatrix test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+ WebCore::TransformationMatrix matrix(16.0, 15.0, 14.0, 13.0, 12.0, 11.0, 10.0,
+ 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ testAffineLikeConstruction(test);
+
+ test = matrix;
+
+ testValueConstruction(test);
+}
+
+TEST(TransformationMatrix, Identity)
+{
+ WebCore::TransformationMatrix test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ ASSERT_FALSE(test.isIdentity());
+ ASSERT_FALSE(test.isIdentityOrTranslation());
+
+ test.makeIdentity();
+
+ ASSERT_TRUE(test.isIdentity());
+ ASSERT_TRUE(test.isIdentityOrTranslation());
+
+ testIdentity(test);
+}
+
+static void testAffineVersion(WebCore::TransformationMatrix affineTransformMatrix)
+{
+ ASSERT_FALSE(affineTransformMatrix.isIdentity());
+ ASSERT_FALSE(affineTransformMatrix.isIdentityOrTranslation());
+ ASSERT_TRUE(affineTransformMatrix.isAffine());
+
+ EXPECT_DOUBLE_EQ(16.0, affineTransformMatrix.m11());
+ EXPECT_DOUBLE_EQ(15.0, affineTransformMatrix.m12());
+ EXPECT_DOUBLE_EQ(0.0, affineTransformMatrix.m13());
+ EXPECT_DOUBLE_EQ(0.0, affineTransformMatrix.m14());
+ EXPECT_DOUBLE_EQ(12.0, affineTransformMatrix.m21());
+ EXPECT_DOUBLE_EQ(11.0, affineTransformMatrix.m22());
+ EXPECT_DOUBLE_EQ(0.0, affineTransformMatrix.m23());
+ EXPECT_DOUBLE_EQ(0.0, affineTransformMatrix.m24());
+ EXPECT_DOUBLE_EQ(0.0, affineTransformMatrix.m31());
+ EXPECT_DOUBLE_EQ(0.0, affineTransformMatrix.m32());
+ EXPECT_DOUBLE_EQ(1.0, affineTransformMatrix.m33());
+ EXPECT_DOUBLE_EQ(0.0, affineTransformMatrix.m34());
+ EXPECT_DOUBLE_EQ(4.0, affineTransformMatrix.m41());
+ EXPECT_DOUBLE_EQ(3.0, affineTransformMatrix.m42());
+ EXPECT_DOUBLE_EQ(0.0, affineTransformMatrix.m43());
+ EXPECT_DOUBLE_EQ(1.0, affineTransformMatrix.m44());
+}
+
+TEST(TransformationMatrix, AffineVersion)
+{
+ WebCore::TransformationMatrix test(16.0, 15.0, 14.0, 13.0, 12.0, 11.0, 10.0,
+ 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ ASSERT_FALSE(test.isIdentity());
+ ASSERT_FALSE(test.isIdentityOrTranslation());
+ ASSERT_FALSE(test.isAffine());
+
+ auto affineCopy = test.toAffineTransform();
+
+ testAffineVersion(affineCopy);
+
+ test.makeAffine();
+
+ testAffineVersion(test);
+}
+
+TEST(TransformationMatrix, MapFloatPoint)
+{
+ WebCore::TransformationMatrix test;
+ WebCore::FloatPoint point(100.0f, 50.0f);
+
+ auto mappedPoint = test.mapPoint(point);
+
+ ASSERT_FLOAT_EQ(100.0f, mappedPoint.x());
+ ASSERT_FLOAT_EQ(50.0f, mappedPoint.y());
+
+ test.setD(2.0);
+
+ auto mappedPoint2 = test.mapPoint(point);
+
+ ASSERT_FLOAT_EQ(100.0f, mappedPoint2.x());
+ ASSERT_FLOAT_EQ(100.0f, mappedPoint2.y());
+
+ test.setA(0.5);
+
+ auto mappedPoint3 = test.mapPoint(point);
+
+ ASSERT_FLOAT_EQ(50.0f, mappedPoint3.x());
+ ASSERT_FLOAT_EQ(100.0f, mappedPoint3.y());
+
+ test.setM22(0.5);
+
+ auto mappedPoint4 = test.mapPoint(point);
+
+ ASSERT_FLOAT_EQ(50.0f, mappedPoint4.x());
+ ASSERT_FLOAT_EQ(25.0f, mappedPoint4.y());
+
+ test.setM11(2.0);
+
+ auto mappedPoint5 = test.mapPoint(point);
+
+ ASSERT_FLOAT_EQ(200.0f, mappedPoint5.x());
+ ASSERT_FLOAT_EQ(25.0f, mappedPoint5.y());
+}
+
+TEST(TransformationMatrix, MapIntPoint)
+{
+ WebCore::TransformationMatrix test;
+ WebCore::IntPoint point(100, 50);
+
+ auto mappedPoint = test.mapPoint(point);
+
+ ASSERT_EQ(100, mappedPoint.x());
+ ASSERT_EQ(50, mappedPoint.y());
+
+ test.setD(2.0);
+
+ auto mappedPoint2 = test.mapPoint(point);
+
+ ASSERT_EQ(100, mappedPoint2.x());
+ ASSERT_EQ(100, mappedPoint2.y());
+
+ test.setA(0.5);
+
+ auto mappedPoint3 = test.mapPoint(point);
+
+ ASSERT_EQ(50, mappedPoint3.x());
+ ASSERT_EQ(100, mappedPoint3.y());
+
+ test.setM22(0.5);
+
+ auto mappedPoint4 = test.mapPoint(point);
+
+ ASSERT_EQ(50, mappedPoint4.x());
+ ASSERT_EQ(25, mappedPoint4.y());
+
+ test.setM11(2.0);
+
+ auto mappedPoint5 = test.mapPoint(point);
+
+ ASSERT_EQ(200, mappedPoint5.x());
+ ASSERT_EQ(25, mappedPoint5.y());
+}
+
+TEST(TransformationMatrix, MapIntRect)
+{
+ WebCore::TransformationMatrix test;
+ WebCore::IntRect rect(10, 20, 200, 300);
+
+ auto mappedRect = test.mapRect(rect);
+
+ ASSERT_EQ(10, mappedRect.x());
+ ASSERT_EQ(20, mappedRect.y());
+ ASSERT_EQ(200, mappedRect.width());
+ ASSERT_EQ(300, mappedRect.height());
+
+ test.setD(2.0);
+
+ auto mappedRect2 = test.mapRect(rect);
+
+ ASSERT_EQ(10, mappedRect2.x());
+ ASSERT_EQ(40, mappedRect2.y());
+ ASSERT_EQ(200, mappedRect2.width());
+ ASSERT_EQ(600, mappedRect2.height());
+
+ test.setA(0.5);
+
+ auto mappedRect3 = test.mapRect(rect);
+
+ ASSERT_EQ(5, mappedRect3.x());
+ ASSERT_EQ(40, mappedRect3.y());
+ ASSERT_EQ(100, mappedRect3.width());
+ ASSERT_EQ(600, mappedRect3.height());
+
+ test.setM22(0.5);
+
+ auto mappedRect4 = test.mapRect(rect);
+
+ ASSERT_EQ(5, mappedRect4.x());
+ ASSERT_EQ(10, mappedRect4.y());
+ ASSERT_EQ(100, mappedRect4.width());
+ ASSERT_EQ(150, mappedRect4.height());
+
+ test.setM11(2.0);
+
+ auto mappedRect5 = test.mapRect(rect);
+
+ ASSERT_EQ(20, mappedRect5.x());
+ ASSERT_EQ(10, mappedRect5.y());
+ ASSERT_EQ(100, mappedRect4.width());
+ ASSERT_EQ(150, mappedRect4.height());
+}
+
+TEST(TransformationMatrix, MapFloatRect)
+{
+ WebCore::TransformationMatrix test;
+ WebCore::FloatRect rect(10.f, 20.0f, 200.0f, 300.0f);
+
+ auto mappedRect = test.mapRect(rect);
+
+ ASSERT_FLOAT_EQ(10.0f, mappedRect.x());
+ ASSERT_FLOAT_EQ(20.0f, mappedRect.y());
+ ASSERT_FLOAT_EQ(200.0f, mappedRect.width());
+ ASSERT_FLOAT_EQ(300.0f, mappedRect.height());
+
+ test.setD(2.0);
+
+ auto mappedRect2 = test.mapRect(rect);
+
+ ASSERT_FLOAT_EQ(10.0f, mappedRect2.x());
+ ASSERT_FLOAT_EQ(40.0f, mappedRect2.y());
+ ASSERT_FLOAT_EQ(200.0f, mappedRect2.width());
+ ASSERT_FLOAT_EQ(600.0f, mappedRect2.height());
+
+ test.setA(0.5);
+
+ auto mappedRect3 = test.mapRect(rect);
+
+ ASSERT_FLOAT_EQ(5.0f, mappedRect3.x());
+ ASSERT_FLOAT_EQ(40.0f, mappedRect3.y());
+ ASSERT_FLOAT_EQ(100.0f, mappedRect3.width());
+ ASSERT_FLOAT_EQ(600.0f, mappedRect3.height());
+
+ test.setM22(0.5);
+
+ auto mappedRect4 = test.mapRect(rect);
+
+ ASSERT_FLOAT_EQ(5.0f, mappedRect4.x());
+ ASSERT_FLOAT_EQ(10.0f, mappedRect4.y());
+ ASSERT_FLOAT_EQ(100.0f, mappedRect4.width());
+ ASSERT_FLOAT_EQ(150.0f, mappedRect4.height());
+
+ test.setM11(2.0);
+
+ auto mappedRect5 = test.mapRect(rect);
+
+ ASSERT_FLOAT_EQ(20.0f, mappedRect5.x());
+ ASSERT_FLOAT_EQ(10.0f, mappedRect5.y());
+ ASSERT_FLOAT_EQ(100.0f, mappedRect4.width());
+ ASSERT_FLOAT_EQ(150.0f, mappedRect4.height());
+}
+
+TEST(TransformationMatrix, MapFloatQuad)
+{
+ WebCore::FloatRect rect(100.0f, 100.0f, 100.0f, 50.0f);
+ WebCore::FloatQuad quad(rect);
+
+ ASSERT_FLOAT_EQ(100.0f, quad.p1().x());
+ ASSERT_FLOAT_EQ(100.0f, quad.p1().y());
+ ASSERT_FLOAT_EQ(200.0f, quad.p2().x());
+ ASSERT_FLOAT_EQ(100.0f, quad.p2().y());
+ ASSERT_FLOAT_EQ(200.0f, quad.p3().x());
+ ASSERT_FLOAT_EQ(150.0f, quad.p3().y());
+ ASSERT_FLOAT_EQ(100.0f, quad.p4().x());
+ ASSERT_FLOAT_EQ(150.0f, quad.p4().y());
+
+ WebCore::TransformationMatrix test;
+ auto mappedQuad = test.mapQuad(quad);
+
+ ASSERT_FLOAT_EQ(100.0f, mappedQuad.p1().x());
+ ASSERT_FLOAT_EQ(100.0f, mappedQuad.p1().y());
+ ASSERT_FLOAT_EQ(200.0f, mappedQuad.p2().x());
+ ASSERT_FLOAT_EQ(100.0f, mappedQuad.p2().y());
+ ASSERT_FLOAT_EQ(200.0f, mappedQuad.p3().x());
+ ASSERT_FLOAT_EQ(150.0f, mappedQuad.p3().y());
+ ASSERT_FLOAT_EQ(100.0f, mappedQuad.p4().x());
+ ASSERT_FLOAT_EQ(150.0f, mappedQuad.p4().y());
+
+ test.setD(2.0);
+
+ auto mappedQuad2 = test.mapQuad(quad);
+
+ ASSERT_FLOAT_EQ(100.0f, mappedQuad2.p1().x());
+ ASSERT_FLOAT_EQ(200.0f, mappedQuad2.p1().y());
+ ASSERT_FLOAT_EQ(200.0f, mappedQuad2.p2().x());
+ ASSERT_FLOAT_EQ(200.0f, mappedQuad2.p2().y());
+ ASSERT_FLOAT_EQ(200.0f, mappedQuad2.p3().x());
+ ASSERT_FLOAT_EQ(300.0f, mappedQuad2.p3().y());
+ ASSERT_FLOAT_EQ(100.0f, mappedQuad2.p4().x());
+ ASSERT_FLOAT_EQ(300.0f, mappedQuad2.p4().y());
+
+ test.setA(0.5);
+
+ auto mappedQuad3 = test.mapQuad(quad);
+
+ ASSERT_FLOAT_EQ(50.0f, mappedQuad3.p1().x());
+ ASSERT_FLOAT_EQ(200.0f, mappedQuad3.p1().y());
+ ASSERT_FLOAT_EQ(100.0f, mappedQuad3.p2().x());
+ ASSERT_FLOAT_EQ(200.0f, mappedQuad3.p2().y());
+ ASSERT_FLOAT_EQ(100.0f, mappedQuad3.p3().x());
+ ASSERT_FLOAT_EQ(300.0f, mappedQuad3.p3().y());
+ ASSERT_FLOAT_EQ(50.0f, mappedQuad3.p4().x());
+ ASSERT_FLOAT_EQ(300.0f, mappedQuad3.p4().y());
+
+ test.setM22(0.5);
+
+ auto mappedQuad4 = test.mapQuad(quad);
+
+ ASSERT_FLOAT_EQ(50.0f, mappedQuad4.p1().x());
+ ASSERT_FLOAT_EQ(50.0f, mappedQuad4.p1().y());
+ ASSERT_FLOAT_EQ(100.0f, mappedQuad4.p2().x());
+ ASSERT_FLOAT_EQ(50.0f, mappedQuad4.p2().y());
+ ASSERT_FLOAT_EQ(100.0f, mappedQuad4.p3().x());
+ ASSERT_FLOAT_EQ(75.0f, mappedQuad4.p3().y());
+ ASSERT_FLOAT_EQ(50.0f, mappedQuad4.p4().x());
+ ASSERT_FLOAT_EQ(75.0f, mappedQuad4.p4().y());
+
+ test.setM11(2.0);
+
+ auto mappedQuad5 = test.mapQuad(quad);
+
+ ASSERT_FLOAT_EQ(200.0f, mappedQuad5.p1().x());
+ ASSERT_FLOAT_EQ(50.0f, mappedQuad5.p1().y());
+ ASSERT_FLOAT_EQ(400.0f, mappedQuad5.p2().x());
+ ASSERT_FLOAT_EQ(50.0f, mappedQuad5.p2().y());
+ ASSERT_FLOAT_EQ(400.0f, mappedQuad5.p3().x());
+ ASSERT_FLOAT_EQ(75.0f, mappedQuad5.p3().y());
+ ASSERT_FLOAT_EQ(200.0f, mappedQuad5.p4().x());
+ ASSERT_FLOAT_EQ(75.0f, mappedQuad5.p4().y());
+}
+
+static void testDoubled(const WebCore::TransformationMatrix& transform)
+{
+ EXPECT_DOUBLE_EQ(12.0, transform.a());
+ EXPECT_DOUBLE_EQ(10.0, transform.b());
+ EXPECT_DOUBLE_EQ(8.0, transform.c());
+ EXPECT_DOUBLE_EQ(6.0, transform.d());
+ EXPECT_DOUBLE_EQ(2.0, transform.e());
+ EXPECT_DOUBLE_EQ(1.0, transform.f());
+}
+
+static void testHalved(const WebCore::TransformationMatrix& transform)
+{
+ EXPECT_DOUBLE_EQ(3.0, transform.a());
+ EXPECT_DOUBLE_EQ(2.5, transform.b());
+ EXPECT_DOUBLE_EQ(2.0, transform.c());
+ EXPECT_DOUBLE_EQ(1.5, transform.d());
+ EXPECT_DOUBLE_EQ(2.0, transform.e());
+ EXPECT_DOUBLE_EQ(1.0, transform.f());
+}
+
+static void testDoubled2(const WebCore::TransformationMatrix& transform)
+{
+ EXPECT_DOUBLE_EQ(32.0, transform.m11());
+ EXPECT_DOUBLE_EQ(30.0, transform.m12());
+ EXPECT_DOUBLE_EQ(28.0, transform.m13());
+ EXPECT_DOUBLE_EQ(26.0, transform.m14());
+ EXPECT_DOUBLE_EQ(24.0, transform.m21());
+ EXPECT_DOUBLE_EQ(22.0, transform.m22());
+ EXPECT_DOUBLE_EQ(20.0, transform.m23());
+ EXPECT_DOUBLE_EQ(18.0, transform.m24());
+ EXPECT_DOUBLE_EQ(16.0, transform.m31());
+ EXPECT_DOUBLE_EQ(14.0, transform.m32());
+ EXPECT_DOUBLE_EQ(12.0, transform.m33());
+ EXPECT_DOUBLE_EQ(10.0, transform.m34());
+ EXPECT_DOUBLE_EQ(8.0, transform.m41());
+ EXPECT_DOUBLE_EQ(6.0, transform.m42());
+ EXPECT_DOUBLE_EQ(4.0, transform.m43());
+ EXPECT_DOUBLE_EQ(2.0, transform.m44());
+}
+
+static void testHalved2(const WebCore::TransformationMatrix& transform)
+{
+ EXPECT_DOUBLE_EQ(8.0, transform.m11());
+ EXPECT_DOUBLE_EQ(7.5, transform.m12());
+ EXPECT_DOUBLE_EQ(7.0, transform.m13());
+ EXPECT_DOUBLE_EQ(6.5, transform.m14());
+ EXPECT_DOUBLE_EQ(6.0, transform.m21());
+ EXPECT_DOUBLE_EQ(5.5, transform.m22());
+ EXPECT_DOUBLE_EQ(5.0, transform.m23());
+ EXPECT_DOUBLE_EQ(4.5, transform.m24());
+ EXPECT_DOUBLE_EQ(4.0, transform.m31());
+ EXPECT_DOUBLE_EQ(3.5, transform.m32());
+ EXPECT_DOUBLE_EQ(3.0, transform.m33());
+ EXPECT_DOUBLE_EQ(2.5, transform.m34());
+ EXPECT_DOUBLE_EQ(2.0, transform.m41());
+ EXPECT_DOUBLE_EQ(1.5, transform.m42());
+ EXPECT_DOUBLE_EQ(1.0, transform.m43());
+ EXPECT_DOUBLE_EQ(0.5, transform.m44());
+}
+
+TEST(TransformationMatrix, Multiply)
+{
+ WebCore::TransformationMatrix test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+ WebCore::TransformationMatrix identity;
+
+ testAffineLikeConstruction(test);
+
+ test.multiply(identity);
+
+ testAffineLikeConstruction(test);
+
+ WebCore::TransformationMatrix doubler(2.0, 0.0, 0.0, 2.0, 0.0, 0.0);
+
+ test.multiply(doubler);
+
+ testDoubled(test);
+
+ WebCore::TransformationMatrix halver(0.5, 0.0, 0.0, 0.5, 0.0, 0.0);
+
+ test.multiply(halver);
+
+ testAffineLikeConstruction(test);
+
+ test.multiply(halver);
+
+ testHalved(test);
+
+ WebCore::TransformationMatrix test2(16.0, 15.0, 14.0, 13.0, 12.0, 11.0, 10.0,
+ 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ testValueConstruction(test2);
+
+ test2.multiply(identity);
+
+ testValueConstruction(test2);
+
+ WebCore::TransformationMatrix doubler2(2.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0,
+ 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 2.0);
+
+ test2.multiply(doubler2);
+
+ testDoubled2(test2);
+
+ WebCore::TransformationMatrix halver2(0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0,
+ 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.5);
+
+ test2.multiply(halver2);
+
+ testValueConstruction(test2);
+
+ test2.multiply(halver2);
+
+ testHalved2(test2);
+
+ WebCore::TransformationMatrix test3(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ test3 *= identity;
+
+ testAffineLikeConstruction(test3);
+
+ test3 *= doubler;
+
+ testDoubled(test3);
+
+ const WebCore::TransformationMatrix test4(16.0, 15.0, 14.0, 13.0, 12.0, 11.0, 10.0,
+ 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ auto result1 = test4 * identity;
+
+ testValueConstruction(result1);
+
+ auto result2 = test4 * doubler2;
+
+ testDoubled2(result2);
+}
+
+static void testScaledByTwo(const WebCore::TransformationMatrix& transform)
+{
+ EXPECT_DOUBLE_EQ(32.0, transform.m11());
+ EXPECT_DOUBLE_EQ(30.0, transform.m12());
+ EXPECT_DOUBLE_EQ(28.0, transform.m13());
+ EXPECT_DOUBLE_EQ(26.0, transform.m14());
+ EXPECT_DOUBLE_EQ(24.0, transform.m21());
+ EXPECT_DOUBLE_EQ(22.0, transform.m22());
+ EXPECT_DOUBLE_EQ(20.0, transform.m23());
+ EXPECT_DOUBLE_EQ(18.0, transform.m24());
+ EXPECT_DOUBLE_EQ(8.0, transform.m31());
+ EXPECT_DOUBLE_EQ(7.0, transform.m32());
+ EXPECT_DOUBLE_EQ(6.0, transform.m33());
+ EXPECT_DOUBLE_EQ(5.0, transform.m34());
+ EXPECT_DOUBLE_EQ(4.0, transform.m41());
+ EXPECT_DOUBLE_EQ(3.0, transform.m42());
+ EXPECT_DOUBLE_EQ(2.0, transform.m43());
+ EXPECT_DOUBLE_EQ(1.0, transform.m44());
+}
+
+static void testScaledByHalf(const WebCore::TransformationMatrix& transform)
+{
+ EXPECT_DOUBLE_EQ(8.0, transform.m11());
+ EXPECT_DOUBLE_EQ(7.5, transform.m12());
+ EXPECT_DOUBLE_EQ(7.0, transform.m13());
+ EXPECT_DOUBLE_EQ(6.5, transform.m14());
+ EXPECT_DOUBLE_EQ(6.0, transform.m21());
+ EXPECT_DOUBLE_EQ(5.5, transform.m22());
+ EXPECT_DOUBLE_EQ(5.0, transform.m23());
+ EXPECT_DOUBLE_EQ(4.5, transform.m24());
+ EXPECT_DOUBLE_EQ(8.0, transform.m31());
+ EXPECT_DOUBLE_EQ(7.0, transform.m32());
+ EXPECT_DOUBLE_EQ(6.0, transform.m33());
+ EXPECT_DOUBLE_EQ(5.0, transform.m34());
+ EXPECT_DOUBLE_EQ(4.0, transform.m41());
+ EXPECT_DOUBLE_EQ(3.0, transform.m42());
+ EXPECT_DOUBLE_EQ(2.0, transform.m43());
+ EXPECT_DOUBLE_EQ(1.0, transform.m44());
+}
+
+
+TEST(TransformationMatrix, Scale)
+{
+ WebCore::TransformationMatrix test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ testAffineLikeConstruction(test);
+
+ test.scale(1.0);
+
+ testAffineLikeConstruction(test);
+
+ test.scale(2.0);
+
+ testDoubled(test);
+
+ test.scale(0.5);
+
+ testAffineLikeConstruction(test);
+
+ test.scale(0.5);
+
+ testHalved(test);
+
+ WebCore::TransformationMatrix test2(16.0, 15.0, 14.0, 13.0, 12.0, 11.0, 10.0,
+ 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ testValueConstruction(test2);
+
+ test2.scale(2.0);
+
+ testScaledByTwo(test2);
+
+ test2.scale(0.5);
+
+ testValueConstruction(test2);
+
+ test2.scale(0.5);
+
+ testScaledByHalf(test2);
+}
+
+TEST(TransformationMatrix, ScaleUniformNonUniform)
+{
+ WebCore::TransformationMatrix test(16.0, 15.0, 14.0, 13.0, 12.0, 11.0, 10.0,
+ 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ testValueConstruction(test);
+
+ test.scaleNonUniform(1.0, 1.0);
+
+ testValueConstruction(test);
+
+ test.scaleNonUniform(2.0, 2.0);
+
+ testScaledByTwo(test);
+
+ test.scaleNonUniform(0.5, 0.5);
+
+ testValueConstruction(test);
+
+ test.scaleNonUniform(0.5, 0.5);
+
+ testScaledByHalf(test);
+}
+
+TEST(TransformationMatrix, Rotate)
+{
+ WebCore::TransformationMatrix test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ test.rotate(360.0);
+
+ testAffineLikeConstruction(test);
+
+ test.rotate(180.0);
+
+ static double epsilon = 0.0001;
+
+ EXPECT_NEAR(-6.0, test.a(), epsilon);
+ EXPECT_NEAR(-5.0, test.b(), epsilon);
+ EXPECT_NEAR(-4.0, test.c(), epsilon);
+ EXPECT_NEAR(-3.0, test.d(), epsilon);
+ EXPECT_DOUBLE_EQ(2.0, test.e());
+ EXPECT_DOUBLE_EQ(1.0, test.f());
+
+ test.rotate(-180.0);
+
+ testAffineLikeConstruction(test);
+
+ test.rotate(90.0);
+
+ EXPECT_NEAR(4.0, test.a(), epsilon);
+ EXPECT_NEAR(3.0, test.b(), epsilon);
+ EXPECT_NEAR(-6.0, test.c(), epsilon);
+ EXPECT_NEAR(-5.0, test.d(), epsilon);
+ EXPECT_DOUBLE_EQ(2.0, test.e());
+ EXPECT_DOUBLE_EQ(1.0, test.f());
+
+ test.rotate(-90.0);
+
+ testAffineLikeConstruction(test);
+}
+
+TEST(TransformationMatrix, TranslateXY)
+{
+ WebCore::TransformationMatrix test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ test.translate(0.0, 0.0);
+
+ testAffineLikeConstruction(test);
+
+ test.translate(5.0, 0.0);
+
+ EXPECT_DOUBLE_EQ(6.0, test.a());
+ EXPECT_DOUBLE_EQ(5.0, test.b());
+ EXPECT_DOUBLE_EQ(4.0, test.c());
+ EXPECT_DOUBLE_EQ(3.0, test.d());
+ EXPECT_DOUBLE_EQ(32.0, test.e());
+ EXPECT_DOUBLE_EQ(26.0, test.f());
+
+ test.translate(0.0, -1.2);
+
+ EXPECT_DOUBLE_EQ(6.0, test.a());
+ EXPECT_DOUBLE_EQ(5.0, test.b());
+ EXPECT_DOUBLE_EQ(4.0, test.c());
+ EXPECT_DOUBLE_EQ(3.0, test.d());
+ EXPECT_DOUBLE_EQ(27.2, test.e());
+ EXPECT_DOUBLE_EQ(22.4, test.f());
+}
+
+TEST(TransformationMatrix, FlipX)
+{
+ WebCore::TransformationMatrix test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ testAffineLikeConstruction(test);
+
+ test.flipX();
+
+ EXPECT_DOUBLE_EQ(-6.0, test.a());
+ EXPECT_DOUBLE_EQ(-5.0, test.b());
+ EXPECT_DOUBLE_EQ(4.0, test.c());
+ EXPECT_DOUBLE_EQ(3.0, test.d());
+ EXPECT_DOUBLE_EQ(2.0, test.e());
+ EXPECT_DOUBLE_EQ(1.0, test.f());
+
+ test.flipX();
+
+ testAffineLikeConstruction(test);
+
+ WebCore::TransformationMatrix test2;
+
+ testIdentity(test2);
+
+ ASSERT_TRUE(test2.isIdentity());
+ ASSERT_TRUE(test2.isIdentityOrTranslation());
+
+ test2.flipX();
+
+ EXPECT_DOUBLE_EQ(-1.0, test2.a());
+ EXPECT_DOUBLE_EQ(0.0, test2.b());
+ EXPECT_DOUBLE_EQ(0.0, test2.c());
+ EXPECT_DOUBLE_EQ(1.0, test2.d());
+ EXPECT_DOUBLE_EQ(0.0, test2.e());
+ EXPECT_DOUBLE_EQ(0.0, test2.f());
+
+ ASSERT_FALSE(test2.isIdentity());
+ ASSERT_FALSE(test2.isIdentityOrTranslation());
+
+ test2.flipX();
+
+ ASSERT_TRUE(test2.isIdentity());
+ ASSERT_TRUE(test2.isIdentityOrTranslation());
+}
+
+TEST(TransformationMatrix, FlipY)
+{
+ WebCore::TransformationMatrix test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ testAffineLikeConstruction(test);
+
+ test.flipY();
+
+ EXPECT_DOUBLE_EQ(6.0, test.a());
+ EXPECT_DOUBLE_EQ(5.0, test.b());
+ EXPECT_DOUBLE_EQ(-4.0, test.c());
+ EXPECT_DOUBLE_EQ(-3.0, test.d());
+ EXPECT_DOUBLE_EQ(2.0, test.e());
+ EXPECT_DOUBLE_EQ(1.0, test.f());
+
+ test.flipY();
+
+ testAffineLikeConstruction(test);
+
+ WebCore::TransformationMatrix test2;
+
+ testIdentity(test2);
+
+ ASSERT_TRUE(test2.isIdentity());
+ ASSERT_TRUE(test2.isIdentityOrTranslation());
+
+ test2.flipY();
+
+ EXPECT_DOUBLE_EQ(1.0, test2.a());
+ EXPECT_DOUBLE_EQ(0.0, test2.b());
+ EXPECT_DOUBLE_EQ(0.0, test2.c());
+ EXPECT_DOUBLE_EQ(-1.0, test2.d());
+ EXPECT_DOUBLE_EQ(0.0, test2.e());
+ EXPECT_DOUBLE_EQ(0.0, test2.f());
+
+ ASSERT_FALSE(test2.isIdentity());
+ ASSERT_FALSE(test2.isIdentityOrTranslation());
+
+ test2.flipY();
+
+ ASSERT_TRUE(test2.isIdentity());
+ ASSERT_TRUE(test2.isIdentityOrTranslation());
+}
+
+TEST(TransformationMatrix, FlipXandFlipY)
+{
+ WebCore::TransformationMatrix test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ testAffineLikeConstruction(test);
+
+ test.flipX();
+
+ EXPECT_DOUBLE_EQ(-6.0, test.a());
+ EXPECT_DOUBLE_EQ(-5.0, test.b());
+ EXPECT_DOUBLE_EQ(4.0, test.c());
+ EXPECT_DOUBLE_EQ(3.0, test.d());
+ EXPECT_DOUBLE_EQ(2.0, test.e());
+ EXPECT_DOUBLE_EQ(1.0, test.f());
+
+ test.flipY();
+
+ EXPECT_DOUBLE_EQ(-6.0, test.a());
+ EXPECT_DOUBLE_EQ(-5.0, test.b());
+ EXPECT_DOUBLE_EQ(-4.0, test.c());
+ EXPECT_DOUBLE_EQ(-3.0, test.d());
+ EXPECT_DOUBLE_EQ(2.0, test.e());
+ EXPECT_DOUBLE_EQ(1.0, test.f());
+
+ test.flipX();
+
+ EXPECT_DOUBLE_EQ(6.0, test.a());
+ EXPECT_DOUBLE_EQ(5.0, test.b());
+ EXPECT_DOUBLE_EQ(-4.0, test.c());
+ EXPECT_DOUBLE_EQ(-3.0, test.d());
+ EXPECT_DOUBLE_EQ(2.0, test.e());
+ EXPECT_DOUBLE_EQ(1.0, test.f());
+
+ test.flipY();
+
+ testAffineLikeConstruction(test);
+
+ WebCore::TransformationMatrix test2;
+
+ ASSERT_TRUE(test2.isIdentity());
+ ASSERT_TRUE(test2.isIdentityOrTranslation());
+
+ test2.flipX();
+
+ ASSERT_FALSE(test2.isIdentity());
+ ASSERT_FALSE(test2.isIdentityOrTranslation());
+
+ test2.flipY();
+
+ ASSERT_FALSE(test2.isIdentity());
+ ASSERT_FALSE(test2.isIdentityOrTranslation());
+
+ test2.flipX();
+
+ ASSERT_FALSE(test2.isIdentity());
+ ASSERT_FALSE(test2.isIdentityOrTranslation());
+
+ test2.flipY();
+
+ ASSERT_TRUE(test2.isIdentity());
+ ASSERT_TRUE(test2.isIdentityOrTranslation());
+}
+
+TEST(TransformationMatrix, Skew)
+{
+ WebCore::TransformationMatrix test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+ testAffineLikeConstruction(test);
+
+ test.skew(360.0, 360.0);
+
+ testAffineLikeConstruction(test);
+
+ test.skew(0.0, 0.0);
+
+ testAffineLikeConstruction(test);
+
+ test.skew(180.0, 180.0);
+
+ static double epsilon = 0.0001;
+
+ EXPECT_DOUBLE_EQ(6.0, test.a());
+ EXPECT_DOUBLE_EQ(5.0, test.b());
+ EXPECT_NEAR(4.0, test.c(), epsilon);
+ EXPECT_DOUBLE_EQ(3.0, test.d());
+ EXPECT_DOUBLE_EQ(2.0, test.e());
+ EXPECT_DOUBLE_EQ(1.0, test.f());
+
+ test.skew(-180.0, -180.0);
+
+ testAffineLikeConstruction(test);
+}
+
+TEST(TransformationMatrix, Inverse)
+{
+ WebCore::TransformationMatrix test;
+
+ auto inverse = test.inverse();
+
+ ASSERT(inverse);
+
+ EXPECT_DOUBLE_EQ(1.0, inverse->a());
+ EXPECT_DOUBLE_EQ(0.0, inverse->b());
+ EXPECT_DOUBLE_EQ(0.0, inverse->c());
+ EXPECT_DOUBLE_EQ(1.0, inverse->d());
+ EXPECT_DOUBLE_EQ(0.0, inverse->e());
+ EXPECT_DOUBLE_EQ(0.0, inverse->f());
+
+ auto test2 = test * inverse.value();
+
+ testIdentity(test2);
+}
+
+TEST(TransformationMatrix, NonInvertableBlend)
+{
+ WebCore::TransformationMatrix from;
+ WebCore::TransformationMatrix to(2.7133590938, 0.0, 0.0, 0.0, 0.0, 2.4645137761, 0.0, 0.0, 0.0, 0.0, 0.00, 0.01, 0.02, 0.03, 0.04, 0.05);
+ WebCore::TransformationMatrix result;
+
+ result = to;
+ result.blend(from, 0.25);
+ EXPECT_TRUE(result == from);
+
+ result = to;
+ result.blend(from, 0.75);
+ EXPECT_TRUE(result == to);
+}
+
+TEST(TransformationMatrix, Blend)
+{
+ WebCore::TransformationMatrix transform;
+
+ WebCore::TransformationMatrix scaled;
+ scaled.scale(2.0);
+
+ transform.blend(scaled, 50);
+
+ static const double epsilon = 0.0001;
+ EXPECT_NEAR(-48.0, transform.m11(), epsilon);
+ EXPECT_NEAR(0.0, transform.m12(), epsilon);
+ EXPECT_NEAR(0.0, transform.m13(), epsilon);
+ EXPECT_NEAR(0.0, transform.m14(), epsilon);
+ EXPECT_NEAR(0.0, transform.m21(), epsilon);
+ EXPECT_NEAR(-48.0, transform.m22(), epsilon);
+ EXPECT_NEAR(0.0, transform.m23(), epsilon);
+ EXPECT_NEAR(0.0, transform.m24(), epsilon);
+ EXPECT_NEAR(0.0, transform.m31(), epsilon);
+ EXPECT_NEAR(0.0, transform.m32(), epsilon);
+ EXPECT_NEAR(1.0, transform.m33(), epsilon);
+ EXPECT_NEAR(0.0, transform.m34(), epsilon);
+ EXPECT_NEAR(0.0, transform.m41(), epsilon);
+ EXPECT_NEAR(0.0, transform.m42(), epsilon);
+ EXPECT_NEAR(0.0, transform.m43(), epsilon);
+ EXPECT_NEAR(1.0, transform.m44(), epsilon);
+}
+
+TEST(TransformationMatrix, Blend2)
+{
+ WebCore::TransformationMatrix transform;
+
+ WebCore::TransformationMatrix scaled;
+ scaled.scale(2.0);
+
+ transform.blend2(scaled, 20);
+
+ static const double epsilon = 0.0001;
+ EXPECT_NEAR(-18.0, transform.m11(), epsilon);
+ EXPECT_NEAR(0.0, transform.m12(), epsilon);
+ EXPECT_NEAR(0.0, transform.m13(), epsilon);
+ EXPECT_NEAR(0.0, transform.m14(), epsilon);
+ EXPECT_NEAR(0.0, transform.m21(), epsilon);
+ EXPECT_NEAR(-18.0, transform.m22(), epsilon);
+ EXPECT_NEAR(0.0, transform.m23(), epsilon);
+ EXPECT_NEAR(0.0, transform.m24(), epsilon);
+ EXPECT_NEAR(0.0, transform.m31(), epsilon);
+ EXPECT_NEAR(0.0, transform.m32(), epsilon);
+ EXPECT_NEAR(1.0, transform.m33(), epsilon);
+ EXPECT_NEAR(0.0, transform.m34(), epsilon);
+ EXPECT_NEAR(0.0, transform.m41(), epsilon);
+ EXPECT_NEAR(0.0, transform.m42(), epsilon);
+ EXPECT_NEAR(0.0, transform.m43(), epsilon);
+ EXPECT_NEAR(1.0, transform.m44(), epsilon);
+}
+
+TEST(TransformationMatrix, Blend4)
+{
+ WebCore::TransformationMatrix transform;
+
+ WebCore::TransformationMatrix scaled;
+ scaled.scale(2.0);
+
+ transform.blend4(scaled, 30);
+
+ static const double epsilon = 0.0001;
+ EXPECT_NEAR(-28.0, transform.m11(), epsilon);
+ EXPECT_NEAR(0.0, transform.m12(), epsilon);
+ EXPECT_NEAR(0.0, transform.m13(), epsilon);
+ EXPECT_NEAR(0.0, transform.m14(), epsilon);
+ EXPECT_NEAR(0.0, transform.m21(), epsilon);
+ EXPECT_NEAR(-28.0, transform.m22(), epsilon);
+ EXPECT_NEAR(0.0, transform.m23(), epsilon);
+ EXPECT_NEAR(0.0, transform.m24(), epsilon);
+ EXPECT_NEAR(0.0, transform.m31(), epsilon);
+ EXPECT_NEAR(0.0, transform.m32(), epsilon);
+ EXPECT_NEAR(1.0, transform.m33(), epsilon);
+ EXPECT_NEAR(0.0, transform.m34(), epsilon);
+ EXPECT_NEAR(0.0, transform.m41(), epsilon);
+ EXPECT_NEAR(0.0, transform.m42(), epsilon);
+ EXPECT_NEAR(0.0, transform.m43(), epsilon);
+ EXPECT_NEAR(1.0, transform.m44(), epsilon);
+}
+
+TEST(TransformationMatrix, Equality)
+{
+ WebCore::TransformationMatrix test(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+ WebCore::TransformationMatrix test2;
+
+ ASSERT_FALSE(test == test2);
+ ASSERT_TRUE(test != test2);
+
+ test.makeIdentity();
+
+ ASSERT_TRUE(test == test2);
+ ASSERT_FALSE(test != test2);
+
+ WebCore::TransformationMatrix test3(16.0, 15.0, 14.0, 13.0, 12.0, 11.0, 10.0,
+ 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+ WebCore::TransformationMatrix test4(test3);
+
+ ASSERT_TRUE(test3 == test4);
+ ASSERT_FALSE(test3 != test4);
+
+ test4.setM43(1002.22);
+
+ ASSERT_FALSE(test3 == test4);
+ ASSERT_TRUE(test3 != test4);
+}
+
+static void testTranslationMatrix(const WebCore::TransformationMatrix& matrix)
+{
+ EXPECT_DOUBLE_EQ(1.0, matrix.m11());
+ EXPECT_DOUBLE_EQ(0.0, matrix.m12());
+ EXPECT_DOUBLE_EQ(0.0, matrix.m13());
+ EXPECT_DOUBLE_EQ(0.0, matrix.m14());
+ EXPECT_DOUBLE_EQ(0.0, matrix.m21());
+ EXPECT_DOUBLE_EQ(1.0, matrix.m22());
+ EXPECT_DOUBLE_EQ(0.0, matrix.m23());
+ EXPECT_DOUBLE_EQ(0.0, matrix.m24());
+ EXPECT_DOUBLE_EQ(0.0, matrix.m31());
+ EXPECT_DOUBLE_EQ(0.0, matrix.m32());
+ EXPECT_DOUBLE_EQ(1.0, matrix.m33());
+ EXPECT_DOUBLE_EQ(0.0, matrix.m34());
+ EXPECT_DOUBLE_EQ(10.0, matrix.m41());
+ EXPECT_DOUBLE_EQ(15.0, matrix.m42());
+ EXPECT_DOUBLE_EQ(30.0, matrix.m43());
+ EXPECT_DOUBLE_EQ(1.0, matrix.m44());
+}
+
+TEST(TransformationMatrix, Casting)
+{
+ WebCore::TransformationMatrix test(16.0, 15.0, 14.0, 13.0, 12.0, 11.0, 10.0,
+ 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+
+#if USE(CA)
+ CATransform3D caTransform = CATransform3DMakeTranslation(10.0f, 15.0f, 30.0f);
+
+ WebCore::TransformationMatrix fromCATransform(caTransform);
+
+ testTranslationMatrix(fromCATransform);
+
+ CATransform3D caFromWK = test;
+
+ EXPECT_DOUBLE_EQ(16.0, caFromWK.m11);
+ EXPECT_DOUBLE_EQ(15.0, caFromWK.m12);
+ EXPECT_DOUBLE_EQ(14.0, caFromWK.m13);
+ EXPECT_DOUBLE_EQ(13.0, caFromWK.m14);
+ EXPECT_DOUBLE_EQ(12.0, caFromWK.m21);
+ EXPECT_DOUBLE_EQ(11.0, caFromWK.m22);
+ EXPECT_DOUBLE_EQ(10.0, caFromWK.m23);
+ EXPECT_DOUBLE_EQ(9.0, caFromWK.m24);
+ EXPECT_DOUBLE_EQ(8.0, caFromWK.m31);
+ EXPECT_DOUBLE_EQ(7.0, caFromWK.m32);
+ EXPECT_DOUBLE_EQ(6.0, caFromWK.m33);
+ EXPECT_DOUBLE_EQ(5.0, caFromWK.m34);
+ EXPECT_DOUBLE_EQ(4.0, caFromWK.m41);
+ EXPECT_DOUBLE_EQ(3.0, caFromWK.m42);
+ EXPECT_DOUBLE_EQ(2.0, caFromWK.m43);
+ EXPECT_DOUBLE_EQ(1.0, caFromWK.m44);
+#endif
+
+#if USE(CG)
+ CGAffineTransform cgTransform = CGAffineTransformMake(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+ WebCore::TransformationMatrix fromCGTransform(cgTransform);
+
+ testAffineLikeConstruction(fromCGTransform);
+
+ CGAffineTransform cgFromWK = test;
+ EXPECT_DOUBLE_EQ(16.0, cgFromWK.a);
+ EXPECT_DOUBLE_EQ(15.0, cgFromWK.b);
+ EXPECT_DOUBLE_EQ(12.0, cgFromWK.c);
+ EXPECT_DOUBLE_EQ(11.0, cgFromWK.d);
+ EXPECT_DOUBLE_EQ(4.0, cgFromWK.tx);
+ EXPECT_DOUBLE_EQ(3.0, cgFromWK.ty);
+#endif
+
+#if PLATFORM(WIN) || (PLATFORM(GTK) && OS(WINDOWS))
+ XFORM gdiFromWK = test;
+ EXPECT_DOUBLE_EQ(16.0, gdiFromWK.eM11);
+ EXPECT_DOUBLE_EQ(15.0, gdiFromWK.eM12);
+ EXPECT_DOUBLE_EQ(12.0, gdiFromWK.eM21);
+ EXPECT_DOUBLE_EQ(11.0, gdiFromWK.eM22);
+ EXPECT_DOUBLE_EQ(4.0, gdiFromWK.eDx);
+ EXPECT_DOUBLE_EQ(3.0, gdiFromWK.eDy);
+#endif
+
+#if PLATFORM(WIN)
+ D2D1_MATRIX_3X2_F d2dTransform = D2D1::Matrix3x2F(6.0, 5.0, 4.0, 3.0, 2.0, 1.0);
+ WebCore::TransformationMatrix fromD2DTransform(d2dTransform);
+
+ testAffineLikeConstruction(fromD2DTransform);
+
+ D2D1_MATRIX_3X2_F d2dFromWK = test;
+ EXPECT_DOUBLE_EQ(16.0, d2dFromWK._11);
+ EXPECT_DOUBLE_EQ(15.0, d2dFromWK._12);
+ EXPECT_DOUBLE_EQ(12.0, d2dFromWK._21);
+ EXPECT_DOUBLE_EQ(11.0, d2dFromWK._22);
+ EXPECT_DOUBLE_EQ(4.0, d2dFromWK._31);
+ EXPECT_DOUBLE_EQ(3.0, d2dFromWK._32);
+#endif
+}
+
+TEST(TransformationMatrix, MakeMapBetweenRects)
+{
+ WebCore::TransformationMatrix transform;
+
+ WebCore::FloatRect fromRect(10.0f, 10.0f, 100.0f, 100.0f);
+ WebCore::FloatRect toRect(70.0f, 70.0f, 200.0f, 50.0f);
+
+ auto mapBetween = WebCore::TransformationMatrix::rectToRect(fromRect, toRect);
+
+ EXPECT_DOUBLE_EQ(2.0, mapBetween.a());
+ EXPECT_DOUBLE_EQ(0.0, mapBetween.b());
+ EXPECT_DOUBLE_EQ(0.0, mapBetween.c());
+ EXPECT_DOUBLE_EQ(0.5, mapBetween.d());
+ EXPECT_DOUBLE_EQ(60.0, mapBetween.e());
+ EXPECT_DOUBLE_EQ(60.0, mapBetween.f());
+
+ EXPECT_DOUBLE_EQ(2.0, mapBetween.m11());
+ EXPECT_DOUBLE_EQ(0.0, mapBetween.m12());
+ EXPECT_DOUBLE_EQ(0.0, mapBetween.m13());
+ EXPECT_DOUBLE_EQ(0.0, mapBetween.m14());
+ EXPECT_DOUBLE_EQ(0.0, mapBetween.m21());
+ EXPECT_DOUBLE_EQ(0.5, mapBetween.m22());
+ EXPECT_DOUBLE_EQ(0.0, mapBetween.m23());
+ EXPECT_DOUBLE_EQ(0.0, mapBetween.m24());
+ EXPECT_DOUBLE_EQ(0.0, mapBetween.m31());
+ EXPECT_DOUBLE_EQ(0.0, mapBetween.m32());
+ EXPECT_DOUBLE_EQ(1.0, mapBetween.m33());
+ EXPECT_DOUBLE_EQ(0.0, mapBetween.m34());
+ EXPECT_DOUBLE_EQ(60.0, mapBetween.m41());
+ EXPECT_DOUBLE_EQ(60.0, mapBetween.m42());
+ EXPECT_DOUBLE_EQ(0.0, mapBetween.m43());
+ EXPECT_DOUBLE_EQ(1.0, mapBetween.m44());
+}
+
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/URL.cpp b/Tools/TestWebKitAPI/Tests/WebCore/URL.cpp
index 4a7f53977..30a7e301e 100644
--- a/Tools/TestWebKitAPI/Tests/WebCore/URL.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebCore/URL.cpp
@@ -26,6 +26,7 @@
#include "config.h"
#include "WTFStringUtilities.h"
#include <WebCore/URL.h>
+#include <WebCore/URLParser.h>
#include <wtf/MainThread.h>
using namespace WebCore;
@@ -57,10 +58,10 @@ TEST_F(URLTest, URLConstructorConstChar)
EXPECT_FALSE(kurl.isNull());
EXPECT_TRUE(kurl.isValid());
- EXPECT_EQ(String("http"), kurl.protocol());
+ EXPECT_EQ(kurl.protocol() == "http", true);
EXPECT_EQ(String("www.example.com"), kurl.host());
- EXPECT_TRUE(kurl.hasPort());
- EXPECT_EQ(8080, kurl.port());
+ EXPECT_TRUE(!!kurl.port());
+ EXPECT_EQ(8080, kurl.port().value());
EXPECT_EQ(String("username"), kurl.user());
EXPECT_EQ(String("password"), kurl.pass());
EXPECT_EQ(String("/index.html"), kurl.path());
@@ -70,6 +71,53 @@ TEST_F(URLTest, URLConstructorConstChar)
EXPECT_EQ(String("fragment"), kurl.fragmentIdentifier());
}
+TEST_F(URLTest, URLProtocolHostAndPort)
+{
+ auto createURL = [](const char* urlAsString) {
+ URLParser parser(urlAsString);
+ return parser.result();
+ };
+
+ auto url = createURL("http://username:password@www.example.com:8080/index.html?var=val#fragment");
+ EXPECT_EQ(String("http://www.example.com:8080"), url.protocolHostAndPort());
+
+ url = createURL("http://username:@www.example.com:8080/index.html?var=val#fragment");
+ EXPECT_EQ(String("http://www.example.com:8080"), url.protocolHostAndPort());
+
+ url = createURL("http://:password@www.example.com:8080/index.html?var=val#fragment");
+ EXPECT_EQ(String("http://www.example.com:8080"), url.protocolHostAndPort());
+
+ url = createURL("http://username@www.example.com:8080/index.html?var=val#fragment");
+ EXPECT_EQ(String("http://www.example.com:8080"), url.protocolHostAndPort());
+
+ url = createURL("http://www.example.com:8080/index.html?var=val#fragment");
+ EXPECT_EQ(String("http://www.example.com:8080"), url.protocolHostAndPort());
+
+ url = createURL("http://www.example.com:/index.html?var=val#fragment");
+ EXPECT_EQ(String("http://www.example.com"), url.protocolHostAndPort());
+
+ url = createURL("http://www.example.com/index.html?var=val#fragment");
+ EXPECT_EQ(String("http://www.example.com"), url.protocolHostAndPort());
+
+ url = createURL("file:///a/b/c");
+ EXPECT_EQ(String("file://"), url.protocolHostAndPort());
+
+ url = createURL("file:///a/b");
+ EXPECT_EQ(String("file://"), url.protocolHostAndPort());
+
+ url = createURL("file:///a");
+ EXPECT_EQ(String("file://"), url.protocolHostAndPort());
+
+ url = createURL("file:///a");
+ EXPECT_EQ(String("file://"), url.protocolHostAndPort());
+
+ url = createURL("asdf://username:password@www.example.com:8080/index.html?var=val#fragment");
+ EXPECT_EQ(String("asdf://www.example.com:8080"), url.protocolHostAndPort());
+
+ url = createURL("asdf:///a/b/c");
+ EXPECT_EQ(String("asdf://"), url.protocolHostAndPort());
+}
+
TEST_F(URLTest, URLDataURIStringSharing)
{
URL baseURL(ParsedURLString, "http://www.webkit.org/");
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp b/Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp
new file mode 100644
index 000000000..043e9c21d
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp
@@ -0,0 +1,1305 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WTFStringUtilities.h"
+#include <WebCore/URLParser.h>
+#include <wtf/MainThread.h>
+#include <wtf/text/StringBuilder.h>
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+class URLParserTest : public testing::Test {
+public:
+ void SetUp() final {
+ WTF::initializeMainThread();
+ }
+};
+
+struct ExpectedParts {
+ String protocol;
+ String user;
+ String password;
+ String host;
+ unsigned short port;
+ String path;
+ String query;
+ String fragment;
+ String string;
+
+ bool isInvalid() const
+ {
+ return protocol.isEmpty()
+ && user.isEmpty()
+ && password.isEmpty()
+ && host.isEmpty()
+ && !port
+ && path.isEmpty()
+ && query.isEmpty()
+ && fragment.isEmpty();
+ }
+};
+
+static bool eq(const String& s1, const String& s2)
+{
+ EXPECT_STREQ(s1.utf8().data(), s2.utf8().data());
+ return s1.utf8() == s2.utf8();
+}
+
+static String insertTabAtLocation(const String& string, size_t location)
+{
+ ASSERT(location <= string.length());
+ return makeString(string.substring(0, location), "\t", string.substring(location));
+}
+
+static ExpectedParts invalidParts(const String& urlStringWithTab)
+{
+ return {"", "", "", "", 0, "" , "", "", urlStringWithTab};
+}
+
+enum class TestTabs { No, Yes };
+
+// Inserting tabs between surrogate pairs changes the encoded value instead of being skipped by the URLParser.
+const TestTabs testTabsValueForSurrogatePairs = TestTabs::No;
+
+static void checkURL(const String& urlString, const ExpectedParts& parts, TestTabs testTabs = TestTabs::Yes)
+{
+ auto url = URL(URL(), urlString);
+
+ EXPECT_TRUE(eq(parts.protocol, url.protocol().toString()));
+ EXPECT_TRUE(eq(parts.user, url.user()));
+ EXPECT_TRUE(eq(parts.password, url.pass()));
+ EXPECT_TRUE(eq(parts.host, url.host()));
+ EXPECT_EQ(parts.port, url.port().value_or(0));
+ EXPECT_TRUE(eq(parts.path, url.path()));
+ EXPECT_TRUE(eq(parts.query, url.query()));
+ EXPECT_TRUE(eq(parts.fragment, url.fragmentIdentifier()));
+ EXPECT_TRUE(eq(parts.string, url.string()));
+
+ EXPECT_TRUE(URLParser::internalValuesConsistent(url));
+
+ if (testTabs == TestTabs::No)
+ return;
+
+ for (size_t i = 0; i < urlString.length(); ++i) {
+ String urlStringWithTab = insertTabAtLocation(urlString, i);
+ checkURL(urlStringWithTab,
+ parts.isInvalid() ? invalidParts(urlStringWithTab) : parts,
+ TestTabs::No);
+ }
+}
+
+static void checkRelativeURL(const String& urlString, const String& baseURLString, const ExpectedParts& parts, TestTabs testTabs = TestTabs::Yes)
+{
+ auto url = URL(URL(URL(), baseURLString), urlString);
+
+ EXPECT_TRUE(eq(parts.protocol, url.protocol().toString()));
+ EXPECT_TRUE(eq(parts.user, url.user()));
+ EXPECT_TRUE(eq(parts.password, url.pass()));
+ EXPECT_TRUE(eq(parts.host, url.host()));
+ EXPECT_EQ(parts.port, url.port().value_or(0));
+ EXPECT_TRUE(eq(parts.path, url.path()));
+ EXPECT_TRUE(eq(parts.query, url.query()));
+ EXPECT_TRUE(eq(parts.fragment, url.fragmentIdentifier()));
+ EXPECT_TRUE(eq(parts.string, url.string()));
+
+ EXPECT_TRUE(URLParser::internalValuesConsistent(url));
+
+ if (testTabs == TestTabs::No)
+ return;
+
+ for (size_t i = 0; i < urlString.length(); ++i) {
+ String urlStringWithTab = insertTabAtLocation(urlString, i);
+ checkRelativeURL(urlStringWithTab,
+ baseURLString,
+ parts.isInvalid() ? invalidParts(urlStringWithTab) : parts,
+ TestTabs::No);
+ }
+}
+
+static void checkURLDifferences(const String& urlString, const ExpectedParts& partsNew, const ExpectedParts& partsOld, TestTabs testTabs = TestTabs::Yes)
+{
+ UNUSED_PARAM(partsOld); // FIXME: Remove all the old expected parts.
+ auto url = URL(URL(), urlString);
+
+ EXPECT_TRUE(eq(partsNew.protocol, url.protocol().toString()));
+ EXPECT_TRUE(eq(partsNew.user, url.user()));
+ EXPECT_TRUE(eq(partsNew.password, url.pass()));
+ EXPECT_TRUE(eq(partsNew.host, url.host()));
+ EXPECT_EQ(partsNew.port, url.port().value_or(0));
+ EXPECT_TRUE(eq(partsNew.path, url.path()));
+ EXPECT_TRUE(eq(partsNew.query, url.query()));
+ EXPECT_TRUE(eq(partsNew.fragment, url.fragmentIdentifier()));
+ EXPECT_TRUE(eq(partsNew.string, url.string()));
+
+ EXPECT_TRUE(URLParser::internalValuesConsistent(url));
+
+ if (testTabs == TestTabs::No)
+ return;
+
+ for (size_t i = 0; i < urlString.length(); ++i) {
+ String urlStringWithTab = insertTabAtLocation(urlString, i);
+ checkURLDifferences(urlStringWithTab,
+ partsNew.isInvalid() ? invalidParts(urlStringWithTab) : partsNew,
+ partsOld.isInvalid() ? invalidParts(urlStringWithTab) : partsOld,
+ TestTabs::No);
+ }
+}
+
+static void checkRelativeURLDifferences(const String& urlString, const String& baseURLString, const ExpectedParts& partsNew, const ExpectedParts& partsOld, TestTabs testTabs = TestTabs::Yes)
+{
+ UNUSED_PARAM(partsOld); // FIXME: Remove all the old expected parts.
+ auto url = URL(URL(URL(), baseURLString), urlString);
+
+ EXPECT_TRUE(eq(partsNew.protocol, url.protocol().toString()));
+ EXPECT_TRUE(eq(partsNew.user, url.user()));
+ EXPECT_TRUE(eq(partsNew.password, url.pass()));
+ EXPECT_TRUE(eq(partsNew.host, url.host()));
+ EXPECT_EQ(partsNew.port, url.port().value_or(0));
+ EXPECT_TRUE(eq(partsNew.path, url.path()));
+ EXPECT_TRUE(eq(partsNew.query, url.query()));
+ EXPECT_TRUE(eq(partsNew.fragment, url.fragmentIdentifier()));
+ EXPECT_TRUE(eq(partsNew.string, url.string()));
+
+ EXPECT_TRUE(URLParser::internalValuesConsistent(url));
+
+ if (testTabs == TestTabs::No)
+ return;
+
+ for (size_t i = 0; i < urlString.length(); ++i) {
+ String urlStringWithTab = insertTabAtLocation(urlString, i);
+ checkRelativeURLDifferences(urlStringWithTab, baseURLString,
+ partsNew.isInvalid() ? invalidParts(urlStringWithTab) : partsNew,
+ partsOld.isInvalid() ? invalidParts(urlStringWithTab) : partsOld,
+ TestTabs::No);
+ }
+}
+
+static void shouldFail(const String& urlString)
+{
+ checkURL(urlString, {"", "", "", "", 0, "", "", "", urlString});
+}
+
+static void shouldFail(const String& urlString, const String& baseString)
+{
+ checkRelativeURL(urlString, baseString, {"", "", "", "", 0, "", "", "", urlString});
+}
+
+static void checkURL(const String& urlString, const TextEncoding& encoding, const ExpectedParts& parts, TestTabs testTabs = TestTabs::Yes)
+{
+ URLParser parser(urlString, { }, encoding);
+ auto url = parser.result();
+ EXPECT_TRUE(eq(parts.protocol, url.protocol().toString()));
+ EXPECT_TRUE(eq(parts.user, url.user()));
+ EXPECT_TRUE(eq(parts.password, url.pass()));
+ EXPECT_TRUE(eq(parts.host, url.host()));
+ EXPECT_EQ(parts.port, url.port().value_or(0));
+ EXPECT_TRUE(eq(parts.path, url.path()));
+ EXPECT_TRUE(eq(parts.query, url.query()));
+ EXPECT_TRUE(eq(parts.fragment, url.fragmentIdentifier()));
+ EXPECT_TRUE(eq(parts.string, url.string()));
+
+ if (testTabs == TestTabs::No)
+ return;
+
+ for (size_t i = 0; i < urlString.length(); ++i) {
+ String urlStringWithTab = insertTabAtLocation(urlString, i);
+ checkURL(urlStringWithTab, encoding,
+ parts.isInvalid() ? invalidParts(urlStringWithTab) : parts,
+ TestTabs::No);
+ }
+}
+
+static void checkURL(const String& urlString, const String& baseURLString, const TextEncoding& encoding, const ExpectedParts& parts, TestTabs testTabs = TestTabs::Yes)
+{
+ URLParser baseParser(baseURLString, { }, encoding);
+ URLParser parser(urlString, baseParser.result(), encoding);
+ auto url = parser.result();
+ EXPECT_TRUE(eq(parts.protocol, url.protocol().toString()));
+ EXPECT_TRUE(eq(parts.user, url.user()));
+ EXPECT_TRUE(eq(parts.password, url.pass()));
+ EXPECT_TRUE(eq(parts.host, url.host()));
+ EXPECT_EQ(parts.port, url.port().value_or(0));
+ EXPECT_TRUE(eq(parts.path, url.path()));
+ EXPECT_TRUE(eq(parts.query, url.query()));
+ EXPECT_TRUE(eq(parts.fragment, url.fragmentIdentifier()));
+ EXPECT_TRUE(eq(parts.string, url.string()));
+
+ if (testTabs == TestTabs::No)
+ return;
+
+ for (size_t i = 0; i < urlString.length(); ++i) {
+ String urlStringWithTab = insertTabAtLocation(urlString, i);
+ checkURL(urlStringWithTab, baseURLString, encoding,
+ parts.isInvalid() ? invalidParts(urlStringWithTab) : parts,
+ TestTabs::No);
+ }
+}
+
+TEST_F(URLParserTest, Basic)
+{
+ checkURL("http://user:pass@webkit.org:123/path?query#fragment", {"http", "user", "pass", "webkit.org", 123, "/path", "query", "fragment", "http://user:pass@webkit.org:123/path?query#fragment"});
+ checkURL("http://user:pass@webkit.org:123/path?query", {"http", "user", "pass", "webkit.org", 123, "/path", "query", "", "http://user:pass@webkit.org:123/path?query"});
+ checkURL("http://user:pass@webkit.org:123/path", {"http", "user", "pass", "webkit.org", 123, "/path", "", "", "http://user:pass@webkit.org:123/path"});
+ checkURL("http://user:pass@webkit.org:123/", {"http", "user", "pass", "webkit.org", 123, "/", "", "", "http://user:pass@webkit.org:123/"});
+ checkURL("http://user:pass@webkit.org:123", {"http", "user", "pass", "webkit.org", 123, "/", "", "", "http://user:pass@webkit.org:123/"});
+ checkURL("http://user:pass@webkit.org", {"http", "user", "pass", "webkit.org", 0, "/", "", "", "http://user:pass@webkit.org/"});
+ checkURL("http://user:\t\t\tpass@webkit.org", {"http", "user", "pass", "webkit.org", 0, "/", "", "", "http://user:pass@webkit.org/"});
+ checkURL("http://us\ter:pass@webkit.org", {"http", "user", "pass", "webkit.org", 0, "/", "", "", "http://user:pass@webkit.org/"});
+ checkURL("http://user:pa\tss@webkit.org", {"http", "user", "pass", "webkit.org", 0, "/", "", "", "http://user:pass@webkit.org/"});
+ checkURL("http://user:pass\t@webkit.org", {"http", "user", "pass", "webkit.org", 0, "/", "", "", "http://user:pass@webkit.org/"});
+ checkURL("http://\tuser:pass@webkit.org", {"http", "user", "pass", "webkit.org", 0, "/", "", "", "http://user:pass@webkit.org/"});
+ checkURL("http://user\t:pass@webkit.org", {"http", "user", "pass", "webkit.org", 0, "/", "", "", "http://user:pass@webkit.org/"});
+ checkURL("http://webkit.org", {"http", "", "", "webkit.org", 0, "/", "", "", "http://webkit.org/"});
+ checkURL("http://127.0.0.1", {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"});
+ checkURL("http://webkit.org/", {"http", "", "", "webkit.org", 0, "/", "", "", "http://webkit.org/"});
+ checkURL("http://webkit.org/path1/path2/index.html", {"http", "", "", "webkit.org", 0, "/path1/path2/index.html", "", "", "http://webkit.org/path1/path2/index.html"});
+ checkURL("about:blank", {"about", "", "", "", 0, "blank", "", "", "about:blank"});
+ checkURL("about:blank?query", {"about", "", "", "", 0, "blank", "query", "", "about:blank?query"});
+ checkURL("about:blank#fragment", {"about", "", "", "", 0, "blank", "", "fragment", "about:blank#fragment"});
+ checkURL("http://[0:f::f:f:0:0]", {"http", "", "", "[0:f::f:f:0:0]", 0, "/", "", "", "http://[0:f::f:f:0:0]/"});
+ checkURL("http://[0:f:0:0:f::]", {"http", "", "", "[0:f:0:0:f::]", 0, "/", "", "", "http://[0:f:0:0:f::]/"});
+ checkURL("http://[::f:0:0:f:0:0]", {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"});
+ checkURL("http://[0:f:0:0:f::]:", {"http", "", "", "[0:f:0:0:f::]", 0, "/", "", "", "http://[0:f:0:0:f::]/"});
+ checkURL("http://[0:f:0:0:f::]:\t", {"http", "", "", "[0:f:0:0:f::]", 0, "/", "", "", "http://[0:f:0:0:f::]/"});
+ checkURL("http://[0:f:0:0:f::]\t:", {"http", "", "", "[0:f:0:0:f::]", 0, "/", "", "", "http://[0:f:0:0:f::]/"});
+ checkURL("http://\t[::f:0:0:f:0:0]", {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"});
+ checkURL("http://[\t::f:0:0:f:0:0]", {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"});
+ checkURL("http://[:\t:f:0:0:f:0:0]", {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"});
+ checkURL("http://[::\tf:0:0:f:0:0]", {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"});
+ checkURL("http://[::f\t:0:0:f:0:0]", {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"});
+ checkURL("http://[::f:\t0:0:f:0:0]", {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"});
+ checkURL("http://example.com/path1/path2/.", {"http", "", "", "example.com", 0, "/path1/path2/", "", "", "http://example.com/path1/path2/"});
+ checkURL("http://example.com/path1/path2/..", {"http", "", "", "example.com", 0, "/path1/", "", "", "http://example.com/path1/"});
+ checkURL("http://example.com/path1/path2/./path3", {"http", "", "", "example.com", 0, "/path1/path2/path3", "", "", "http://example.com/path1/path2/path3"});
+ checkURL("http://example.com/path1/path2/.\\path3", {"http", "", "", "example.com", 0, "/path1/path2/path3", "", "", "http://example.com/path1/path2/path3"});
+ checkURL("http://example.com/path1/path2/../path3", {"http", "", "", "example.com", 0, "/path1/path3", "", "", "http://example.com/path1/path3"});
+ checkURL("http://example.com/path1/path2/..\\path3", {"http", "", "", "example.com", 0, "/path1/path3", "", "", "http://example.com/path1/path3"});
+ checkURL("http://example.com/.", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
+ checkURL("http://example.com/..", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
+ checkURL("http://example.com/./path1", {"http", "", "", "example.com", 0, "/path1", "", "", "http://example.com/path1"});
+ checkURL("http://example.com/../path1", {"http", "", "", "example.com", 0, "/path1", "", "", "http://example.com/path1"});
+ checkURL("http://example.com/../path1/../../path2/path3/../path4", {"http", "", "", "example.com", 0, "/path2/path4", "", "", "http://example.com/path2/path4"});
+ checkURL("http://example.com/path1/.%2", {"http", "", "", "example.com", 0, "/path1/.%2", "", "", "http://example.com/path1/.%2"});
+ checkURL("http://example.com/path1/%2", {"http", "", "", "example.com", 0, "/path1/%2", "", "", "http://example.com/path1/%2"});
+ checkURL("http://example.com/path1/%", {"http", "", "", "example.com", 0, "/path1/%", "", "", "http://example.com/path1/%"});
+ checkURL("http://example.com/path1/.%", {"http", "", "", "example.com", 0, "/path1/.%", "", "", "http://example.com/path1/.%"});
+ checkURL("http://example.com//.", {"http", "", "", "example.com", 0, "//", "", "", "http://example.com//"});
+ checkURL("http://example.com//./", {"http", "", "", "example.com", 0, "//", "", "", "http://example.com//"});
+ checkURL("http://example.com//.//", {"http", "", "", "example.com", 0, "///", "", "", "http://example.com///"});
+ checkURL("http://example.com//..", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
+ checkURL("http://example.com//../", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
+ checkURL("http://example.com//..//", {"http", "", "", "example.com", 0, "//", "", "", "http://example.com//"});
+ checkURL("http://example.com//..", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
+ checkURL("http://example.com/.//", {"http", "", "", "example.com", 0, "//", "", "", "http://example.com//"});
+ checkURL("http://example.com/..//", {"http", "", "", "example.com", 0, "//", "", "", "http://example.com//"});
+ checkURL("http://example.com/./", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
+ checkURL("http://example.com/../", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
+ checkURL("http://example.com/path1/.../path3", {"http", "", "", "example.com", 0, "/path1/.../path3", "", "", "http://example.com/path1/.../path3"});
+ checkURL("http://example.com/path1/...", {"http", "", "", "example.com", 0, "/path1/...", "", "", "http://example.com/path1/..."});
+ checkURL("http://example.com/path1/.../", {"http", "", "", "example.com", 0, "/path1/.../", "", "", "http://example.com/path1/.../"});
+ checkURL("http://example.com/.path1/", {"http", "", "", "example.com", 0, "/.path1/", "", "", "http://example.com/.path1/"});
+ checkURL("http://example.com/..path1/", {"http", "", "", "example.com", 0, "/..path1/", "", "", "http://example.com/..path1/"});
+ checkURL("http://example.com/path1/.path2", {"http", "", "", "example.com", 0, "/path1/.path2", "", "", "http://example.com/path1/.path2"});
+ checkURL("http://example.com/path1/..path2", {"http", "", "", "example.com", 0, "/path1/..path2", "", "", "http://example.com/path1/..path2"});
+ checkURL("http://example.com/path1/path2/.?query", {"http", "", "", "example.com", 0, "/path1/path2/", "query", "", "http://example.com/path1/path2/?query"});
+ checkURL("http://example.com/path1/path2/..?query", {"http", "", "", "example.com", 0, "/path1/", "query", "", "http://example.com/path1/?query"});
+ checkURL("http://example.com/path1/path2/.#fragment", {"http", "", "", "example.com", 0, "/path1/path2/", "", "fragment", "http://example.com/path1/path2/#fragment"});
+ checkURL("http://example.com/path1/path2/..#fragment", {"http", "", "", "example.com", 0, "/path1/", "", "fragment", "http://example.com/path1/#fragment"});
+
+ checkURL("file:", {"file", "", "", "", 0, "/", "", "", "file:///"});
+ checkURL("file:/", {"file", "", "", "", 0, "/", "", "", "file:///"});
+ checkURL("file://", {"file", "", "", "", 0, "/", "", "", "file:///"});
+ checkURL("file:///", {"file", "", "", "", 0, "/", "", "", "file:///"});
+ checkURL("file:////", {"file", "", "", "", 0, "//", "", "", "file:////"}); // This matches Firefox and URL::parse which I believe are correct, but not Chrome.
+ checkURL("file:/path", {"file", "", "", "", 0, "/path", "", "", "file:///path"});
+ checkURL("file://host/path", {"file", "", "", "host", 0, "/path", "", "", "file://host/path"});
+ checkURL("file://host", {"file", "", "", "host", 0, "/", "", "", "file://host/"});
+ checkURL("file://host/", {"file", "", "", "host", 0, "/", "", "", "file://host/"});
+ checkURL("file:///path", {"file", "", "", "", 0, "/path", "", "", "file:///path"});
+ checkURL("file:////path", {"file", "", "", "", 0, "//path", "", "", "file:////path"});
+ checkURL("file://localhost/path", {"file", "", "", "", 0, "/path", "", "", "file:///path"});
+ checkURL("file://localhost/", {"file", "", "", "", 0, "/", "", "", "file:///"});
+ checkURL("file://localhost", {"file", "", "", "", 0, "/", "", "", "file:///"});
+ checkURL("file://lOcAlHoSt", {"file", "", "", "", 0, "/", "", "", "file:///"});
+ checkURL("file://lOcAlHoSt/", {"file", "", "", "", 0, "/", "", "", "file:///"});
+ checkURL("file:/pAtH/", {"file", "", "", "", 0, "/pAtH/", "", "", "file:///pAtH/"});
+ checkURL("file:/pAtH", {"file", "", "", "", 0, "/pAtH", "", "", "file:///pAtH"});
+ checkURL("file:?query", {"file", "", "", "", 0, "/", "query", "", "file:///?query"});
+ checkURL("file:#fragment", {"file", "", "", "", 0, "/", "", "fragment", "file:///#fragment"});
+ checkURL("file:?query#fragment", {"file", "", "", "", 0, "/", "query", "fragment", "file:///?query#fragment"});
+ checkURL("file:#fragment?notquery", {"file", "", "", "", 0, "/", "", "fragment?notquery", "file:///#fragment?notquery"});
+ checkURL("file:/?query", {"file", "", "", "", 0, "/", "query", "", "file:///?query"});
+ checkURL("file:/#fragment", {"file", "", "", "", 0, "/", "", "fragment", "file:///#fragment"});
+ checkURL("file://?query", {"file", "", "", "", 0, "/", "query", "", "file:///?query"});
+ checkURL("file://#fragment", {"file", "", "", "", 0, "/", "", "fragment", "file:///#fragment"});
+ checkURL("file:///?query", {"file", "", "", "", 0, "/", "query", "", "file:///?query"});
+ checkURL("file:///#fragment", {"file", "", "", "", 0, "/", "", "fragment", "file:///#fragment"});
+ checkURL("file:////?query", {"file", "", "", "", 0, "//", "query", "", "file:////?query"});
+ checkURL("file:////#fragment", {"file", "", "", "", 0, "//", "", "fragment", "file:////#fragment"});
+ checkURL("http://host/A b", {"http", "", "", "host", 0, "/A%20b", "", "", "http://host/A%20b"});
+ checkURL("http://host/a%20B", {"http", "", "", "host", 0, "/a%20B", "", "", "http://host/a%20B"});
+ checkURL("http://host?q=@ <>!#fragment", {"http", "", "", "host", 0, "/", "q=@%20%3C%3E!", "fragment", "http://host/?q=@%20%3C%3E!#fragment"});
+ checkURL("http://user:@host", {"http", "user", "", "host", 0, "/", "", "", "http://user@host/"});
+ checkURL("http://user:@\thost", {"http", "user", "", "host", 0, "/", "", "", "http://user@host/"});
+ checkURL("http://user:\t@host", {"http", "user", "", "host", 0, "/", "", "", "http://user@host/"});
+ checkURL("http://user\t:@host", {"http", "user", "", "host", 0, "/", "", "", "http://user@host/"});
+ checkURL("http://use\tr:@host", {"http", "user", "", "host", 0, "/", "", "", "http://user@host/"});
+ checkURL("http://127.0.0.1:10100/path", {"http", "", "", "127.0.0.1", 10100, "/path", "", "", "http://127.0.0.1:10100/path"});
+ checkURL("http://127.0.0.1:/path", {"http", "", "", "127.0.0.1", 0, "/path", "", "", "http://127.0.0.1/path"});
+ checkURL("http://127.0.0.1\t:/path", {"http", "", "", "127.0.0.1", 0, "/path", "", "", "http://127.0.0.1/path"});
+ checkURL("http://127.0.0.1:\t/path", {"http", "", "", "127.0.0.1", 0, "/path", "", "", "http://127.0.0.1/path"});
+ checkURL("http://127.0.0.1:/\tpath", {"http", "", "", "127.0.0.1", 0, "/path", "", "", "http://127.0.0.1/path"});
+ checkURL("http://127.0.0.1:123", {"http", "", "", "127.0.0.1", 123, "/", "", "", "http://127.0.0.1:123/"});
+ checkURL("http://127.0.0.1:", {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"});
+ checkURL("http://[0:f::f:f:0:0]:123/path", {"http", "", "", "[0:f::f:f:0:0]", 123, "/path", "", "", "http://[0:f::f:f:0:0]:123/path"});
+ checkURL("http://[0:f::f:f:0:0]:123", {"http", "", "", "[0:f::f:f:0:0]", 123, "/", "", "", "http://[0:f::f:f:0:0]:123/"});
+ checkURL("http://[0:f:0:0:f:\t:]:123", {"http", "", "", "[0:f:0:0:f::]", 123, "/", "", "", "http://[0:f:0:0:f::]:123/"});
+ checkURL("http://[0:f:0:0:f::\t]:123", {"http", "", "", "[0:f:0:0:f::]", 123, "/", "", "", "http://[0:f:0:0:f::]:123/"});
+ checkURL("http://[0:f:0:0:f::]\t:123", {"http", "", "", "[0:f:0:0:f::]", 123, "/", "", "", "http://[0:f:0:0:f::]:123/"});
+ checkURL("http://[0:f:0:0:f::]:\t123", {"http", "", "", "[0:f:0:0:f::]", 123, "/", "", "", "http://[0:f:0:0:f::]:123/"});
+ checkURL("http://[0:f:0:0:f::]:1\t23", {"http", "", "", "[0:f:0:0:f::]", 123, "/", "", "", "http://[0:f:0:0:f::]:123/"});
+ checkURL("http://[0:f::f:f:0:0]:/path", {"http", "", "", "[0:f::f:f:0:0]", 0, "/path", "", "", "http://[0:f::f:f:0:0]/path"});
+ checkURL("http://[0:f::f:f:0:0]:", {"http", "", "", "[0:f::f:f:0:0]", 0, "/", "", "", "http://[0:f::f:f:0:0]/"});
+ checkURL("http://host:10100/path", {"http", "", "", "host", 10100, "/path", "", "", "http://host:10100/path"});
+ checkURL("http://host:/path", {"http", "", "", "host", 0, "/path", "", "", "http://host/path"});
+ checkURL("http://host:123", {"http", "", "", "host", 123, "/", "", "", "http://host:123/"});
+ checkURL("http://host:", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
+ checkURL("http://hos\tt\n:\t1\n2\t3\t/\npath", {"http", "", "", "host", 123, "/path", "", "", "http://host:123/path"});
+ checkURL("http://user@example.org/path3", {"http", "user", "", "example.org", 0, "/path3", "", "", "http://user@example.org/path3"});
+ checkURL("sc:/pa/pa", {"sc", "", "", "", 0, "/pa/pa", "", "", "sc:/pa/pa"});
+ checkURL("sc:/pa", {"sc", "", "", "", 0, "/pa", "", "", "sc:/pa"});
+ checkURL("sc:/pa/", {"sc", "", "", "", 0, "/pa/", "", "", "sc:/pa/"});
+ checkURL("notspecial:/notuser:notpassword@nothost", {"notspecial", "", "", "", 0, "/notuser:notpassword@nothost", "", "", "notspecial:/notuser:notpassword@nothost"});
+ checkURL("sc://pa/", {"sc", "", "", "pa", 0, "/", "", "", "sc://pa/"});
+ checkURL("sc://\tpa/", {"sc", "", "", "pa", 0, "/", "", "", "sc://pa/"});
+ checkURL("sc:/\t/pa/", {"sc", "", "", "pa", 0, "/", "", "", "sc://pa/"});
+ checkURL("sc:\t//pa/", {"sc", "", "", "pa", 0, "/", "", "", "sc://pa/"});
+ checkURL("http://host \a ", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
+ checkURL("notspecial:/a", {"notspecial", "", "", "", 0, "/a", "", "", "notspecial:/a"});
+ checkURL("notspecial:", {"notspecial", "", "", "", 0, "", "", "", "notspecial:"});
+ checkURL("http:/a", {"http", "", "", "a", 0, "/", "", "", "http://a/"});
+ checkURL("http://256../", {"http", "", "", "256..", 0, "/", "", "", "http://256../"});
+ checkURL("http://256..", {"http", "", "", "256..", 0, "/", "", "", "http://256../"});
+ checkURL("http://127..1/", {"http", "", "", "127..1", 0, "/", "", "", "http://127..1/"});
+ checkURL("http://127.a.0.1/", {"http", "", "", "127.a.0.1", 0, "/", "", "", "http://127.a.0.1/"});
+ checkURL("http://127.0.0.1/", {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"});
+ checkURL("http://12\t7.0.0.1/", {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"});
+ checkURL("http://127.\t0.0.1/", {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"});
+ checkURL("http://./", {"http", "", "", ".", 0, "/", "", "", "http://./"});
+ checkURL("http://.", {"http", "", "", ".", 0, "/", "", "", "http://./"});
+ checkURL("notspecial:/a", {"notspecial", "", "", "", 0, "/a", "", "", "notspecial:/a"});
+ checkURL("notspecial:", {"notspecial", "", "", "", 0, "", "", "", "notspecial:"});
+ checkURL("notspecial:/", {"notspecial", "", "", "", 0, "/", "", "", "notspecial:/"});
+ checkURL("data:image/png;base64,encoded-data-follows-here", {"data", "", "", "", 0, "image/png;base64,encoded-data-follows-here", "", "", "data:image/png;base64,encoded-data-follows-here"});
+ checkURL("data:image/png;base64,encoded/data-with-slash", {"data", "", "", "", 0, "image/png;base64,encoded/data-with-slash", "", "", "data:image/png;base64,encoded/data-with-slash"});
+ checkURL("about:~", {"about", "", "", "", 0, "~", "", "", "about:~"});
+ checkURL("https://@test@test@example:800\\path@end", {"", "", "", "", 0, "", "", "", "https://@test@test@example:800\\path@end"});
+ checkURL("http://www.example.com/#a\nb\rc\td", {"http", "", "", "www.example.com", 0, "/", "", "abcd", "http://www.example.com/#abcd"});
+ checkURL("http://[A:b:c:DE:fF:0:1:aC]/", {"http", "", "", "[a:b:c:de:ff:0:1:ac]", 0, "/", "", "", "http://[a:b:c:de:ff:0:1:ac]/"});
+ checkURL("http:////////user:@webkit.org:99?foo", {"http", "user", "", "webkit.org", 99, "/", "foo", "", "http://user@webkit.org:99/?foo"});
+ checkURL("http:////////user:@webkit.org:99#foo", {"http", "user", "", "webkit.org", 99, "/", "", "foo", "http://user@webkit.org:99/#foo"});
+ checkURL("http:////\t////user:@webkit.org:99?foo", {"http", "user", "", "webkit.org", 99, "/", "foo", "", "http://user@webkit.org:99/?foo"});
+ checkURL("http://\t//\\///user:@webkit.org:99?foo", {"http", "user", "", "webkit.org", 99, "/", "foo", "", "http://user@webkit.org:99/?foo"});
+ checkURL("http:/\\user:@webkit.org:99?foo", {"http", "user", "", "webkit.org", 99, "/", "foo", "", "http://user@webkit.org:99/?foo"});
+ checkURL("http://127.0.0.1", {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"});
+ checkURLDifferences("http://127.0.0.1.",
+ {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"},
+ {"http", "", "", "127.0.0.1.", 0, "/", "", "", "http://127.0.0.1./"});
+ checkURLDifferences("http://127.0.0.1./",
+ {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"},
+ {"http", "", "", "127.0.0.1.", 0, "/", "", "", "http://127.0.0.1./"});
+ checkURL("http://127.0.0.1../", {"http", "", "", "127.0.0.1..", 0, "/", "", "", "http://127.0.0.1../"});
+ checkURLDifferences("http://0x100.0/",
+ {"", "", "", "", 0, "", "", "", "http://0x100.0/"},
+ {"http", "", "", "0x100.0", 0, "/", "", "", "http://0x100.0/"});
+ checkURLDifferences("http://0.0.0x100.0/",
+ {"", "", "", "", 0, "", "", "", "http://0.0.0x100.0/"},
+ {"http", "", "", "0.0.0x100.0", 0, "/", "", "", "http://0.0.0x100.0/"});
+ checkURLDifferences("http://0.0.0.0x100/",
+ {"", "", "", "", 0, "", "", "", "http://0.0.0.0x100/"},
+ {"http", "", "", "0.0.0.0x100", 0, "/", "", "", "http://0.0.0.0x100/"});
+ checkURL("http://host:123?", {"http", "", "", "host", 123, "/", "", "", "http://host:123/?"});
+ checkURL("http://host:123?query", {"http", "", "", "host", 123, "/", "query", "", "http://host:123/?query"});
+ checkURL("http://host:123#", {"http", "", "", "host", 123, "/", "", "", "http://host:123/#"});
+ checkURL("http://host:123#fragment", {"http", "", "", "host", 123, "/", "", "fragment", "http://host:123/#fragment"});
+ checkURLDifferences("foo:////",
+ {"foo", "", "", "", 0, "//", "", "", "foo:////"},
+ {"foo", "", "", "", 0, "////", "", "", "foo:////"});
+ checkURLDifferences("foo:///?",
+ {"foo", "", "", "", 0, "/", "", "", "foo:///?"},
+ {"foo", "", "", "", 0, "///", "", "", "foo:///?"});
+ checkURLDifferences("foo:///#",
+ {"foo", "", "", "", 0, "/", "", "", "foo:///#"},
+ {"foo", "", "", "", 0, "///", "", "", "foo:///#"});
+ checkURLDifferences("foo:///",
+ {"foo", "", "", "", 0, "/", "", "", "foo:///"},
+ {"foo", "", "", "", 0, "///", "", "", "foo:///"});
+ checkURLDifferences("foo://?",
+ {"foo", "", "", "", 0, "", "", "", "foo://?"},
+ {"foo", "", "", "", 0, "//", "", "", "foo://?"});
+ checkURLDifferences("foo://#",
+ {"foo", "", "", "", 0, "", "", "", "foo://#"},
+ {"foo", "", "", "", 0, "//", "", "", "foo://#"});
+ checkURLDifferences("foo://",
+ {"foo", "", "", "", 0, "", "", "", "foo://"},
+ {"foo", "", "", "", 0, "//", "", "", "foo://"});
+ checkURL("foo:/?", {"foo", "", "", "", 0, "/", "", "", "foo:/?"});
+ checkURL("foo:/#", {"foo", "", "", "", 0, "/", "", "", "foo:/#"});
+ checkURL("foo:/", {"foo", "", "", "", 0, "/", "", "", "foo:/"});
+ checkURL("foo:?", {"foo", "", "", "", 0, "", "", "", "foo:?"});
+ checkURL("foo:#", {"foo", "", "", "", 0, "", "", "", "foo:#"});
+ checkURLDifferences("A://",
+ {"a", "", "", "", 0, "", "", "", "a://"},
+ {"a", "", "", "", 0, "//", "", "", "a://"});
+ checkURLDifferences("aA://",
+ {"aa", "", "", "", 0, "", "", "", "aa://"},
+ {"aa", "", "", "", 0, "//", "", "", "aa://"});
+ checkURL(utf16String(u"foo://host/#ПП\u0007 a</"), {"foo", "", "", "host", 0, "/", "", "%D0%9F%D0%9F%07 a</", "foo://host/#%D0%9F%D0%9F%07 a</"});
+ checkURL(utf16String(u"foo://host/#\u0007 a</"), {"foo", "", "", "host", 0, "/", "", "%07 a</", "foo://host/#%07 a</"});
+ checkURL(utf16String(u"http://host?ß😍#ß😍"), {"http", "", "", "host", 0, "/", "%C3%9F%F0%9F%98%8D", "%C3%9F%F0%9F%98%8D", "http://host/?%C3%9F%F0%9F%98%8D#%C3%9F%F0%9F%98%8D"}, testTabsValueForSurrogatePairs);
+ checkURL(utf16String(u"http://host/path#💩\t💩"), {"http", "", "", "host", 0, "/path", "", "%F0%9F%92%A9%F0%9F%92%A9", "http://host/path#%F0%9F%92%A9%F0%9F%92%A9"}, testTabsValueForSurrogatePairs);
+ checkURL(utf16String(u"http://host/#ПП\u0007 a</"), {"http", "", "", "host", 0, "/", "", "%D0%9F%D0%9F%07 a</", "http://host/#%D0%9F%D0%9F%07 a</"});
+ checkURL(utf16String(u"http://host/#\u0007 a</"), {"http", "", "", "host", 0, "/", "", "%07 a</", "http://host/#%07 a</"});
+
+ // This disagrees with the web platform test for http://:@www.example.com but agrees with Chrome and URL::parse,
+ // and Firefox fails the web platform test differently. Maybe the web platform test ought to be changed.
+ checkURL("http://:@host", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
+}
+
+TEST_F(URLParserTest, ParseRelative)
+{
+ checkRelativeURL("/index.html", "http://webkit.org/path1/path2/", {"http", "", "", "webkit.org", 0, "/index.html", "", "", "http://webkit.org/index.html"});
+ checkRelativeURL("http://whatwg.org/index.html", "http://webkit.org/path1/path2/", {"http", "", "", "whatwg.org", 0, "/index.html", "", "", "http://whatwg.org/index.html"});
+ checkRelativeURL("index.html", "http://webkit.org/path1/path2/page.html?query#fragment", {"http", "", "", "webkit.org", 0, "/path1/path2/index.html", "", "", "http://webkit.org/path1/path2/index.html"});
+ checkRelativeURL("//whatwg.org/index.html", "https://www.webkit.org/path", {"https", "", "", "whatwg.org", 0, "/index.html", "", "", "https://whatwg.org/index.html"});
+ checkRelativeURL("http://example\t.\norg", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/", "", "", "http://example.org/"});
+ checkRelativeURL("test", "file:///path1/path2", {"file", "", "", "", 0, "/path1/test", "", "", "file:///path1/test"});
+ checkRelativeURL(utf16String(u"http://www.foo。bar.com"), "http://other.com/", {"http", "", "", "www.foo.bar.com", 0, "/", "", "", "http://www.foo.bar.com/"});
+ checkRelativeURLDifferences(utf16String(u"sc://ñ.test/"), "about:blank",
+ {"sc", "", "", "%C3%B1.test", 0, "/", "", "", "sc://%C3%B1.test/"},
+ {"sc", "", "", "xn--ida.test", 0, "/", "", "", "sc://xn--ida.test/"});
+ checkRelativeURL("#fragment", "http://host/path", {"http", "", "", "host", 0, "/path", "", "fragment", "http://host/path#fragment"});
+ checkRelativeURL("#fragment", "file:///path", {"file", "", "", "", 0, "/path", "", "fragment", "file:///path#fragment"});
+ checkRelativeURL("#fragment", "file:///path#old", {"file", "", "", "", 0, "/path", "", "fragment", "file:///path#fragment"});
+ checkRelativeURL("#", "file:///path#old", {"file", "", "", "", 0, "/path", "", "", "file:///path#"});
+ checkRelativeURL(" ", "file:///path#old", {"file", "", "", "", 0, "/path", "", "", "file:///path"});
+ checkRelativeURL("#", "file:///path", {"file", "", "", "", 0, "/path", "", "", "file:///path#"});
+ checkRelativeURL("#", "file:///path?query", {"file", "", "", "", 0, "/path", "query", "", "file:///path?query#"});
+ checkRelativeURL("#", "file:///path?query#old", {"file", "", "", "", 0, "/path", "query", "", "file:///path?query#"});
+ checkRelativeURL("?query", "http://host/path", {"http", "", "", "host", 0, "/path", "query", "", "http://host/path?query"});
+ checkRelativeURL("?query#fragment", "http://host/path", {"http", "", "", "host", 0, "/path", "query", "fragment", "http://host/path?query#fragment"});
+ checkRelativeURL("?new", "file:///path?old#fragment", {"file", "", "", "", 0, "/path", "new", "", "file:///path?new"});
+ checkRelativeURL("?", "file:///path?old#fragment", {"file", "", "", "", 0, "/path", "", "", "file:///path?"});
+ checkRelativeURL("?", "file:///path", {"file", "", "", "", 0, "/path", "", "", "file:///path?"});
+ checkRelativeURL("?query", "file:///path", {"file", "", "", "", 0, "/path", "query", "", "file:///path?query"});
+ checkRelativeURL(utf16String(u"?β"), "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "%CE%B2", "", "http://example.org/foo/bar?%CE%B2"});
+ checkRelativeURL("?", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar?"});
+ checkRelativeURL("#", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar#"});
+ checkRelativeURL("?#", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar?#"});
+ checkRelativeURL("#?", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "?", "http://example.org/foo/bar#?"});
+ checkRelativeURL("/", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/", "", "", "http://example.org/"});
+ checkRelativeURL("http://@host", "about:blank", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
+ checkRelativeURL("http://:@host", "about:blank", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
+ checkRelativeURL("http://foo.com/\\@", "http://example.org/foo/bar", {"http", "", "", "foo.com", 0, "//@", "", "", "http://foo.com//@"});
+ checkRelativeURL("\\@", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/@", "", "", "http://example.org/@"});
+ checkRelativeURL("/path3", "http://user@example.org/path1/path2", {"http", "user", "", "example.org", 0, "/path3", "", "", "http://user@example.org/path3"});
+ checkRelativeURL("", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar"});
+ checkRelativeURL("\t", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar"});
+ checkRelativeURL(" ", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar"});
+ checkRelativeURL(" \a \t\n", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar"});
+ checkRelativeURL(":foo.com\\", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/:foo.com/", "", "", "http://example.org/foo/:foo.com/"});
+ checkRelativeURL("http:/example.com/", "about:blank", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
+ checkRelativeURL("http:example.com/", "about:blank", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
+ checkRelativeURL("http:\\\\foo.com\\", "http://example.org/foo/bar", {"http", "", "", "foo.com", 0, "/", "", "", "http://foo.com/"});
+ checkRelativeURL("http:\\\\foo.com/", "http://example.org/foo/bar", {"http", "", "", "foo.com", 0, "/", "", "", "http://foo.com/"});
+ checkRelativeURL("http:\\\\foo.com", "http://example.org/foo/bar", {"http", "", "", "foo.com", 0, "/", "", "", "http://foo.com/"});
+ checkRelativeURL("http://ExAmPlE.CoM", "http://other.com", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
+ checkRelativeURL("http:", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar"});
+ checkRelativeURL("#x", "data:,", {"data", "", "", "", 0, ",", "", "x", "data:,#x"});
+ checkRelativeURL("#x", "about:blank", {"about", "", "", "", 0, "blank", "", "x", "about:blank#x"});
+ checkRelativeURL(" foo.com ", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/foo.com", "", "", "http://example.org/foo/foo.com"});
+ checkRelativeURL(" \a baz", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/baz", "", "", "http://example.org/foo/baz"});
+ checkRelativeURL("~", "http://example.org", {"http", "", "", "example.org", 0, "/~", "", "", "http://example.org/~"});
+ checkRelativeURL("notspecial:", "about:blank", {"notspecial", "", "", "", 0, "", "", "", "notspecial:"});
+ checkRelativeURL("notspecial:", "http://host", {"notspecial", "", "", "", 0, "", "", "", "notspecial:"});
+ checkRelativeURL("http:", "http://host", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
+ checkRelativeURL("i", "sc:/pa/po", {"sc", "", "", "", 0, "/pa/i", "", "", "sc:/pa/i"});
+ checkRelativeURL("i ", "sc:/pa/po", {"sc", "", "", "", 0, "/pa/i", "", "", "sc:/pa/i"});
+ checkRelativeURL("i\t\n ", "sc:/pa/po", {"sc", "", "", "", 0, "/pa/i", "", "", "sc:/pa/i"});
+ checkRelativeURL("i", "sc://ho/pa", {"sc", "", "", "ho", 0, "/i", "", "", "sc://ho/i"});
+ checkRelativeURL("!", "sc://ho/pa", {"sc", "", "", "ho", 0, "/!", "", "", "sc://ho/!"});
+ checkRelativeURL("!", "sc:/ho/pa", {"sc", "", "", "", 0, "/ho/!", "", "", "sc:/ho/!"});
+ checkRelativeURL("notspecial:/", "about:blank", {"notspecial", "", "", "", 0, "/", "", "", "notspecial:/"});
+ checkRelativeURL("notspecial:/", "http://host", {"notspecial", "", "", "", 0, "/", "", "", "notspecial:/"});
+ checkRelativeURL("foo:/", "http://example.org/foo/bar", {"foo", "", "", "", 0, "/", "", "", "foo:/"});
+ checkRelativeURL("://:0/", "http://webkit.org/", {"http", "", "", "webkit.org", 0, "/://:0/", "", "", "http://webkit.org/://:0/"});
+ checkRelativeURL(String(), "http://webkit.org/", {"http", "", "", "webkit.org", 0, "/", "", "", "http://webkit.org/"});
+ checkRelativeURL("https://@test@test@example:800\\path@end", "http://doesnotmatter/", {"", "", "", "", 0, "", "", "", "https://@test@test@example:800\\path@end"});
+ checkRelativeURL("http://f:0/c", "http://example.org/foo/bar", {"http", "", "", "f", 0, "/c", "", "", "http://f:0/c"});
+ checkRelativeURL(String(), "http://host/#fragment", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
+ checkRelativeURL("", "http://host/#fragment", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
+ checkRelativeURL(" ", "http://host/#fragment", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
+ checkRelativeURL(" ", "http://host/path?query#fra#gment", {"http", "", "", "host", 0, "/path", "query", "", "http://host/path?query"});
+ checkRelativeURL(" \a ", "http://host/#fragment", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
+ checkRelativeURLDifferences("foo://", "http://example.org/foo/bar",
+ {"foo", "", "", "", 0, "", "", "", "foo://"},
+ {"foo", "", "", "", 0, "//", "", "", "foo://"});
+ checkRelativeURL(utf16String(u"#β"), "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "%CE%B2", "http://example.org/foo/bar#%CE%B2"});
+ checkRelativeURL("index.html", "applewebdata://Host/", {"applewebdata", "", "", "Host", 0, "/index.html", "", "", "applewebdata://Host/index.html"});
+ checkRelativeURL("index.html", "applewebdata://Host", {"applewebdata", "", "", "Host", 0, "/index.html", "", "", "applewebdata://Host/index.html"});
+ checkRelativeURL("", "applewebdata://Host", {"applewebdata", "", "", "Host", 0, "", "", "", "applewebdata://Host"});
+ checkRelativeURL("?query", "applewebdata://Host", {"applewebdata", "", "", "Host", 0, "", "query", "", "applewebdata://Host?query"});
+ checkRelativeURL("#fragment", "applewebdata://Host", {"applewebdata", "", "", "Host", 0, "", "", "fragment", "applewebdata://Host#fragment"});
+ checkRelativeURL("notspecial://something?", "file:////var//containers//stuff/", {"notspecial", "", "", "something", 0, "", "", "", "notspecial://something?"}, TestTabs::No);
+ checkRelativeURL("notspecial://something#", "file:////var//containers//stuff/", {"notspecial", "", "", "something", 0, "", "", "", "notspecial://something#"}, TestTabs::No);
+ checkRelativeURL("http://something?", "file:////var//containers//stuff/", {"http", "", "", "something", 0, "/", "", "", "http://something/?"}, TestTabs::No);
+ checkRelativeURL("http://something#", "file:////var//containers//stuff/", {"http", "", "", "something", 0, "/", "", "", "http://something/#"}, TestTabs::No);
+ checkRelativeURL("file:", "file:///path?query#fragment", {"file", "", "", "", 0, "/path", "query", "", "file:///path?query"});
+ checkRelativeURL("/", "file:///C:/a/b", {"file", "", "", "", 0, "/C:/", "", "", "file:///C:/"});
+ checkRelativeURL("/abc", "file:///C:/a/b", {"file", "", "", "", 0, "/C:/abc", "", "", "file:///C:/abc"});
+ checkRelativeURL("/abc", "file:///C:", {"file", "", "", "", 0, "/C:/abc", "", "", "file:///C:/abc"});
+ checkRelativeURL("/abc", "file:///", {"file", "", "", "", 0, "/abc", "", "", "file:///abc"});
+ checkRelativeURL("//d:", "file:///C:/a/b", {"file", "", "", "", 0, "/d:", "", "", "file:///d:"}, TestTabs::No);
+ checkRelativeURL("//d|", "file:///C:/a/b", {"file", "", "", "", 0, "/d:", "", "", "file:///d:"}, TestTabs::No);
+ checkRelativeURL("//A|", "file:///C:/a/b", {"file", "", "", "", 0, "/A:", "", "", "file:///A:"}, TestTabs::No);
+
+ // The checking of slashes in SpecialAuthoritySlashes needed to get this to pass contradicts what is in the spec,
+ // but it is included in the web platform tests.
+ checkRelativeURL("http:\\\\host\\foo", "about:blank", {"http", "", "", "host", 0, "/foo", "", "", "http://host/foo"});
+}
+
+// These are differences between the new URLParser and the old URL::parse which make URLParser more standards compliant.
+TEST_F(URLParserTest, ParserDifferences)
+{
+ checkURLDifferences("http://127.0.1",
+ {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"},
+ {"http", "", "", "127.0.1", 0, "/", "", "", "http://127.0.1/"});
+ checkURLDifferences("http://011.11.0X11.0x011",
+ {"http", "", "", "9.11.17.17", 0, "/", "", "", "http://9.11.17.17/"},
+ {"http", "", "", "011.11.0x11.0x011", 0, "/", "", "", "http://011.11.0x11.0x011/"});
+ checkURLDifferences("http://[1234:0078:90AB:CdEf:0123:0007:89AB:0000]",
+ {"http", "", "", "[1234:78:90ab:cdef:123:7:89ab:0]", 0, "/", "", "", "http://[1234:78:90ab:cdef:123:7:89ab:0]/"},
+ {"http", "", "", "[1234:0078:90ab:cdef:0123:0007:89ab:0000]", 0, "/", "", "", "http://[1234:0078:90ab:cdef:0123:0007:89ab:0000]/"});
+ checkURLDifferences("http://[0:f:0:0:f:f:0:0]",
+ {"http", "", "", "[0:f::f:f:0:0]", 0, "/", "", "", "http://[0:f::f:f:0:0]/"},
+ {"http", "", "", "[0:f:0:0:f:f:0:0]", 0, "/", "", "", "http://[0:f:0:0:f:f:0:0]/"});
+ checkURLDifferences("http://[0:f:0:0:f:0:0:0]",
+ {"http", "", "", "[0:f:0:0:f::]", 0, "/", "", "", "http://[0:f:0:0:f::]/"},
+ {"http", "", "", "[0:f:0:0:f:0:0:0]", 0, "/", "", "", "http://[0:f:0:0:f:0:0:0]/"});
+ checkURLDifferences("http://[0:0:f:0:0:f:0:0]",
+ {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"},
+ {"http", "", "", "[0:0:f:0:0:f:0:0]", 0, "/", "", "", "http://[0:0:f:0:0:f:0:0]/"});
+ checkURLDifferences("http://[a:0:0:0:b:c::d]",
+ {"http", "", "", "[a::b:c:0:d]", 0, "/", "", "", "http://[a::b:c:0:d]/"},
+ {"http", "", "", "[a:0:0:0:b:c::d]", 0, "/", "", "", "http://[a:0:0:0:b:c::d]/"});
+ checkURLDifferences("http://[::7f00:0001]/",
+ {"http", "", "", "[::7f00:1]", 0, "/", "", "", "http://[::7f00:1]/"},
+ {"http", "", "", "[::7f00:0001]", 0, "/", "", "", "http://[::7f00:0001]/"});
+ checkURLDifferences("http://[::7f00:00]/",
+ {"http", "", "", "[::7f00:0]", 0, "/", "", "", "http://[::7f00:0]/"},
+ {"http", "", "", "[::7f00:00]", 0, "/", "", "", "http://[::7f00:00]/"});
+ checkURLDifferences("http://[::0:7f00:0001]/",
+ {"http", "", "", "[::7f00:1]", 0, "/", "", "", "http://[::7f00:1]/"},
+ {"http", "", "", "[::0:7f00:0001]", 0, "/", "", "", "http://[::0:7f00:0001]/"});
+ checkURLDifferences("http://127.00.0.1/",
+ {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"},
+ {"http", "", "", "127.00.0.1", 0, "/", "", "", "http://127.00.0.1/"});
+ checkURLDifferences("http://127.0.0.01/",
+ {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"},
+ {"http", "", "", "127.0.0.01", 0, "/", "", "", "http://127.0.0.01/"});
+ checkURLDifferences("http://example.com/path1/.%2e",
+ {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"},
+ {"http", "", "", "example.com", 0, "/path1/.%2e", "", "", "http://example.com/path1/.%2e"});
+ checkURLDifferences("http://example.com/path1/.%2E",
+ {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"},
+ {"http", "", "", "example.com", 0, "/path1/.%2E", "", "", "http://example.com/path1/.%2E"});
+ checkURLDifferences("http://example.com/path1/.%2E/",
+ {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"},
+ {"http", "", "", "example.com", 0, "/path1/.%2E/", "", "", "http://example.com/path1/.%2E/"});
+ checkURLDifferences("http://example.com/path1/%2e.",
+ {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"},
+ {"http", "", "", "example.com", 0, "/path1/%2e.", "", "", "http://example.com/path1/%2e."});
+ checkURLDifferences("http://example.com/path1/%2E%2e",
+ {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"},
+ {"http", "", "", "example.com", 0, "/path1/%2E%2e", "", "", "http://example.com/path1/%2E%2e"});
+ checkURLDifferences("http://example.com/path1/%2e",
+ {"http", "", "", "example.com", 0, "/path1/", "", "", "http://example.com/path1/"},
+ {"http", "", "", "example.com", 0, "/path1/%2e", "", "", "http://example.com/path1/%2e"});
+ checkURLDifferences("http://example.com/path1/%2E",
+ {"http", "", "", "example.com", 0, "/path1/", "", "", "http://example.com/path1/"},
+ {"http", "", "", "example.com", 0, "/path1/%2E", "", "", "http://example.com/path1/%2E"});
+ checkURLDifferences("http://example.com/path1/%2E/",
+ {"http", "", "", "example.com", 0, "/path1/", "", "", "http://example.com/path1/"},
+ {"http", "", "", "example.com", 0, "/path1/%2E/", "", "", "http://example.com/path1/%2E/"});
+ checkURLDifferences("http://example.com/path1/path2/%2e?query",
+ {"http", "", "", "example.com", 0, "/path1/path2/", "query", "", "http://example.com/path1/path2/?query"},
+ {"http", "", "", "example.com", 0, "/path1/path2/%2e", "query", "", "http://example.com/path1/path2/%2e?query"});
+ checkURLDifferences("http://example.com/path1/path2/%2e%2e?query",
+ {"http", "", "", "example.com", 0, "/path1/", "query", "", "http://example.com/path1/?query"},
+ {"http", "", "", "example.com", 0, "/path1/path2/%2e%2e", "query", "", "http://example.com/path1/path2/%2e%2e?query"});
+ checkURLDifferences("http://example.com/path1/path2/%2e#fragment",
+ {"http", "", "", "example.com", 0, "/path1/path2/", "", "fragment", "http://example.com/path1/path2/#fragment"},
+ {"http", "", "", "example.com", 0, "/path1/path2/%2e", "", "fragment", "http://example.com/path1/path2/%2e#fragment"});
+ checkURLDifferences("http://example.com/path1/path2/%2e%2e#fragment",
+ {"http", "", "", "example.com", 0, "/path1/", "", "fragment", "http://example.com/path1/#fragment"},
+ {"http", "", "", "example.com", 0, "/path1/path2/%2e%2e", "", "fragment", "http://example.com/path1/path2/%2e%2e#fragment"});
+ checkURL("http://example.com/path1/path2/A%2e%2e#fragment", {"http", "", "", "example.com", 0, "/path1/path2/A%2e%2e", "", "fragment", "http://example.com/path1/path2/A%2e%2e#fragment"});
+ checkURLDifferences("file://[0:a:0:0:b:c:0:0]/path",
+ {"file", "", "", "[0:a::b:c:0:0]", 0, "/path", "", "", "file://[0:a::b:c:0:0]/path"},
+ {"file", "", "", "[0:a:0:0:b:c:0:0]", 0, "/path", "", "", "file://[0:a:0:0:b:c:0:0]/path"});
+ checkURLDifferences("http://",
+ {"", "", "", "", 0, "", "", "", "http://"},
+ {"http", "", "", "", 0, "/", "", "", "http:/"});
+ checkRelativeURLDifferences("//", "https://www.webkit.org/path",
+ {"", "", "", "", 0, "", "", "", "//"},
+ {"https", "", "", "", 0, "/", "", "", "https:/"});
+ checkURLDifferences("http://127.0.0.1:65536/path",
+ {"", "", "", "", 0, "", "", "", "http://127.0.0.1:65536/path"},
+ {"http", "", "", "127.0.0.1", 0, "/path", "", "", "http://127.0.0.1:65536/path"});
+ checkURLDifferences("http://host:65536",
+ {"", "", "", "", 0, "", "", "", "http://host:65536"},
+ {"http", "", "", "host", 0, "/", "", "", "http://host:65536/"});
+ checkURLDifferences("http://127.0.0.1:65536",
+ {"", "", "", "", 0, "", "", "", "http://127.0.0.1:65536"},
+ {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1:65536/"});
+ checkURLDifferences("http://[0:f::f:f:0:0]:65536",
+ {"", "", "", "", 0, "", "", "", "http://[0:f::f:f:0:0]:65536"},
+ {"http", "", "", "[0:f::f:f:0:0]", 0, "/", "", "", "http://[0:f::f:f:0:0]:65536/"});
+ checkRelativeURLDifferences(":foo.com\\", "notspecial://example.org/foo/bar",
+ {"notspecial", "", "", "example.org", 0, "/foo/:foo.com\\", "", "", "notspecial://example.org/foo/:foo.com\\"},
+ {"notspecial", "", "", "example.org", 0, "/foo/:foo.com/", "", "", "notspecial://example.org/foo/:foo.com/"});
+ checkURL("sc://pa", {"sc", "", "", "pa", 0, "", "", "", "sc://pa"});
+ checkRelativeURLDifferences("notspecial:\\\\foo.com\\", "http://example.org/foo/bar",
+ {"notspecial", "", "", "", 0, "\\\\foo.com\\", "", "", "notspecial:\\\\foo.com\\"},
+ {"notspecial", "", "", "foo.com", 0, "/", "", "", "notspecial://foo.com/"});
+ checkRelativeURLDifferences("notspecial:\\\\foo.com/", "http://example.org/foo/bar",
+ {"notspecial", "", "", "", 0, "\\\\foo.com/", "", "", "notspecial:\\\\foo.com/"},
+ {"notspecial", "", "", "foo.com", 0, "/", "", "", "notspecial://foo.com/"});
+ checkRelativeURLDifferences("notspecial:\\\\foo.com", "http://example.org/foo/bar",
+ {"notspecial", "", "", "", 0, "\\\\foo.com", "", "", "notspecial:\\\\foo.com"},
+ {"notspecial", "", "", "foo.com", 0, "", "", "", "notspecial://foo.com"});
+ checkURLDifferences("file://notuser:notpassword@test",
+ {"", "", "", "", 0, "", "", "", "file://notuser:notpassword@test"},
+ {"file", "notuser", "notpassword", "test", 0, "/", "", "", "file://notuser:notpassword@test/"});
+ checkURLDifferences("file://notuser:notpassword@test/",
+ {"", "", "", "", 0, "", "", "", "file://notuser:notpassword@test/"},
+ {"file", "notuser", "notpassword", "test", 0, "/", "", "", "file://notuser:notpassword@test/"});
+ checkRelativeURLDifferences("http:/", "about:blank",
+ {"", "", "", "", 0, "", "", "", "http:/"},
+ {"http", "", "", "", 0, "/", "", "", "http:/"});
+ checkRelativeURLDifferences("http:", "about:blank",
+ {"http", "", "", "", 0, "", "", "", "http:"},
+ {"http", "", "", "", 0, "/", "", "", "http:/"});
+ checkRelativeURLDifferences("http:/", "http://host",
+ {"", "", "", "", 0, "", "", "", "http:/"},
+ {"http", "", "", "", 0, "/", "", "", "http:/"});
+ checkURLDifferences("http:/",
+ {"", "", "", "", 0, "", "", "", "http:/"},
+ {"http", "", "", "", 0, "/", "", "", "http:/"});
+ checkURLDifferences("http:",
+ {"http", "", "", "", 0, "", "", "", "http:"},
+ {"http", "", "", "", 0, "/", "", "", "http:/"});
+ checkRelativeURLDifferences("http:/example.com/", "http://example.org/foo/bar",
+ {"http", "", "", "example.org", 0, "/example.com/", "", "", "http://example.org/example.com/"},
+ {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
+
+ // This behavior matches Chrome and Firefox, but not WebKit using URL::parse.
+ // The behavior of URL::parse is clearly wrong because reparsing file://path would make path the host.
+ // The spec is unclear.
+ checkURLDifferences("file:path",
+ {"file", "", "", "", 0, "/path", "", "", "file:///path"},
+ {"file", "", "", "", 0, "path", "", "", "file://path"});
+ checkURLDifferences("file:pAtH",
+ {"file", "", "", "", 0, "/pAtH", "", "", "file:///pAtH"},
+ {"file", "", "", "", 0, "pAtH", "", "", "file://pAtH"});
+ checkURLDifferences("file:pAtH/",
+ {"file", "", "", "", 0, "/pAtH/", "", "", "file:///pAtH/"},
+ {"file", "", "", "", 0, "pAtH/", "", "", "file://pAtH/"});
+ checkURLDifferences("http://example.com%A0",
+ {"", "", "", "", 0, "", "", "", "http://example.com%A0"},
+ {"http", "", "", "example.com%a0", 0, "/", "", "", "http://example.com%a0/"});
+ checkURLDifferences("http://%E2%98%83",
+ {"http", "", "", "xn--n3h", 0, "/", "", "", "http://xn--n3h/"},
+ {"http", "", "", "%e2%98%83", 0, "/", "", "", "http://%e2%98%83/"});
+ checkURLDifferences("http://host%73",
+ {"http", "", "", "hosts", 0, "/", "", "", "http://hosts/"},
+ {"http", "", "", "host%73", 0, "/", "", "", "http://host%73/"});
+ checkURLDifferences("http://host%53",
+ {"http", "", "", "hosts", 0, "/", "", "", "http://hosts/"},
+ {"http", "", "", "host%53", 0, "/", "", "", "http://host%53/"});
+ checkURLDifferences("http://%",
+ {"", "", "", "", 0, "", "", "", "http://%"},
+ {"http", "", "", "%", 0, "/", "", "", "http://%/"});
+ checkURLDifferences("http://%7",
+ {"", "", "", "", 0, "", "", "", "http://%7"},
+ {"http", "", "", "%7", 0, "/", "", "", "http://%7/"});
+ checkURLDifferences("http://%7s",
+ {"", "", "", "", 0, "", "", "", "http://%7s"},
+ {"http", "", "", "%7s", 0, "/", "", "", "http://%7s/"});
+ checkURLDifferences("http://%73",
+ {"http", "", "", "s", 0, "/", "", "", "http://s/"},
+ {"http", "", "", "%73", 0, "/", "", "", "http://%73/"});
+ checkURLDifferences("http://abcdefg%",
+ {"", "", "", "", 0, "", "", "", "http://abcdefg%"},
+ {"http", "", "", "abcdefg%", 0, "/", "", "", "http://abcdefg%/"});
+ checkURLDifferences("http://abcd%7Xefg",
+ {"", "", "", "", 0, "", "", "", "http://abcd%7Xefg"},
+ {"http", "", "", "abcd%7xefg", 0, "/", "", "", "http://abcd%7xefg/"});
+
+
+ // URLParser matches Chrome and the spec, but not URL::parse or Firefox.
+ checkURLDifferences(utf16String(u"http://0Xc0.0250.01"),
+ {"http", "", "", "192.168.0.1", 0, "/", "", "", "http://192.168.0.1/"},
+ {"http", "", "", "0xc0.0250.01", 0, "/", "", "", "http://0xc0.0250.01/"});
+
+ checkURL("http://host/path%2e.%2E", {"http", "", "", "host", 0, "/path%2e.%2E", "", "", "http://host/path%2e.%2E"});
+
+ checkRelativeURLDifferences(utf16String(u"http://foo:💩@example.com/bar"), "http://other.com/",
+ {"http", "foo", utf16String(u"💩"), "example.com", 0, "/bar", "", "", "http://foo:%F0%9F%92%A9@example.com/bar"},
+ {"", "", "", "", 0, "", "", "", utf16String(u"http://foo:💩@example.com/bar")}, testTabsValueForSurrogatePairs);
+ checkRelativeURLDifferences("http://&a:foo(b]c@d:2/", "http://example.org/foo/bar",
+ {"http", "&a", "foo(b]c", "d", 2, "/", "", "", "http://&a:foo(b%5Dc@d:2/"},
+ {"", "", "", "", 0, "", "", "", "http://&a:foo(b]c@d:2/"});
+ checkRelativeURLDifferences("http://`{}:`{}@h/`{}?`{}", "http://doesnotmatter/",
+ {"http", "`{}", "`{}", "h", 0, "/%60%7B%7D", "`{}", "", "http://%60%7B%7D:%60%7B%7D@h/%60%7B%7D?`{}"},
+ {"", "", "", "", 0, "", "", "", "http://`{}:`{}@h/`{}?`{}"});
+ checkURLDifferences("http://[0:f::f::f]",
+ {"", "", "", "", 0, "" , "", "", "http://[0:f::f::f]"},
+ {"http", "", "", "[0:f::f::f]", 0, "/" , "", "", "http://[0:f::f::f]/"});
+ checkURLDifferences("http://123",
+ {"http", "", "", "0.0.0.123", 0, "/", "", "", "http://0.0.0.123/"},
+ {"http", "", "", "123", 0, "/", "", "", "http://123/"});
+ checkURLDifferences("http://123.234/",
+ {"http", "", "", "123.0.0.234", 0, "/", "", "", "http://123.0.0.234/"},
+ {"http", "", "", "123.234", 0, "/", "", "", "http://123.234/"});
+ checkURLDifferences("http://123.234.012",
+ {"http", "", "", "123.234.0.10", 0, "/", "", "", "http://123.234.0.10/"},
+ {"http", "", "", "123.234.012", 0, "/", "", "", "http://123.234.012/"});
+ checkURLDifferences("http://123.234.12",
+ {"http", "", "", "123.234.0.12", 0, "/", "", "", "http://123.234.0.12/"},
+ {"http", "", "", "123.234.12", 0, "/", "", "", "http://123.234.12/"});
+ checkRelativeURLDifferences("file:c:\\foo\\bar.html", "file:///tmp/mock/path",
+ {"file", "", "", "", 0, "/c:/foo/bar.html", "", "", "file:///c:/foo/bar.html"},
+ {"file", "", "", "", 0, "/tmp/mock/c:/foo/bar.html", "", "", "file:///tmp/mock/c:/foo/bar.html"});
+ checkRelativeURLDifferences(" File:c|////foo\\bar.html", "file:///tmp/mock/path",
+ {"file", "", "", "", 0, "/c:////foo/bar.html", "", "", "file:///c:////foo/bar.html"},
+ {"file", "", "", "", 0, "/tmp/mock/c|////foo/bar.html", "", "", "file:///tmp/mock/c|////foo/bar.html"});
+ checkRelativeURLDifferences(" Fil\t\n\te\n\t\n:\t\n\tc\t\n\t|\n\t\n/\t\n\t/\n\t\n//foo\\bar.html", "file:///tmp/mock/path",
+ {"file", "", "", "", 0, "/c:////foo/bar.html", "", "", "file:///c:////foo/bar.html"},
+ {"file", "", "", "", 0, "/tmp/mock/c|////foo/bar.html", "", "", "file:///tmp/mock/c|////foo/bar.html"});
+ checkRelativeURLDifferences("C|/foo/bar", "file:///tmp/mock/path",
+ {"file", "", "", "", 0, "/C:/foo/bar", "", "", "file:///C:/foo/bar"},
+ {"file", "", "", "", 0, "/tmp/mock/C|/foo/bar", "", "", "file:///tmp/mock/C|/foo/bar"});
+ checkRelativeURLDifferences("/C|/foo/bar", "file:///tmp/mock/path",
+ {"file", "", "", "", 0, "/C:/foo/bar", "", "", "file:///C:/foo/bar"},
+ {"file", "", "", "", 0, "/C|/foo/bar", "", "", "file:///C|/foo/bar"});
+ checkRelativeURLDifferences("https://@test@test@example:800/", "http://doesnotmatter/",
+ {"https", "@test@test", "", "example", 800, "/", "", "", "https://%40test%40test@example:800/"},
+ {"", "", "", "", 0, "", "", "", "https://@test@test@example:800/"});
+ checkRelativeURLDifferences("https://@test@test@example:800/path@end", "http://doesnotmatter/",
+ {"https", "@test@test", "", "example", 800, "/path@end", "", "", "https://%40test%40test@example:800/path@end"},
+ {"", "", "", "", 0, "", "", "", "https://@test@test@example:800/path@end"});
+ checkURLDifferences("notspecial://@test@test@example:800/path@end",
+ {"notspecial", "@test@test", "", "example", 800, "/path@end", "", "", "notspecial://%40test%40test@example:800/path@end"},
+ {"", "", "", "", 0, "", "", "", "notspecial://@test@test@example:800/path@end"});
+ checkURLDifferences("notspecial://@test@test@example:800\\path@end",
+ {"notspecial", "@test@test@example", "800\\path", "end", 0, "", "", "", "notspecial://%40test%40test%40example:800%5Cpath@end"},
+ {"", "", "", "", 0, "", "", "", "notspecial://@test@test@example:800\\path@end"});
+ checkURLDifferences("http://%48OsT",
+ {"http", "", "", "host", 0, "/", "", "", "http://host/"},
+ {"http", "", "", "%48ost", 0, "/", "", "", "http://%48ost/"});
+ checkURLDifferences("http://h%4FsT",
+ {"http", "", "", "host", 0, "/", "", "", "http://host/"},
+ {"http", "", "", "h%4fst", 0, "/", "", "", "http://h%4fst/"});
+ checkURLDifferences("http://h%4fsT",
+ {"http", "", "", "host", 0, "/", "", "", "http://host/"},
+ {"http", "", "", "h%4fst", 0, "/", "", "", "http://h%4fst/"});
+ checkURLDifferences("http://h%6fsT",
+ {"http", "", "", "host", 0, "/", "", "", "http://host/"},
+ {"http", "", "", "h%6fst", 0, "/", "", "", "http://h%6fst/"});
+ checkURLDifferences("http://host/`",
+ {"http", "", "", "host", 0, "/%60", "", "", "http://host/%60"},
+ {"http", "", "", "host", 0, "/`", "", "", "http://host/`"});
+ checkURLDifferences("http://://",
+ {"", "", "", "", 0, "", "", "", "http://://"},
+ {"http", "", "", "", 0, "//", "", "", "http://://"});
+ checkURLDifferences("http://:123?",
+ {"", "", "", "", 0, "", "", "", "http://:123?"},
+ {"http", "", "", "", 123, "/", "", "", "http://:123/?"});
+ checkURLDifferences("http:/:",
+ {"", "", "", "", 0, "", "", "", "http:/:"},
+ {"http", "", "", "", 0, "/", "", "", "http://:/"});
+ checkURLDifferences("asdf://:",
+ {"", "", "", "", 0, "", "", "", "asdf://:"},
+ {"asdf", "", "", "", 0, "", "", "", "asdf://:"});
+ checkURLDifferences("http://:",
+ {"", "", "", "", 0, "", "", "", "http://:"},
+ {"http", "", "", "", 0, "/", "", "", "http://:/"});
+ checkURLDifferences("http:##foo",
+ {"", "", "", "", 0, "", "", "", "http:##foo"},
+ {"http", "", "", "", 0, "/", "", "#foo", "http:/##foo"});
+ checkURLDifferences("http:??bar",
+ {"", "", "", "", 0, "", "", "", "http:??bar"},
+ {"http", "", "", "", 0, "/", "?bar", "", "http:/??bar"});
+ checkURL("asdf:##foo", {"asdf", "", "", "", 0, "", "", "#foo", "asdf:##foo"});
+ checkURL("asdf:??bar", {"asdf", "", "", "", 0, "", "?bar", "", "asdf:??bar"});
+ checkRelativeURLDifferences("//C|/foo/bar", "file:///tmp/mock/path",
+ {"file", "", "", "", 0, "/C:/foo/bar", "", "", "file:///C:/foo/bar"},
+ {"", "", "", "", 0, "", "", "", "//C|/foo/bar"});
+ checkRelativeURLDifferences("//C:/foo/bar", "file:///tmp/mock/path",
+ {"file", "", "", "", 0, "/C:/foo/bar", "", "", "file:///C:/foo/bar"},
+ {"file", "", "", "c", 0, "/foo/bar", "", "", "file://c/foo/bar"});
+ checkRelativeURLDifferences("//C|?foo/bar", "file:///tmp/mock/path",
+ {"file", "", "", "", 0, "/C:/", "foo/bar", "", "file:///C:/?foo/bar"},
+ {"", "", "", "", 0, "", "", "", "//C|?foo/bar"});
+ checkRelativeURLDifferences("//C|#foo/bar", "file:///tmp/mock/path",
+ {"file", "", "", "", 0, "/C:/", "", "foo/bar", "file:///C:/#foo/bar"},
+ {"", "", "", "", 0, "", "", "", "//C|#foo/bar"});
+ checkURLDifferences("http://0xFFFFFfFF/",
+ {"http", "", "", "255.255.255.255", 0, "/", "", "", "http://255.255.255.255/"},
+ {"http", "", "", "0xffffffff", 0, "/", "", "", "http://0xffffffff/"});
+ checkURLDifferences("http://0000000000000000037777777777/",
+ {"http", "", "", "255.255.255.255", 0, "/", "", "", "http://255.255.255.255/"},
+ {"http", "", "", "0000000000000000037777777777", 0, "/", "", "", "http://0000000000000000037777777777/"});
+ checkURLDifferences("http://4294967295/",
+ {"http", "", "", "255.255.255.255", 0, "/", "", "", "http://255.255.255.255/"},
+ {"http", "", "", "4294967295", 0, "/", "", "", "http://4294967295/"});
+ checkURLDifferences("http://256/",
+ {"http", "", "", "0.0.1.0", 0, "/", "", "", "http://0.0.1.0/"},
+ {"http", "", "", "256", 0, "/", "", "", "http://256/"});
+ checkURLDifferences("http://256./",
+ {"http", "", "", "0.0.1.0", 0, "/", "", "", "http://0.0.1.0/"},
+ {"http", "", "", "256.", 0, "/", "", "", "http://256./"});
+ checkURLDifferences("http://123.256/",
+ {"http", "", "", "123.0.1.0", 0, "/", "", "", "http://123.0.1.0/"},
+ {"http", "", "", "123.256", 0, "/", "", "", "http://123.256/"});
+ checkURLDifferences("http://127.%.0.1/",
+ {"", "", "", "", 0, "", "", "", "http://127.%.0.1/"},
+ {"http", "", "", "127.%.0.1", 0, "/", "", "", "http://127.%.0.1/"});
+ checkURLDifferences("http://[1:2:3:4:5:6:7:8:]/",
+ {"", "", "", "", 0, "", "", "", "http://[1:2:3:4:5:6:7:8:]/"},
+ {"http", "", "", "[1:2:3:4:5:6:7:8:]", 0, "/", "", "", "http://[1:2:3:4:5:6:7:8:]/"});
+ checkURLDifferences("http://[:2:3:4:5:6:7:8:]/",
+ {"", "", "", "", 0, "", "", "", "http://[:2:3:4:5:6:7:8:]/"},
+ {"http", "", "", "[:2:3:4:5:6:7:8:]", 0, "/", "", "", "http://[:2:3:4:5:6:7:8:]/"});
+ checkURLDifferences("http://[1:2:3:4:5:6:7::]/",
+ {"http", "", "", "[1:2:3:4:5:6:7:0]", 0, "/", "", "", "http://[1:2:3:4:5:6:7:0]/"},
+ {"http", "", "", "[1:2:3:4:5:6:7::]", 0, "/", "", "", "http://[1:2:3:4:5:6:7::]/"});
+ checkURLDifferences("http://[1:2:3:4:5:6:7:::]/",
+ {"", "", "", "", 0, "", "", "", "http://[1:2:3:4:5:6:7:::]/"},
+ {"http", "", "", "[1:2:3:4:5:6:7:::]", 0, "/", "", "", "http://[1:2:3:4:5:6:7:::]/"});
+ checkURLDifferences("http://127.0.0.1~/",
+ {"http", "", "", "127.0.0.1~", 0, "/", "", "", "http://127.0.0.1~/"},
+ {"", "", "", "", 0, "", "", "", "http://127.0.0.1~/"});
+ checkURLDifferences("http://127.0.1~/",
+ {"http", "", "", "127.0.1~", 0, "/", "", "", "http://127.0.1~/"},
+ {"", "", "", "", 0, "", "", "", "http://127.0.1~/"});
+ checkURLDifferences("http://127.0.1./",
+ {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"},
+ {"http", "", "", "127.0.1.", 0, "/", "", "", "http://127.0.1./"});
+ checkURLDifferences("http://127.0.1.~/",
+ {"http", "", "", "127.0.1.~", 0, "/", "", "", "http://127.0.1.~/"},
+ {"", "", "", "", 0, "", "", "", "http://127.0.1.~/"});
+ checkURLDifferences("http://127.0.1.~",
+ {"http", "", "", "127.0.1.~", 0, "/", "", "", "http://127.0.1.~/"},
+ {"", "", "", "", 0, "", "", "", "http://127.0.1.~"});
+ checkRelativeURLDifferences("http://f:000/c", "http://example.org/foo/bar",
+ {"http", "", "", "f", 0, "/c", "", "", "http://f:0/c"},
+ {"http", "", "", "f", 0, "/c", "", "", "http://f:000/c"});
+ checkRelativeURLDifferences("http://f:010/c", "http://example.org/foo/bar",
+ {"http", "", "", "f", 10, "/c", "", "", "http://f:10/c"},
+ {"http", "", "", "f", 10, "/c", "", "", "http://f:010/c"});
+ checkURL("notspecial://HoSt", {"notspecial", "", "", "HoSt", 0, "", "", "", "notspecial://HoSt"});
+ checkURL("notspecial://H%6FSt", {"notspecial", "", "", "H%6FSt", 0, "", "", "", "notspecial://H%6FSt"});
+ checkURL("notspecial://H%4fSt", {"notspecial", "", "", "H%4fSt", 0, "", "", "", "notspecial://H%4fSt"});
+ checkURLDifferences(utf16String(u"notspecial://H😍ßt"),
+ {"notspecial", "", "", "H%F0%9F%98%8D%C3%9Ft", 0, "", "", "", "notspecial://H%F0%9F%98%8D%C3%9Ft"},
+ {"notspecial", "", "", "xn--hsst-qc83c", 0, "", "", "", "notspecial://xn--hsst-qc83c"}, testTabsValueForSurrogatePairs);
+ checkURLDifferences("http://[ffff:aaaa:cccc:eeee:bbbb:dddd:255.255.255.255]/",
+ {"http", "", "", "[ffff:aaaa:cccc:eeee:bbbb:dddd:ffff:ffff]", 0, "/", "", "", "http://[ffff:aaaa:cccc:eeee:bbbb:dddd:ffff:ffff]/"},
+ {"http", "", "", "[ffff:aaaa:cccc:eeee:bbbb:dddd:255.255.255.255]", 0, "/", "", "", "http://[ffff:aaaa:cccc:eeee:bbbb:dddd:255.255.255.255]/"}, TestTabs::No);
+ checkURLDifferences("http://[::123.234.12.210]/",
+ {"http", "", "", "[::7bea:cd2]", 0, "/", "", "", "http://[::7bea:cd2]/"},
+ {"http", "", "", "[::123.234.12.210]", 0, "/", "", "", "http://[::123.234.12.210]/"});
+ checkURLDifferences("http://[::a:255.255.255.255]/",
+ {"http", "", "", "[::a:ffff:ffff]", 0, "/", "", "", "http://[::a:ffff:ffff]/"},
+ {"http", "", "", "[::a:255.255.255.255]", 0, "/", "", "", "http://[::a:255.255.255.255]/"});
+ checkURLDifferences("http://[::0.00.255.255]/",
+ {"", "", "", "", 0, "", "", "", "http://[::0.00.255.255]/"},
+ {"http", "", "", "[::0.00.255.255]", 0, "/", "", "", "http://[::0.00.255.255]/"});
+ checkURLDifferences("http://[::0.0.255.255]/",
+ {"http", "", "", "[::ffff]", 0, "/", "", "", "http://[::ffff]/"},
+ {"http", "", "", "[::0.0.255.255]", 0, "/", "", "", "http://[::0.0.255.255]/"});
+ checkURLDifferences("http://[::0:1.0.255.255]/",
+ {"http", "", "", "[::100:ffff]", 0, "/", "", "", "http://[::100:ffff]/"},
+ {"http", "", "", "[::0:1.0.255.255]", 0, "/", "", "", "http://[::0:1.0.255.255]/"});
+ checkURLDifferences("http://[::A:1.0.255.255]/",
+ {"http", "", "", "[::a:100:ffff]", 0, "/", "", "", "http://[::a:100:ffff]/"},
+ {"http", "", "", "[::a:1.0.255.255]", 0, "/", "", "", "http://[::a:1.0.255.255]/"});
+ checkURLDifferences("http://[:127.0.0.1]",
+ {"", "", "", "", 0, "", "", "", "http://[:127.0.0.1]"},
+ {"http", "", "", "[:127.0.0.1]", 0, "/", "", "", "http://[:127.0.0.1]/"});
+ checkURLDifferences("http://[127.0.0.1]",
+ {"", "", "", "", 0, "", "", "", "http://[127.0.0.1]"},
+ {"http", "", "", "[127.0.0.1]", 0, "/", "", "", "http://[127.0.0.1]/"});
+ checkURLDifferences("http://[a:b:c:d:e:f:127.0.0.1]",
+ {"http", "", "", "[a:b:c:d:e:f:7f00:1]", 0, "/", "", "", "http://[a:b:c:d:e:f:7f00:1]/"},
+ {"http", "", "", "[a:b:c:d:e:f:127.0.0.1]", 0, "/", "", "", "http://[a:b:c:d:e:f:127.0.0.1]/"});
+ checkURLDifferences("http://[a:b:c:d:e:f:127.0.0.101]",
+ {"http", "", "", "[a:b:c:d:e:f:7f00:65]", 0, "/", "", "", "http://[a:b:c:d:e:f:7f00:65]/"},
+ {"http", "", "", "[a:b:c:d:e:f:127.0.0.101]", 0, "/", "", "", "http://[a:b:c:d:e:f:127.0.0.101]/"});
+ checkURLDifferences("http://[::a:b:c:d:e:f:127.0.0.1]",
+ {"", "", "", "", 0, "", "", "", "http://[::a:b:c:d:e:f:127.0.0.1]"},
+ {"http", "", "", "[::a:b:c:d:e:f:127.0.0.1]", 0, "/", "", "", "http://[::a:b:c:d:e:f:127.0.0.1]/"});
+ checkURLDifferences("http://[a:b::c:d:e:f:127.0.0.1]",
+ {"", "", "", "", 0, "", "", "", "http://[a:b::c:d:e:f:127.0.0.1]"},
+ {"http", "", "", "[a:b::c:d:e:f:127.0.0.1]", 0, "/", "", "", "http://[a:b::c:d:e:f:127.0.0.1]/"});
+ checkURLDifferences("http://[a:b:c:d:e:127.0.0.1]",
+ {"", "", "", "", 0, "", "", "", "http://[a:b:c:d:e:127.0.0.1]"},
+ {"http", "", "", "[a:b:c:d:e:127.0.0.1]", 0, "/", "", "", "http://[a:b:c:d:e:127.0.0.1]/"});
+ checkURLDifferences("http://[a:b:c:d:e:f:127.0.0.0.1]",
+ {"", "", "", "", 0, "", "", "", "http://[a:b:c:d:e:f:127.0.0.0.1]"},
+ {"http", "", "", "[a:b:c:d:e:f:127.0.0.0.1]", 0, "/", "", "", "http://[a:b:c:d:e:f:127.0.0.0.1]/"});
+ checkURLDifferences("http://[a:b:c:d:e:f:127.0.1]",
+ {"", "", "", "", 0, "", "", "", "http://[a:b:c:d:e:f:127.0.1]"},
+ {"http", "", "", "[a:b:c:d:e:f:127.0.1]", 0, "/", "", "", "http://[a:b:c:d:e:f:127.0.1]/"});
+ checkURLDifferences("http://[a:b:c:d:e:f:127.0.0.011]", // Chrome treats this as octal, Firefox and the spec fail
+ {"", "", "", "", 0, "", "", "", "http://[a:b:c:d:e:f:127.0.0.011]"},
+ {"http", "", "", "[a:b:c:d:e:f:127.0.0.011]", 0, "/", "", "", "http://[a:b:c:d:e:f:127.0.0.011]/"});
+ checkURLDifferences("http://[a:b:c:d:e:f:127.0.00.1]",
+ {"", "", "", "", 0, "", "", "", "http://[a:b:c:d:e:f:127.0.00.1]"},
+ {"http", "", "", "[a:b:c:d:e:f:127.0.00.1]", 0, "/", "", "", "http://[a:b:c:d:e:f:127.0.00.1]/"});
+ checkURLDifferences("http://[a:b:c:d:e:f:127.0.0.1.]",
+ {"", "", "", "", 0, "", "", "", "http://[a:b:c:d:e:f:127.0.0.1.]"},
+ {"http", "", "", "[a:b:c:d:e:f:127.0.0.1.]", 0, "/", "", "", "http://[a:b:c:d:e:f:127.0.0.1.]/"});
+ checkURLDifferences("http://[a:b:c:d:e:f:127.0..0.1]",
+ {"", "", "", "", 0, "", "", "", "http://[a:b:c:d:e:f:127.0..0.1]"},
+ {"http", "", "", "[a:b:c:d:e:f:127.0..0.1]", 0, "/", "", "", "http://[a:b:c:d:e:f:127.0..0.1]/"});
+ checkURLDifferences("http://[a:b:c:d:e:f::127.0.0.1]",
+ {"", "", "", "", 0, "", "", "", "http://[a:b:c:d:e:f::127.0.0.1]"},
+ {"http", "", "", "[a:b:c:d:e:f::127.0.0.1]", 0, "/", "", "", "http://[a:b:c:d:e:f::127.0.0.1]/"});
+ checkURLDifferences("http://[a:b:c:d:e::127.0.0.1]",
+ {"http", "", "", "[a:b:c:d:e:0:7f00:1]", 0, "/", "", "", "http://[a:b:c:d:e:0:7f00:1]/"},
+ {"http", "", "", "[a:b:c:d:e::127.0.0.1]", 0, "/", "", "", "http://[a:b:c:d:e::127.0.0.1]/"});
+ checkURLDifferences("http://[a:b:c:d::e:127.0.0.1]",
+ {"http", "", "", "[a:b:c:d:0:e:7f00:1]", 0, "/", "", "", "http://[a:b:c:d:0:e:7f00:1]/"},
+ {"http", "", "", "[a:b:c:d::e:127.0.0.1]", 0, "/", "", "", "http://[a:b:c:d::e:127.0.0.1]/"});
+ checkURLDifferences("http://[a:b:c:d:e:f::127.0.0.]",
+ {"", "", "", "", 0, "", "", "", "http://[a:b:c:d:e:f::127.0.0.]"},
+ {"http", "", "", "[a:b:c:d:e:f::127.0.0.]", 0, "/", "", "", "http://[a:b:c:d:e:f::127.0.0.]/"});
+ checkURLDifferences("http://[a:b:c:d:e:f::127.0.0.256]",
+ {"", "", "", "", 0, "", "", "", "http://[a:b:c:d:e:f::127.0.0.256]"},
+ {"http", "", "", "[a:b:c:d:e:f::127.0.0.256]", 0, "/", "", "", "http://[a:b:c:d:e:f::127.0.0.256]/"});
+ checkURLDifferences("http://123456", {"http", "", "", "0.1.226.64", 0, "/", "", "", "http://0.1.226.64/"}, {"http", "", "", "123456", 0, "/", "", "", "http://123456/"});
+ checkURL("asdf://123456", {"asdf", "", "", "123456", 0, "", "", "", "asdf://123456"});
+ checkURLDifferences("http://[0:0:0:0:a:b:c:d]",
+ {"http", "", "", "[::a:b:c:d]", 0, "/", "", "", "http://[::a:b:c:d]/"},
+ {"http", "", "", "[0:0:0:0:a:b:c:d]", 0, "/", "", "", "http://[0:0:0:0:a:b:c:d]/"});
+ checkURLDifferences("asdf://[0:0:0:0:a:b:c:d]",
+ {"asdf", "", "", "[::a:b:c:d]", 0, "", "", "", "asdf://[::a:b:c:d]"},
+ {"asdf", "", "", "[0:0:0:0:a:b:c:d]", 0, "", "", "", "asdf://[0:0:0:0:a:b:c:d]"}, TestTabs::No);
+ shouldFail("a://%:a");
+ checkURL("a://%:/", {"a", "", "", "%", 0, "/", "", "", "a://%/"});
+ checkURL("a://%:", {"a", "", "", "%", 0, "", "", "", "a://%"});
+ checkURL("a://%:1/", {"a", "", "", "%", 1, "/", "", "", "a://%:1/"});
+ checkURLDifferences("http://%:",
+ {"", "", "", "", 0, "", "", "", "http://%:"},
+ {"http", "", "", "%", 0, "/", "", "", "http://%/"});
+ checkURL("a://123456", {"a", "", "", "123456", 0, "", "", "", "a://123456"});
+ checkURL("a://123456:7", {"a", "", "", "123456", 7, "", "", "", "a://123456:7"});
+ checkURL("a://123456:7/", {"a", "", "", "123456", 7, "/", "", "", "a://123456:7/"});
+ checkURL("a://A", {"a", "", "", "A", 0, "", "", "", "a://A"});
+ checkURL("a://A:2", {"a", "", "", "A", 2, "", "", "", "a://A:2"});
+ checkURL("a://A:2/", {"a", "", "", "A", 2, "/", "", "", "a://A:2/"});
+ checkURLDifferences(u8"asd://ß",
+ {"asd", "", "", "%C3%83%C2%9F", 0, "", "", "", "asd://%C3%83%C2%9F"},
+ {"", "", "", "", 0, "", "", "", "about:blank"}, TestTabs::No);
+ checkURLDifferences(u8"asd://ß:4",
+ {"asd", "", "", "%C3%83%C2%9F", 4, "", "", "", "asd://%C3%83%C2%9F:4"},
+ {"", "", "", "", 0, "", "", "", "about:blank"}, TestTabs::No);
+ checkURLDifferences(u8"asd://ß:4/",
+ {"asd", "", "", "%C3%83%C2%9F", 4, "/", "", "", "asd://%C3%83%C2%9F:4/"},
+ {"", "", "", "", 0, "", "", "", "about:blank"}, TestTabs::No);
+ checkURLDifferences("a://[A::b]:4",
+ {"a", "", "", "[a::b]", 4, "", "", "", "a://[a::b]:4"},
+ {"a", "", "", "[A::b]", 4, "", "", "", "a://[A::b]:4"});
+ shouldFail("http://[~]");
+ shouldFail("a://[~]");
+ checkRelativeURLDifferences("a://b", "//[aBc]",
+ {"a", "", "", "b", 0, "", "", "", "a://b"},
+ {"", "", "", "", 0, "", "", "", "a://b"});
+ checkURL(utf16String(u"http://öbb.at"), {"http", "", "", "xn--bb-eka.at", 0, "/", "", "", "http://xn--bb-eka.at/"});
+ checkURL(utf16String(u"http://ÖBB.at"), {"http", "", "", "xn--bb-eka.at", 0, "/", "", "", "http://xn--bb-eka.at/"});
+ checkURL(utf16String(u"http://√.com"), {"http", "", "", "xn--19g.com", 0, "/", "", "", "http://xn--19g.com/"});
+ checkURLDifferences(utf16String(u"http://faß.de"),
+ {"http", "", "", "xn--fa-hia.de", 0, "/", "", "", "http://xn--fa-hia.de/"},
+ {"http", "", "", "fass.de", 0, "/", "", "", "http://fass.de/"});
+ checkURL(utf16String(u"http://ԛәлп.com"), {"http", "", "", "xn--k1ai47bhi.com", 0, "/", "", "", "http://xn--k1ai47bhi.com/"});
+ checkURLDifferences(utf16String(u"http://Ⱥbby.com"),
+ {"http", "", "", "xn--bby-iy0b.com", 0, "/", "", "", "http://xn--bby-iy0b.com/"},
+ {"http", "", "", "xn--bby-spb.com", 0, "/", "", "", "http://xn--bby-spb.com/"});
+ checkURLDifferences(utf16String(u"http://\u2132"),
+ {"", "", "", "", 0, "", "", "", utf16String(u"http://Ⅎ")},
+ {"http", "", "", "xn--f3g", 0, "/", "", "", "http://xn--f3g/"});
+ checkURLDifferences(utf16String(u"http://\u05D9\u05B4\u05D5\u05D0\u05B8/"),
+ {"http", "", "", "xn--cdbi5etas", 0, "/", "", "", "http://xn--cdbi5etas/"},
+ {"", "", "", "", 0, "", "", "", "about:blank"}, TestTabs::No);
+ checkURLDifferences(utf16String(u"http://bidirectional\u0786\u07AE\u0782\u07B0\u0795\u07A9\u0793\u07A6\u0783\u07AA/"),
+ {"", "", "", "", 0, "", "", "", utf16String(u"http://bidirectionalކޮންޕީޓަރު/")},
+ {"", "", "", "", 0, "", "", "", "about:blank"}, TestTabs::No);
+ checkURLDifferences(utf16String(u"http://contextj\u200D"),
+ {"", "", "", "", 0, "", "", "", utf16String(u"http://contextj\u200D")},
+ {"http", "", "", "contextj", 0, "/", "", "", "http://contextj/"});
+ checkURL(utf16String(u"http://contexto\u30FB"), {"http", "", "", "xn--contexto-wg5g", 0, "/", "", "", "http://xn--contexto-wg5g/"});
+ checkURLDifferences(utf16String(u"http://\u321D\u321E/"),
+ {"http", "", "", "xn--()()-bs0sc174agx4b", 0, "/", "", "", "http://xn--()()-bs0sc174agx4b/"},
+ {"http", "", "", "xn--5mkc", 0, "/", "", "", "http://xn--5mkc/"});
+}
+
+TEST_F(URLParserTest, DefaultPort)
+{
+ checkURL("FtP://host:21/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
+ checkURL("ftp://host:21/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
+ checkURL("f\ttp://host:21/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
+ checkURL("f\ttp://host\t:21/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
+ checkURL("f\ttp://host:\t21/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
+ checkURL("f\ttp://host:2\t1/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
+ checkURL("f\ttp://host:21\t/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
+ checkURL("ftp://host\t:21/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
+ checkURL("ftp://host:\t21/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
+ checkURL("ftp://host:2\t1/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
+ checkURL("ftp://host:21\t/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
+ checkURL("ftp://host:22/", {"ftp", "", "", "host", 22, "/", "", "", "ftp://host:22/"});
+ checkURLDifferences("ftp://host:21",
+ {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"},
+ {"ftp", "", "", "host", 0, "", "", "", "ftp://host"});
+ checkURLDifferences("ftp://host:22",
+ {"ftp", "", "", "host", 22, "/", "", "", "ftp://host:22/"},
+ {"ftp", "", "", "host", 22, "", "", "", "ftp://host:22"});
+
+ checkURL("gOpHeR://host:70/", {"gopher", "", "", "host", 0, "/", "", "", "gopher://host/"});
+ checkURL("gopher://host:70/", {"gopher", "", "", "host", 0, "/", "", "", "gopher://host/"});
+ checkURL("gopher://host:71/", {"gopher", "", "", "host", 71, "/", "", "", "gopher://host:71/"});
+ // Spec, Chrome, Firefox, and URLParser have "/", URL::parse does not.
+ // Spec, Chrome, URLParser, URL::parse recognize gopher default port, Firefox does not.
+ checkURLDifferences("gopher://host:70",
+ {"gopher", "", "", "host", 0, "/", "", "", "gopher://host/"},
+ {"gopher", "", "", "host", 0, "", "", "", "gopher://host"});
+ checkURLDifferences("gopher://host:71",
+ {"gopher", "", "", "host", 71, "/", "", "", "gopher://host:71/"},
+ {"gopher", "", "", "host", 71, "", "", "", "gopher://host:71"});
+
+ checkURL("hTtP://host:80", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
+ checkURL("http://host:80", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
+ checkURL("http://host:80/", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
+ checkURL("http://host:81", {"http", "", "", "host", 81, "/", "", "", "http://host:81/"});
+ checkURL("http://host:81/", {"http", "", "", "host", 81, "/", "", "", "http://host:81/"});
+
+ checkURL("hTtPs://host:443", {"https", "", "", "host", 0, "/", "", "", "https://host/"});
+ checkURL("https://host:443", {"https", "", "", "host", 0, "/", "", "", "https://host/"});
+ checkURL("https://host:443/", {"https", "", "", "host", 0, "/", "", "", "https://host/"});
+ checkURL("https://host:444", {"https", "", "", "host", 444, "/", "", "", "https://host:444/"});
+ checkURL("https://host:444/", {"https", "", "", "host", 444, "/", "", "", "https://host:444/"});
+
+ checkURL("wS://host:80/", {"ws", "", "", "host", 0, "/", "", "", "ws://host/"});
+ checkURL("ws://host:80/", {"ws", "", "", "host", 0, "/", "", "", "ws://host/"});
+ checkURL("ws://host:81/", {"ws", "", "", "host", 81, "/", "", "", "ws://host:81/"});
+ // URLParser matches Chrome and Firefox, but not URL::parse
+ checkURLDifferences("ws://host:80",
+ {"ws", "", "", "host", 0, "/", "", "", "ws://host/"},
+ {"ws", "", "", "host", 0, "", "", "", "ws://host"});
+ checkURLDifferences("ws://host:81",
+ {"ws", "", "", "host", 81, "/", "", "", "ws://host:81/"},
+ {"ws", "", "", "host", 81, "", "", "", "ws://host:81"});
+
+ checkURL("WsS://host:443/", {"wss", "", "", "host", 0, "/", "", "", "wss://host/"});
+ checkURL("wss://host:443/", {"wss", "", "", "host", 0, "/", "", "", "wss://host/"});
+ checkURL("wss://host:444/", {"wss", "", "", "host", 444, "/", "", "", "wss://host:444/"});
+ // URLParser matches Chrome and Firefox, but not URL::parse
+ checkURLDifferences("wss://host:443",
+ {"wss", "", "", "host", 0, "/", "", "", "wss://host/"},
+ {"wss", "", "", "host", 0, "", "", "", "wss://host"});
+ checkURLDifferences("wss://host:444",
+ {"wss", "", "", "host", 444, "/", "", "", "wss://host:444/"},
+ {"wss", "", "", "host", 444, "", "", "", "wss://host:444"});
+
+ checkURL("fTpS://host:990/", {"ftps", "", "", "host", 990, "/", "", "", "ftps://host:990/"});
+ checkURL("ftps://host:990/", {"ftps", "", "", "host", 990, "/", "", "", "ftps://host:990/"});
+ checkURL("ftps://host:991/", {"ftps", "", "", "host", 991, "/", "", "", "ftps://host:991/"});
+ checkURL("ftps://host:990", {"ftps", "", "", "host", 990, "", "", "", "ftps://host:990"});
+ checkURL("ftps://host:991", {"ftps", "", "", "host", 991, "", "", "", "ftps://host:991"});
+
+ checkURL("uNkNoWn://host:80/", {"unknown", "", "", "host", 80, "/", "", "", "unknown://host:80/"});
+ checkURL("unknown://host:80/", {"unknown", "", "", "host", 80, "/", "", "", "unknown://host:80/"});
+ checkURL("unknown://host:81/", {"unknown", "", "", "host", 81, "/", "", "", "unknown://host:81/"});
+ checkURL("unknown://host:80", {"unknown", "", "", "host", 80, "", "", "", "unknown://host:80"});
+ checkURL("unknown://host:81", {"unknown", "", "", "host", 81, "", "", "", "unknown://host:81"});
+
+ checkURL("file://host:0", {"file", "", "", "host", 0, "/", "", "", "file://host:0/"});
+ checkURL("file://host:80", {"file", "", "", "host", 80, "/", "", "", "file://host:80/"});
+ checkURL("file://host:80/path", {"file", "", "", "host", 80, "/path", "", "", "file://host:80/path"});
+ checkURLDifferences("file://:80/path",
+ {"", "", "", "", 0, "", "", "", "file://:80/path"},
+ {"file", "", "", "", 80, "/path", "", "", "file://:80/path"});
+ checkURLDifferences("file://:0/path",
+ {"", "", "", "", 0, "", "", "", "file://:0/path"},
+ {"file", "", "", "", 0, "/path", "", "", "file://:0/path"});
+}
+
+TEST_F(URLParserTest, ParserFailures)
+{
+ shouldFail(" ");
+ shouldFail(" \a ");
+ shouldFail("");
+ shouldFail(String());
+ shouldFail("", "about:blank");
+ shouldFail(String(), "about:blank");
+ shouldFail("http://127.0.0.1:abc");
+ shouldFail("http://host:abc");
+ shouldFail("http://:abc");
+ shouldFail("http://a:@", "about:blank");
+ shouldFail("http://:b@", "about:blank");
+ shouldFail("http://:@", "about:blank");
+ shouldFail("http://a:@");
+ shouldFail("http://:b@");
+ shouldFail("http://@");
+ shouldFail("http://[0:f::f:f:0:0]:abc");
+ shouldFail("../i", "sc:sd");
+ shouldFail("../i", "sc:sd/sd");
+ shouldFail("/i", "sc:sd");
+ shouldFail("/i", "sc:sd/sd");
+ shouldFail("?i", "sc:sd");
+ shouldFail("?i", "sc:sd/sd");
+ shouldFail("http://example example.com", "http://other.com/");
+ shouldFail("http://[www.example.com]/", "about:blank");
+ shouldFail("http://192.168.0.1 hello", "http://other.com/");
+ shouldFail("http://[example.com]", "http://other.com/");
+ shouldFail("i", "sc:sd");
+ shouldFail("i", "sc:sd/sd");
+ shouldFail("i");
+ shouldFail("asdf");
+ shouldFail("~");
+ shouldFail("%");
+ shouldFail("//%");
+ shouldFail("~", "about:blank");
+ shouldFail("~~~");
+ shouldFail("://:0/");
+ shouldFail("://:0/", "");
+ shouldFail("://:0/", "about:blank");
+ shouldFail("about~");
+ shouldFail("//C:asdf/foo/bar", "file:///tmp/mock/path");
+ shouldFail("http://[1234::ab#]");
+ shouldFail("http://[1234::ab/]");
+ shouldFail("http://[1234::ab?]");
+ shouldFail("http://[1234::ab@]");
+ shouldFail("http://[1234::ab~]");
+ shouldFail("http://[2001::1");
+ shouldFail("http://4:b\xE1");
+ shouldFail("http://[1:2:3:4:5:6:7:8~]/");
+ shouldFail("http://[a:b:c:d:e:f:g:127.0.0.1]");
+ shouldFail("http://[a:b:c:d:e:f:g:h:127.0.0.1]");
+ shouldFail("http://[a:b:c:d:e:f:127.0.0.0x11]"); // Chrome treats this as hex, Firefox and the spec fail
+ shouldFail("http://[a:b:c:d:e:f:127.0.-0.1]");
+ shouldFail("asdf://space In\aHost");
+ shouldFail("asdf://[0:0:0:0:a:b:c:d");
+}
+
+// These are in the spec but not in the web platform tests.
+TEST_F(URLParserTest, AdditionalTests)
+{
+ checkURL("about:\a\aabc", {"about", "", "", "", 0, "%07%07abc", "", "", "about:%07%07abc"});
+ checkURL("notspecial:\t\t\n\t", {"notspecial", "", "", "", 0, "", "", "", "notspecial:"});
+ checkURL("notspecial\t\t\n\t:\t\t\n\t/\t\t\n\t/\t\t\n\thost", {"notspecial", "", "", "host", 0, "", "", "", "notspecial://host"});
+ checkRelativeURL("http:", "http://example.org/foo/bar?query#fragment", {"http", "", "", "example.org", 0, "/foo/bar", "query", "", "http://example.org/foo/bar?query"});
+ checkRelativeURLDifferences("ws:", "http://example.org/foo/bar",
+ {"ws", "", "", "", 0, "", "", "", "ws:"},
+ {"ws", "", "", "", 0, "s:", "", "", "ws:s:"});
+ checkRelativeURL("notspecial:", "http://example.org/foo/bar", {"notspecial", "", "", "", 0, "", "", "", "notspecial:"});
+
+ const wchar_t surrogateBegin = 0xD800;
+ const wchar_t validSurrogateEnd = 0xDD55;
+ const wchar_t invalidSurrogateEnd = 'A';
+ checkURL(utf16String<12>({'h', 't', 't', 'p', ':', '/', '/', 'w', '/', surrogateBegin, validSurrogateEnd, '\0'}),
+ {"http", "", "", "w", 0, "/%F0%90%85%95", "", "", "http://w/%F0%90%85%95"}, testTabsValueForSurrogatePairs);
+
+ // URLParser matches Chrome and Firefox but not URL::parse.
+ checkURLDifferences(utf16String<12>({'h', 't', 't', 'p', ':', '/', '/', 'w', '/', surrogateBegin, invalidSurrogateEnd}),
+ {"http", "", "", "w", 0, "/%EF%BF%BDA", "", "", "http://w/%EF%BF%BDA"},
+ {"http", "", "", "w", 0, "/%ED%A0%80A", "", "", "http://w/%ED%A0%80A"});
+ checkURLDifferences(utf16String<13>({'h', 't', 't', 'p', ':', '/', '/', 'w', '/', '?', surrogateBegin, invalidSurrogateEnd, '\0'}),
+ {"http", "", "", "w", 0, "/", "%EF%BF%BDA", "", "http://w/?%EF%BF%BDA"},
+ {"http", "", "", "w", 0, "/", "%ED%A0%80A", "", "http://w/?%ED%A0%80A"});
+ checkURLDifferences(utf16String<11>({'h', 't', 't', 'p', ':', '/', '/', 'w', '/', surrogateBegin, '\0'}),
+ {"http", "", "", "w", 0, "/%EF%BF%BD", "", "", "http://w/%EF%BF%BD"},
+ {"http", "", "", "w", 0, "/%ED%A0%80", "", "", "http://w/%ED%A0%80"});
+ checkURLDifferences(utf16String<12>({'h', 't', 't', 'p', ':', '/', '/', 'w', '/', '?', surrogateBegin, '\0'}),
+ {"http", "", "", "w", 0, "/", "%EF%BF%BD", "", "http://w/?%EF%BF%BD"},
+ {"http", "", "", "w", 0, "/", "%ED%A0%80", "", "http://w/?%ED%A0%80"});
+ checkURLDifferences(utf16String<13>({'h', 't', 't', 'p', ':', '/', '/', 'w', '/', '?', surrogateBegin, ' ', '\0'}),
+ {"http", "", "", "w", 0, "/", "%EF%BF%BD", "", "http://w/?%EF%BF%BD"},
+ {"http", "", "", "w", 0, "/", "%ED%A0%80", "", "http://w/?%ED%A0%80"});
+
+ // FIXME: Write more invalid surrogate pair tests based on feedback from https://bugs.webkit.org/show_bug.cgi?id=162105
+}
+
+TEST_F(URLParserTest, QueryEncoding)
+{
+ checkURL(utf16String(u"http://host?ß😍#ß😍"), UTF8Encoding(), {"http", "", "", "host", 0, "/", "%C3%9F%F0%9F%98%8D", "%C3%9F%F0%9F%98%8D", utf16String(u"http://host/?%C3%9F%F0%9F%98%8D#%C3%9F%F0%9F%98%8D")}, testTabsValueForSurrogatePairs);
+
+ TextEncoding latin1(String("latin1"));
+ checkURL("http://host/?query with%20spaces", latin1, {"http", "", "", "host", 0, "/", "query%20with%20spaces", "", "http://host/?query%20with%20spaces"});
+ checkURL("http://host/?query", latin1, {"http", "", "", "host", 0, "/", "query", "", "http://host/?query"});
+ checkURL("http://host/?\tquery", latin1, {"http", "", "", "host", 0, "/", "query", "", "http://host/?query"});
+ checkURL("http://host/?q\tuery", latin1, {"http", "", "", "host", 0, "/", "query", "", "http://host/?query"});
+ checkURL("http://host/?query with SpAcEs#fragment", latin1, {"http", "", "", "host", 0, "/", "query%20with%20SpAcEs", "fragment", "http://host/?query%20with%20SpAcEs#fragment"});
+ checkURL("http://host/?que\rry\t\r\n#fragment", latin1, {"http", "", "", "host", 0, "/", "query", "fragment", "http://host/?query#fragment"});
+
+ TextEncoding unrecognized(String("unrecognized invalid encoding name"));
+ checkURL("http://host/?query", unrecognized, {"http", "", "", "host", 0, "/", "", "", "http://host/?"});
+ checkURL("http://host/?", unrecognized, {"http", "", "", "host", 0, "/", "", "", "http://host/?"});
+
+ TextEncoding iso88591(String("ISO-8859-1"));
+ String withUmlauts = utf16String<4>({0xDC, 0x430, 0x451, '\0'});
+ checkURL(makeString("ws://host/path?", withUmlauts), iso88591, {"ws", "", "", "host", 0, "/path", "%C3%9C%D0%B0%D1%91", "", "ws://host/path?%C3%9C%D0%B0%D1%91"});
+ checkURL(makeString("wss://host/path?", withUmlauts), iso88591, {"wss", "", "", "host", 0, "/path", "%C3%9C%D0%B0%D1%91", "", "wss://host/path?%C3%9C%D0%B0%D1%91"});
+ checkURL(makeString("asdf://host/path?", withUmlauts), iso88591, {"asdf", "", "", "host", 0, "/path", "%C3%9C%D0%B0%D1%91", "", "asdf://host/path?%C3%9C%D0%B0%D1%91"});
+ checkURL(makeString("https://host/path?", withUmlauts), iso88591, {"https", "", "", "host", 0, "/path", "%DC%26%231072%3B%26%231105%3B", "", "https://host/path?%DC%26%231072%3B%26%231105%3B"});
+ checkURL(makeString("gopher://host/path?", withUmlauts), iso88591, {"gopher", "", "", "host", 0, "/path", "%DC%26%231072%3B%26%231105%3B", "", "gopher://host/path?%DC%26%231072%3B%26%231105%3B"});
+ checkURL(makeString("/path?", withUmlauts, "#fragment"), "ws://example.com/", iso88591, {"ws", "", "", "example.com", 0, "/path", "%C3%9C%D0%B0%D1%91", "fragment", "ws://example.com/path?%C3%9C%D0%B0%D1%91#fragment"});
+ checkURL(makeString("/path?", withUmlauts, "#fragment"), "wss://example.com/", iso88591, {"wss", "", "", "example.com", 0, "/path", "%C3%9C%D0%B0%D1%91", "fragment", "wss://example.com/path?%C3%9C%D0%B0%D1%91#fragment"});
+ checkURL(makeString("/path?", withUmlauts, "#fragment"), "asdf://example.com/", iso88591, {"asdf", "", "", "example.com", 0, "/path", "%C3%9C%D0%B0%D1%91", "fragment", "asdf://example.com/path?%C3%9C%D0%B0%D1%91#fragment"});
+ checkURL(makeString("/path?", withUmlauts, "#fragment"), "https://example.com/", iso88591, {"https", "", "", "example.com", 0, "/path", "%DC%26%231072%3B%26%231105%3B", "fragment", "https://example.com/path?%DC%26%231072%3B%26%231105%3B#fragment"});
+ checkURL(makeString("/path?", withUmlauts, "#fragment"), "gopher://example.com/", iso88591, {"gopher", "", "", "example.com", 0, "/path", "%DC%26%231072%3B%26%231105%3B", "fragment", "gopher://example.com/path?%DC%26%231072%3B%26%231105%3B#fragment"});
+ checkURL(makeString("gopher://host/path?", withUmlauts, "#fragment"), "asdf://example.com/?doesntmatter", iso88591, {"gopher", "", "", "host", 0, "/path", "%DC%26%231072%3B%26%231105%3B", "fragment", "gopher://host/path?%DC%26%231072%3B%26%231105%3B#fragment"});
+ checkURL(makeString("asdf://host/path?", withUmlauts, "#fragment"), "http://example.com/?doesntmatter", iso88591, {"asdf", "", "", "host", 0, "/path", "%C3%9C%D0%B0%D1%91", "fragment", "asdf://host/path?%C3%9C%D0%B0%D1%91#fragment"});
+
+ checkURL("http://host/?query=foo'bar", UTF8Encoding(), {"http", "", "", "host", 0, "/", "query=foo%27bar", "", "http://host/?query=foo%27bar"});
+ // FIXME: Add more tests with other encodings and things like non-ascii characters, emoji and unmatched surrogate pairs.
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/UserAgentQuirks.cpp b/Tools/TestWebKitAPI/Tests/WebCore/UserAgentQuirks.cpp
new file mode 100644
index 000000000..7fff8e361
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/UserAgentQuirks.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <WebCore/URL.h>
+#include <WebCore/UserAgent.h>
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+static void assertUserAgentForURLHasChromeBrowserQuirk(const char* url)
+{
+ String uaString = standardUserAgentForURL(URL(ParsedURLString, url));
+
+ EXPECT_TRUE(uaString.contains("Chrome"));
+ EXPECT_TRUE(uaString.contains("Safari"));
+ EXPECT_FALSE(uaString.contains("Chromium"));
+ EXPECT_FALSE(uaString.contains("Firefox"));
+}
+
+static void assertUserAgentForURLHasLinuxPlatformQuirk(const char* url)
+{
+ String uaString = standardUserAgentForURL(URL(ParsedURLString, url));
+
+ EXPECT_TRUE(uaString.contains("Linux"));
+ EXPECT_FALSE(uaString.contains("Macintosh"));
+ EXPECT_FALSE(uaString.contains("Mac OS X"));
+ EXPECT_FALSE(uaString.contains("Windows"));
+ EXPECT_FALSE(uaString.contains("Chrome"));
+ EXPECT_FALSE(uaString.contains("FreeBSD"));
+}
+
+static void assertUserAgentForURLHasMacPlatformQuirk(const char* url)
+{
+ String uaString = standardUserAgentForURL(URL(ParsedURLString, url));
+
+ EXPECT_TRUE(uaString.contains("Macintosh"));
+ EXPECT_TRUE(uaString.contains("Mac OS X"));
+ EXPECT_FALSE(uaString.contains("Linux"));
+ EXPECT_FALSE(uaString.contains("Windows"));
+ EXPECT_FALSE(uaString.contains("Chrome"));
+ EXPECT_FALSE(uaString.contains("FreeBSD"));
+}
+
+TEST(UserAgentTest, Quirks)
+{
+ // A site with not quirks should return a null String.
+ String uaString = standardUserAgentForURL(URL(ParsedURLString, "http://www.webkit.org/"));
+ EXPECT_TRUE(uaString.isNull());
+
+#if !OS(LINUX) || !CPU(X86_64)
+ // Google quirk should not affect sites with similar domains.
+ uaString = standardUserAgentForURL(URL(ParsedURLString, "http://www.googleblog.com/"));
+ EXPECT_FALSE(uaString.contains("Linux x86_64"));
+#endif
+
+ assertUserAgentForURLHasChromeBrowserQuirk("http://typekit.com/");
+ assertUserAgentForURLHasChromeBrowserQuirk("http://typekit.net/");
+
+ assertUserAgentForURLHasLinuxPlatformQuirk("http://www.google.com/");
+ assertUserAgentForURLHasLinuxPlatformQuirk("http://www.google.es/");
+ assertUserAgentForURLHasLinuxPlatformQuirk("http://calendar.google.com/");
+ assertUserAgentForURLHasLinuxPlatformQuirk("http://plus.google.com/");
+
+ assertUserAgentForURLHasMacPlatformQuirk("http://www.yahoo.com/");
+ assertUserAgentForURLHasMacPlatformQuirk("http://finance.yahoo.com/");
+ assertUserAgentForURLHasMacPlatformQuirk("http://intl.taobao.com/");
+ assertUserAgentForURLHasMacPlatformQuirk("http://www.whatsapp.com/");
+ assertUserAgentForURLHasMacPlatformQuirk("http://web.whatsapp.com/");
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/YouTubePluginReplacement.cpp b/Tools/TestWebKitAPI/Tests/WebCore/YouTubePluginReplacement.cpp
new file mode 100644
index 000000000..76b103575
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebCore/YouTubePluginReplacement.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include <WebCore/URL.h>
+#include <WebCore/YouTubePluginReplacement.h>
+#include <wtf/MainThread.h>
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+class YouTubePluginReplacementTest : public testing::Test {
+public:
+ void SetUp() final {
+ WTF::initializeMainThread();
+ }
+};
+
+static bool test(const String& inputURLString, const String& expectedURLString)
+{
+ URL inputURL(URL(), inputURLString);
+ String actualURLString = YouTubePluginReplacement::youTubeURLFromAbsoluteURL(inputURL, inputURLString);
+ return actualURLString.utf8() == expectedURLString.utf8();
+}
+
+TEST_F(YouTubePluginReplacementTest, YouTubeURLFromAbsoluteURL)
+{
+ // YouTube non-video URL, not expected to be transformed.
+ EXPECT_TRUE(test("https://www.youtube.com", "https://www.youtube.com"));
+
+ // Basic YouTube video links, expected to be transformed.
+ EXPECT_TRUE(test("https://www.youtube.com/v/dQw4w9WgXcQ", "https://www.youtube.com/embed/dQw4w9WgXcQ"));
+ EXPECT_TRUE(test("http://www.youtube.com/v/dQw4w9WgXcQ", "http://www.youtube.com/embed/dQw4w9WgXcQ"));
+ EXPECT_TRUE(test("https://youtube.com/v/dQw4w9WgXcQ", "https://youtube.com/embed/dQw4w9WgXcQ"));
+ EXPECT_TRUE(test("http://youtube.com/v/dQw4w9WgXcQ", "http://youtube.com/embed/dQw4w9WgXcQ"));
+
+ // With start time, preserved.
+ EXPECT_TRUE(test("http://www.youtube.com/v/dQw4w9WgXcQ?start=4", "http://www.youtube.com/embed/dQw4w9WgXcQ?start=4"));
+ EXPECT_TRUE(test("http://www.youtube.com/v/dQw4w9WgXcQ?start=4&fs=1", "http://www.youtube.com/embed/dQw4w9WgXcQ?start=4&fs=1"));
+
+ // With an invalid query (see & instead of ?), we preserve and fix the query.
+ EXPECT_TRUE(test("http://www.youtube.com/v/dQw4w9WgXcQ&start=4", "http://www.youtube.com/embed/dQw4w9WgXcQ?start=4"));
+ EXPECT_TRUE(test("http://www.youtube.com/v/dQw4w9WgXcQ&start=4&fs=1", "http://www.youtube.com/embed/dQw4w9WgXcQ?start=4&fs=1"));
+
+ // Non-Flash URL is untouched.
+ EXPECT_TRUE(test("https://www.youtube.com/embed/dQw4w9WgXcQ", "https://www.youtube.com/embed/dQw4w9WgXcQ"));
+ EXPECT_TRUE(test("http://www.youtube.com/embed/dQw4w9WgXcQ", "http://www.youtube.com/embed/dQw4w9WgXcQ"));
+ EXPECT_TRUE(test("https://youtube.com/embed/dQw4w9WgXcQ", "https://youtube.com/embed/dQw4w9WgXcQ"));
+ EXPECT_TRUE(test("http://youtube.com/embed/dQw4w9WgXcQ", "http://youtube.com/embed/dQw4w9WgXcQ"));
+ // Even with extra parameters.
+ EXPECT_TRUE(test("https://www.youtube.com/embed/dQw4w9WgXcQ?start=4", "https://www.youtube.com/embed/dQw4w9WgXcQ?start=4"));
+ EXPECT_TRUE(test("http://www.youtube.com/embed/dQw4w9WgXcQ?enablejsapi=1", "http://www.youtube.com/embed/dQw4w9WgXcQ?enablejsapi=1"));
+ // Even with an invalid "query".
+ EXPECT_TRUE(test("https://www.youtube.com/embed/dQw4w9WgXcQ&start=4", "https://www.youtube.com/embed/dQw4w9WgXcQ&start=4"));
+
+ // Don't transform anything with a non "/v/" path component immediately following the domain.
+ EXPECT_TRUE(test("https://www.youtube.com/something/v/dQw4w9WgXcQ", "https://www.youtube.com/something/v/dQw4w9WgXcQ"));
+
+ // Non-YouTube domain whose path looks like a Flash video shouldn't be transformed.
+ EXPECT_TRUE(test("https://www.notyoutube.com/v/dQw4w9WgXcQ", "https://www.notyoutube.com/v/dQw4w9WgXcQ"));
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/gtk/UserAgentQuirks.cpp b/Tools/TestWebKitAPI/Tests/WebCore/gtk/UserAgentQuirks.cpp
deleted file mode 100644
index 40305e801..000000000
--- a/Tools/TestWebKitAPI/Tests/WebCore/gtk/UserAgentQuirks.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2014 Igalia S.L.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#include <WebCore/URL.h>
-#include <WebCore/UserAgentGtk.h>
-
-using namespace WebCore;
-
-namespace TestWebKitAPI {
-
-TEST(WebCore, UserAgentQuirksTest)
-{
- // A site with not quirks should return a null String.
- String uaString = standardUserAgentForURL(URL(ParsedURLString, "http://www.webkit.org/"));
- EXPECT_TRUE(uaString.isNull());
-
- // www.yahoo.com requires MAC OS platform in the UA.
- uaString = standardUserAgentForURL(URL(ParsedURLString, "http://www.yahoo.com/"));
- EXPECT_TRUE(uaString.contains("Macintosh"));
- EXPECT_TRUE(uaString.contains("Mac OS X"));
- EXPECT_FALSE(uaString.contains("Linux"));
-
- // For Google domains we always return the standard UA.
- uaString = standardUserAgent();
- EXPECT_FALSE(uaString.isNull());
- EXPECT_TRUE(uaString == standardUserAgentForURL(URL(ParsedURLString, "http://www.google.com/")));
- EXPECT_TRUE(uaString == standardUserAgentForURL(URL(ParsedURLString, "http://calendar.google.com/")));
- EXPECT_TRUE(uaString == standardUserAgentForURL(URL(ParsedURLString, "http://gmail.com/")));
- EXPECT_TRUE(uaString == standardUserAgentForURL(URL(ParsedURLString, "http://www.google.com.br/")));
- EXPECT_TRUE(uaString == standardUserAgentForURL(URL(ParsedURLString, "http://www.youtube.com/")));
- EXPECT_TRUE(uaString != standardUserAgentForURL(URL(ParsedURLString, "http://www.google.uk.not.com.br/")));
-
- // For Google Maps we remove the Version/8.0 string.
- uaString = standardUserAgentForURL(URL(ParsedURLString, "http://maps.google.com/"));
- EXPECT_TRUE(uaString == standardUserAgentForURL(URL(ParsedURLString, "http://www.google.com/maps/")));
- EXPECT_FALSE(uaString.contains("Version/8.0 Safari/"));
-}
-
-} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/18-characters.html b/Tools/TestWebKitAPI/Tests/WebKit2/18-characters.html
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/18-characters.html
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/AboutBlankLoad.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/AboutBlankLoad.cpp
index 0a2f00ca5..5503edd9e 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/AboutBlankLoad.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/AboutBlankLoad.cpp
@@ -24,6 +24,9 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
@@ -57,3 +60,5 @@ TEST(WebKit2, AboutBlankLoad)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/Ahem.ttf b/Tools/TestWebKitAPI/Tests/WebKit2/Ahem.ttf
new file mode 100644
index 000000000..ac81cb031
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/Ahem.ttf
Binary files differ
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/CanHandleRequest.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/CanHandleRequest.cpp
index 4c0c77963..a1d09f2cd 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/CanHandleRequest.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/CanHandleRequest.cpp
@@ -24,9 +24,12 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
-#include <WebKit2/WKContextPrivate.h>
+#include <WebKit/WKContextPrivate.h>
namespace TestWebKitAPI {
@@ -71,3 +74,5 @@ TEST(WebKit2, CanHandleRequest)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/CanHandleRequest_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/CanHandleRequest_Bundle.cpp
index 5f66b537a..590615e8c 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/CanHandleRequest_Bundle.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/CanHandleRequest_Bundle.cpp
@@ -24,10 +24,13 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "InjectedBundleTest.h"
#include "PlatformUtilities.h"
-#include <WebKit2/WKBundlePage.h>
+#include <WebKit/WKBundlePage.h>
namespace TestWebKitAPI {
@@ -65,3 +68,5 @@ void CanHandleRequestTest::didReceiveMessage(WKBundleRef bundle, WKStringRef mes
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/CloseFromWithinCreatePage.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/CloseFromWithinCreatePage.cpp
new file mode 100644
index 000000000..fabfd2d80
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/CloseFromWithinCreatePage.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include <WebKit/WKPreferencesRefPrivate.h>
+
+namespace TestWebKitAPI {
+
+static bool testDone;
+static std::unique_ptr<PlatformWebView> openedWebView;
+
+static void runJavaScriptAlert(WKPageRef page, WKStringRef alertText, WKFrameRef frame, WKSecurityOriginRef, const void* clientInfo)
+{
+ // FIXME: Check that the alert text matches the storage.
+ testDone = true;
+}
+
+static WKPageRef createNewPage(WKPageRef page, WKURLRequestRef urlRequest, WKDictionaryRef features, WKEventModifiers modifiers, WKEventMouseButton mouseButton, const void *clientInfo)
+{
+ EXPECT_TRUE(openedWebView == nullptr);
+
+ openedWebView = std::make_unique<PlatformWebView>(page);
+
+ WKPageUIClientV5 uiClient;
+ memset(&uiClient, 0, sizeof(uiClient));
+
+ uiClient.base.version = 5;
+ uiClient.runJavaScriptAlert = runJavaScriptAlert;
+ WKPageSetPageUIClient(openedWebView->page(), &uiClient.base);
+
+ WKPageClose(page);
+
+ WKRetain(openedWebView->page());
+ return openedWebView->page();
+}
+
+TEST(WebKit2, CloseFromWithinCreatePage)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+
+ PlatformWebView webView(context.get());
+
+ WKPageUIClientV5 uiClient;
+ memset(&uiClient, 0, sizeof(uiClient));
+
+ uiClient.base.version = 5;
+ uiClient.createNewPage = createNewPage;
+ uiClient.runJavaScriptAlert = runJavaScriptAlert;
+ WKPageSetPageUIClient(webView.page(), &uiClient.base);
+
+ // Allow file URLs to load non-file resources
+ WKRetainPtr<WKPreferencesRef> preferences(AdoptWK, WKPreferencesCreate());
+ WKPageGroupRef pageGroup = WKPageGetPageGroup(webView.page());
+ WKPreferencesSetUniversalAccessFromFileURLsAllowed(preferences.get(), true);
+ WKPageGroupSetPreferences(pageGroup, preferences.get());
+
+ WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("close-from-within-create-page", "html"));
+ WKPageLoadURL(webView.page(), url.get());
+
+ Util::run(&testDone);
+
+ openedWebView = nullptr;
+}
+
+}
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/CloseThenTerminate.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/CloseThenTerminate.cpp
index ff70511f4..71239e4f0 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/CloseThenTerminate.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/CloseThenTerminate.cpp
@@ -24,6 +24,9 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
@@ -62,3 +65,5 @@ TEST(WebKit2, CloseThenTerminate)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/CookieManager.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/CookieManager.cpp
index 2f17b8162..d231e0e75 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/CookieManager.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/CookieManager.cpp
@@ -24,10 +24,13 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
-#include <WebKit2/WKCookieManager.h>
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKCookieManager.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -86,3 +89,5 @@ TEST(WebKit2, CookieManager)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/WKViewIsActiveSetIsActive.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/WKViewIsActiveSetIsActive.cpp
new file mode 100644
index 000000000..ef9625b99
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/WKViewIsActiveSetIsActive.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PlatformUtilities.h"
+#include "Test.h"
+
+#include <WebKit/WKContext.h>
+#include <WebKit/WKPage.h>
+#include <WebKit/WKRetainPtr.h>
+#include <WebKit/WKView.h>
+
+namespace TestWebKitAPI {
+
+static bool didWebProcessCrash = false;
+static bool didWebProcessRelaunch = false;
+static bool didFinishLoad = false;
+
+static void didFinishLoadForFrame(WKPageRef, WKFrameRef, WKTypeRef, const void*)
+{
+ didFinishLoad = true;
+}
+
+static void webProcessCrashed(WKViewRef view, WKURLRef, const void*)
+{
+ // WebProcess crashed, so at this point the view should not be active.
+ ASSERT_FALSE(WKViewIsActive(view));
+ didWebProcessCrash = true;
+}
+
+static void webProcessRelaunched(WKViewRef view, const void*)
+{
+ // WebProcess just relaunched, so at this point the view should not be active.
+ ASSERT_FALSE(WKViewIsActive(view));
+
+ didWebProcessRelaunch = true;
+}
+
+TEST(WebKit2, WKViewIsActiveSetIsActive)
+{
+ WKRetainPtr<WKContextRef> context = adoptWK(WKContextCreate());
+ WKRetainPtr<WKViewRef> view = adoptWK(WKViewCreate(context.get(), 0));
+
+ WKViewInitialize(view.get());
+
+ // At this point we should have an active view.
+ ASSERT_TRUE(WKViewIsActive(view.get()));
+
+ // Now we are going to play with its active state a few times.
+ WKViewSetIsActive(view.get(), true);
+ ASSERT_TRUE(WKViewIsActive(view.get()));
+
+ WKViewSetIsActive(view.get(), false);
+ ASSERT_FALSE(WKViewIsActive(view.get()));
+
+ WKViewSetIsActive(view.get(), false);
+ ASSERT_FALSE(WKViewIsActive(view.get()));
+
+ WKViewSetIsActive(view.get(), true);
+ ASSERT_TRUE(WKViewIsActive(view.get()));
+}
+
+TEST(WebKit2, WKViewIsActive)
+{
+ WKRetainPtr<WKContextRef> context = adoptWK(Util::createContextForInjectedBundleTest("WKViewIsActiveSetIsActiveTest"));
+ WKRetainPtr<WKViewRef> view = adoptWK(WKViewCreate(context.get(), 0));
+
+ WKViewClientV0 viewClient;
+ memset(&viewClient, 0, sizeof(WKViewClientV0));
+ viewClient.base.version = 0;
+ viewClient.webProcessCrashed = webProcessCrashed;
+ viewClient.webProcessDidRelaunch = webProcessRelaunched;
+ WKViewSetViewClient(view.get(), &viewClient.base);
+
+ WKViewInitialize(view.get());
+
+ // At this point we should have an active view.
+ ASSERT_TRUE(WKViewIsActive(view.get()));
+
+ WKPageLoaderClientV3 pageLoaderClient;
+ memset(&pageLoaderClient, 0, sizeof(WKPageLoaderClient));
+ pageLoaderClient.base.version = 3;
+ pageLoaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+ WKPageSetPageLoaderClient(WKViewGetPage(view.get()), &pageLoaderClient.base);
+
+ const WKSize size = WKSizeMake(100, 100);
+ WKViewSetSize(view.get(), size);
+
+ didFinishLoad = false;
+ didWebProcessCrash = false;
+ didWebProcessRelaunch = false;
+
+ WKRetainPtr<WKURLRef> simpleUrl = adoptWK(Util::createURLForResource("../WebKit/simple", "html"));
+ WKPageLoadURL(WKViewGetPage(view.get()), simpleUrl.get());
+ Util::run(&didFinishLoad);
+ didFinishLoad = false;
+
+ WKContextPostMessageToInjectedBundle(context.get(), Util::toWK("Crash").get(), 0);
+ Util::run(&didWebProcessCrash);
+ ASSERT_TRUE(didWebProcessCrash);
+
+ WKPageLoadURL(WKViewGetPage(view.get()), simpleUrl.get());
+ Util::run(&didFinishLoad);
+
+ ASSERT_TRUE(didWebProcessRelaunch);
+ ASSERT_TRUE(didFinishLoad);
+}
+
+} // TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/WKViewIsActiveSetIsActive_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/WKViewIsActiveSetIsActive_Bundle.cpp
new file mode 100644
index 000000000..a3cb1b6de
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/WKViewIsActiveSetIsActive_Bundle.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "InjectedBundleTest.h"
+#include <WebKit/WKRetainPtr.h>
+
+#include <cstdlib>
+
+namespace TestWebKitAPI {
+
+class WKViewIsActiveSetIsActiveTest : public InjectedBundleTest {
+public:
+ WKViewIsActiveSetIsActiveTest(const std::string& identifier)
+ : InjectedBundleTest(identifier)
+ {
+ }
+
+ virtual void didReceiveMessage(WKBundleRef bundle, WKStringRef messageName, WKTypeRef messageBody)
+ {
+ if (!WKStringIsEqualToUTF8CString(messageName, "Crash"))
+ return;
+ abort();
+ }
+};
+
+static InjectedBundleTest::Register<WKViewIsActiveSetIsActiveTest> registrar("WKViewIsActiveSetIsActiveTest");
+
+} // namespace TestWebKitAPI
+
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/WKViewRestoreZoomAndScrollBackForward.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/WKViewRestoreZoomAndScrollBackForward.cpp
new file mode 100644
index 000000000..5c556ecee
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/WKViewRestoreZoomAndScrollBackForward.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2012-2013 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2011 Samsung Electronics. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "ewk_view_private.h"
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include <WebKit/WKContext.h>
+#include <WebKit/WKRetainPtr.h>
+#include "Test.h"
+
+namespace TestWebKitAPI {
+
+static bool finishedLoad = false;
+static bool scroll = false;
+
+static void didFinishLoadForFrame(WKPageRef, WKFrameRef, WKTypeRef, const void*)
+{
+ finishedLoad = true;
+}
+
+static void didChangeContentsPosition(WKViewRef, WKPoint p, const void*)
+{
+ scroll = true;
+}
+
+TEST(WebKit2, WKViewRestoreZoomAndScrollBackForward)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+ PlatformWebView webView(context.get());
+ WKRetainPtr<WKViewRef> view = EWKViewGetWKView(webView.platformView());
+
+ WKPageSetUseFixedLayout(webView.page(), true);
+
+ WKPageLoaderClientV0 loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+ loaderClient.base.version = 0;
+ loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+ WKPageSetPageLoaderClient(webView.page(), &loaderClient.base);
+
+ WKViewClientV0 viewClient;
+ memset(&viewClient, 0, sizeof(viewClient));
+ viewClient.base.version = 0;
+ viewClient.didChangeContentsPosition = didChangeContentsPosition;
+ WKViewSetViewClient(view.get(), &viewClient.base);
+
+ // Load first page.
+ WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("CoordinatedGraphics/backforward1", "html"));
+ WKPageLoadURL(webView.page(), url.get());
+ Util::run(&finishedLoad);
+
+ // Change scale and position on first page.
+ float firstPageScale = 2.0;
+ WKPoint firstPageScrollPosition = WKPointMake(10, 350); // Scroll position of first page.
+ WKViewSetContentPosition(view.get(), firstPageScrollPosition);
+ WKViewSetContentScaleFactor(view.get(), firstPageScale);
+ float currentPageScale = WKViewGetContentScaleFactor(view.get());
+ WKPoint currentPagePosition = WKViewGetContentPosition(view.get());
+ Util::run(&scroll);
+ EXPECT_EQ(firstPageScale, currentPageScale);
+ EXPECT_EQ(firstPageScrollPosition.x, currentPagePosition.x);
+ EXPECT_EQ(firstPageScrollPosition.y, currentPagePosition.y);
+
+ // Load second page.
+ finishedLoad = false;
+ url = adoptWK(Util::createURLForResource("CoordinatedGraphics/backforward2", "html"));
+ WKPageLoadURL(webView.page(), url.get());
+ Util::run(&finishedLoad);
+
+ // Check if second page scale and position is correct.
+ currentPageScale = WKViewGetContentScaleFactor(view.get());
+ currentPagePosition = WKViewGetContentPosition(view.get());
+ EXPECT_EQ(1, currentPageScale);
+ EXPECT_EQ(0, currentPagePosition.x);
+ EXPECT_EQ(0, currentPagePosition.y);
+
+ // Go back first page.
+ scroll = false;
+ finishedLoad = false;
+ WKPageGoBack(webView.page());
+ Util::run(&finishedLoad);
+ Util::run(&scroll);
+
+ // Check if scroll position and scale of first page are restored correctly.
+ currentPageScale = WKViewGetContentScaleFactor(view.get());
+ currentPagePosition = WKViewGetContentPosition(view.get());
+ EXPECT_EQ(firstPageScale, currentPageScale);
+ EXPECT_EQ(firstPageScrollPosition.x, currentPagePosition.x);
+ EXPECT_EQ(firstPageScrollPosition.y, currentPagePosition.y);
+
+ // Go to second page again.
+ WKPageGoForward(webView.page());
+ scroll = false;
+ finishedLoad = false;
+ Util::run(&finishedLoad);
+
+ // Check if the scroll position and scale of second page are restored correctly.
+ currentPageScale = WKViewGetContentScaleFactor(view.get());
+ currentPagePosition = WKViewGetContentPosition(view.get());
+ EXPECT_EQ(1, currentPageScale);
+ EXPECT_EQ(0, currentPagePosition.x);
+ EXPECT_EQ(0, currentPagePosition.y);
+}
+
+} // TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/WKViewUserViewportToContents.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/WKViewUserViewportToContents.cpp
new file mode 100644
index 000000000..e6465480c
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/WKViewUserViewportToContents.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "WebKit/WKView.h"
+#include "WebKit/WKRetainPtr.h"
+
+namespace TestWebKitAPI {
+
+TEST(WebKit2, DISABLED_WKViewUserViewportToContents)
+{
+ // This test creates a WKView and uses the WKViewUserViewportToContents
+ // function to convert viewport coordinates to contents (page) coordinates.
+ // It scrolls and scales around the contents and check if the coordinates
+ // conversion math is right.
+
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+ WKRetainPtr<WKPageConfigurationRef> configuration(AdoptWK, WKPageConfigurationCreate());
+ WKPageConfigurationSetContext(configuration.get(), context.get());
+
+ WKRetainPtr<WKViewRef> webView(AdoptWK, WKViewCreate(configuration.get()));
+
+ WKViewSetIsActive(webView.get(), true);
+ WKPageSetUseFixedLayout(WKViewGetPage(webView.get()), false);
+
+ WKPoint out;
+
+ // At scale 1.0 the viewport and contents coordinates should match.
+
+ WKViewSetContentScaleFactor(webView.get(), 1.0);
+ WKViewSetContentPosition(webView.get(), WKPointMake(0, 0));
+
+ out = WKViewUserViewportToContents(webView.get(), WKPointMake(0, 0));
+ EXPECT_EQ(out.x, 0);
+ EXPECT_EQ(out.y, 0);
+
+ out = WKViewUserViewportToContents(webView.get(), WKPointMake(10, 10));
+ EXPECT_EQ(out.x, 10);
+ EXPECT_EQ(out.y, 10);
+
+ WKViewSetContentPosition(webView.get(), WKPointMake(20, 20));
+
+ out = WKViewUserViewportToContents(webView.get(), WKPointMake(0, 0));
+ EXPECT_EQ(out.x, 20);
+ EXPECT_EQ(out.y, 20);
+
+ out = WKViewUserViewportToContents(webView.get(), WKPointMake(10, 10));
+ EXPECT_EQ(out.x, 30);
+ EXPECT_EQ(out.y, 30);
+
+ // At scale 2.0 the viewport distance values will be half
+ // the ones seem in the contents.
+
+ WKViewSetContentScaleFactor(webView.get(), 2.0);
+ WKViewSetContentPosition(webView.get(), WKPointMake(0, 0));
+
+ out = WKViewUserViewportToContents(webView.get(), WKPointMake(0, 0));
+ EXPECT_EQ(out.x, 0);
+ EXPECT_EQ(out.y, 0);
+
+ out = WKViewUserViewportToContents(webView.get(), WKPointMake(10, 10));
+ EXPECT_EQ(out.x, 5);
+ EXPECT_EQ(out.y, 5);
+
+ WKViewSetContentPosition(webView.get(), WKPointMake(20, 20));
+
+ out = WKViewUserViewportToContents(webView.get(), WKPointMake(0, 0));
+ EXPECT_EQ(out.x, 20);
+ EXPECT_EQ(out.y, 20);
+
+ out = WKViewUserViewportToContents(webView.get(), WKPointMake(10, 10));
+ EXPECT_EQ(out.x, 25);
+ EXPECT_EQ(out.y, 25);
+
+ // At scale 0.5 the viewport distance values will be twice
+ // the ones seem in the contents.
+
+ WKViewSetContentScaleFactor(webView.get(), 0.5);
+ WKViewSetContentPosition(webView.get(), WKPointMake(0, 0));
+
+ out = WKViewUserViewportToContents(webView.get(), WKPointMake(0, 0));
+ EXPECT_EQ(out.x, 0);
+ EXPECT_EQ(out.y, 0);
+
+ out = WKViewUserViewportToContents(webView.get(), WKPointMake(10, 10));
+ EXPECT_EQ(out.x, 20);
+ EXPECT_EQ(out.y, 20);
+
+ WKViewSetContentPosition(webView.get(), WKPointMake(20, 20));
+
+ out = WKViewUserViewportToContents(webView.get(), WKPointMake(0, 0));
+ EXPECT_EQ(out.x, 20);
+ EXPECT_EQ(out.y, 20);
+
+ out = WKViewUserViewportToContents(webView.get(), WKPointMake(10, 10));
+ EXPECT_EQ(out.x, 40);
+ EXPECT_EQ(out.y, 40);
+
+ // Let's add translation to the viewport.
+
+ const int delta = 10;
+ WKViewSetUserViewportTranslation(webView.get(), delta, delta);
+
+ WKViewSetContentPosition(webView.get(), WKPointMake(0, 0));
+
+ out = WKViewUserViewportToContents(webView.get(), WKPointMake(0, 0));
+ EXPECT_EQ(out.x, 0 - delta / 0.5);
+ EXPECT_EQ(out.y, 0 - delta / 0.5);
+
+ out = WKViewUserViewportToContents(webView.get(), WKPointMake(10, 10));
+ EXPECT_EQ(out.x, 20 - delta / 0.5);
+ EXPECT_EQ(out.y, 20 - delta / 0.5);
+
+ WKViewSetContentPosition(webView.get(), WKPointMake(20, 20));
+
+ out = WKViewUserViewportToContents(webView.get(), WKPointMake(0, 0));
+ EXPECT_EQ(out.x, 20 - delta / 0.5);
+ EXPECT_EQ(out.y, 20 - delta / 0.5);
+
+ out = WKViewUserViewportToContents(webView.get(), WKPointMake(10, 10));
+ EXPECT_EQ(out.x, 40 - delta / 0.5);
+ EXPECT_EQ(out.y, 40 - delta / 0.5);
+}
+
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/backforward1.html b/Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/backforward1.html
new file mode 100644
index 000000000..98c1c107c
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/backforward1.html
@@ -0,0 +1,5 @@
+<html>
+<body style="width:100%; height:100%">
+ <div style="position: absolute; top: 0; left: 0; width: 900px; height: 1200px;"></div>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/backforward2.html b/Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/backforward2.html
new file mode 100644
index 000000000..3806b9d32
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/backforward2.html
@@ -0,0 +1 @@
+<body style="width:100%; height:100%"/>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/DOMWindowExtensionBasic.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/DOMWindowExtensionBasic.cpp
index 06abe884b..c336652ac 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/DOMWindowExtensionBasic.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/DOMWindowExtensionBasic.cpp
@@ -24,10 +24,13 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include "Test.h"
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKRetainPtr.h>
#include <wtf/Vector.h>
namespace TestWebKitAPI {
@@ -133,3 +136,5 @@ TEST(WebKit2, DISABLED_DOMWindowExtensionBasic)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/DOMWindowExtensionBasic_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/DOMWindowExtensionBasic_Bundle.cpp
index 5c946625a..9bdc683ba 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/DOMWindowExtensionBasic_Bundle.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/DOMWindowExtensionBasic_Bundle.cpp
@@ -24,14 +24,17 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "InjectedBundleTest.h"
-#include <WebKit2/WKBundleDOMWindowExtension.h>
-#include <WebKit2/WKBundleFrame.h>
-#include <WebKit2/WKBundlePage.h>
-#include <WebKit2/WKBundlePageGroup.h>
-#include <WebKit2/WKBundlePrivate.h>
-#include <WebKit2/WKBundleScriptWorld.h>
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKBundleDOMWindowExtension.h>
+#include <WebKit/WKBundleFrame.h>
+#include <WebKit/WKBundlePage.h>
+#include <WebKit/WKBundlePageGroup.h>
+#include <WebKit/WKBundlePrivate.h>
+#include <WebKit/WKBundleScriptWorld.h>
+#include <WebKit/WKRetainPtr.h>
#include <wtf/HashMap.h>
#include <assert.h>
@@ -257,3 +260,5 @@ static void willDestroyGlobalObjectForDOMWindowExtensionCallback(WKBundlePageRef
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/DOMWindowExtensionNoCache.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/DOMWindowExtensionNoCache.cpp
index c5f6104f6..56a069fb9 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/DOMWindowExtensionNoCache.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/DOMWindowExtensionNoCache.cpp
@@ -24,6 +24,9 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include "Test.h"
@@ -132,3 +135,5 @@ TEST(WebKit2, DISABLED_DOMWindowExtensionNoCache)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/DOMWindowExtensionNoCache_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/DOMWindowExtensionNoCache_Bundle.cpp
index 680c17288..e48dadd1e 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/DOMWindowExtensionNoCache_Bundle.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/DOMWindowExtensionNoCache_Bundle.cpp
@@ -24,14 +24,17 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "InjectedBundleTest.h"
-#include <WebKit2/WKBundleDOMWindowExtension.h>
-#include <WebKit2/WKBundleFrame.h>
-#include <WebKit2/WKBundlePage.h>
-#include <WebKit2/WKBundlePageGroup.h>
-#include <WebKit2/WKBundlePrivate.h>
-#include <WebKit2/WKBundleScriptWorld.h>
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKBundleDOMWindowExtension.h>
+#include <WebKit/WKBundleFrame.h>
+#include <WebKit/WKBundlePage.h>
+#include <WebKit/WKBundlePageGroup.h>
+#include <WebKit/WKBundlePrivate.h>
+#include <WebKit/WKBundleScriptWorld.h>
+#include <WebKit/WKRetainPtr.h>
#include <wtf/HashMap.h>
#include <assert.h>
@@ -276,3 +279,5 @@ static void willDestroyGlobalObjectForDOMWindowExtensionCallback(WKBundlePageRef
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/DidAssociateFormControls.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/DidAssociateFormControls.cpp
index a78b8867f..a930f5346 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/DidAssociateFormControls.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/DidAssociateFormControls.cpp
@@ -24,6 +24,9 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include "Test.h"
@@ -83,3 +86,5 @@ TEST(WebKit2, DidAssociateFormControls)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/DidAssociateFormControls_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/DidAssociateFormControls_Bundle.cpp
index fd373d282..4e30eee5f 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/DidAssociateFormControls_Bundle.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/DidAssociateFormControls_Bundle.cpp
@@ -24,11 +24,14 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "InjectedBundleTest.h"
#include "PlatformUtilities.h"
-#include <WebKit2/WKBundle.h>
-#include <WebKit2/WKBundlePage.h>
+#include <WebKit/WKBundle.h>
+#include <WebKit/WKBundlePage.h>
namespace TestWebKitAPI {
@@ -36,7 +39,7 @@ class DidAssociateFormControlsTest : public InjectedBundleTest {
public:
DidAssociateFormControlsTest(const std::string& identifier);
- virtual void didCreatePage(WKBundleRef, WKBundlePageRef) override;
+ void didCreatePage(WKBundleRef, WKBundlePageRef) override;
};
static InjectedBundleTest::Register<DidAssociateFormControlsTest> registrar("DidAssociateFormControlsTest");
@@ -54,7 +57,7 @@ static void didAssociateFormControls(WKBundlePageRef page, WKArrayRef elementHan
WKRetainPtr<WKUInt64Ref> numberOfElements = adoptWK(WKUInt64Create(WKArrayGetSize(elementHandles)));
WKDictionarySetItem(messageBody.get(), Util::toWK("NumberOfControls").get(), numberOfElements.get());
- WKBundlePostMessage(InjectedBundleController::shared().bundle(), Util::toWK("DidReceiveDidAssociateFormControls").get(), messageBody.get());
+ WKBundlePostMessage(InjectedBundleController::singleton().bundle(), Util::toWK("DidReceiveDidAssociateFormControls").get(), messageBody.get());
}
DidAssociateFormControlsTest::DidAssociateFormControlsTest(const std::string& identifier)
@@ -76,3 +79,5 @@ void DidAssociateFormControlsTest::didCreatePage(WKBundleRef bundle, WKBundlePag
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/DidNotHandleKeyDown.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/DidNotHandleKeyDown.cpp
index e0c5cb0d8..b5f4fb863 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/DidNotHandleKeyDown.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/DidNotHandleKeyDown.cpp
@@ -24,10 +24,13 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "JavaScriptTest.h"
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -76,3 +79,5 @@ TEST(WebKit2, DidNotHandleKeyDown)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/DidRemoveFrameFromHiearchyInPageCache.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/DidRemoveFrameFromHiearchyInPageCache.cpp
new file mode 100644
index 000000000..2a6f5da0a
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/DidRemoveFrameFromHiearchyInPageCache.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include "Test.h"
+
+#include <WebKit/WKString.h>
+
+namespace TestWebKitAPI {
+
+static bool finished = false;
+static int didRemoveFrameFromHierarchyCount;
+
+static void didFinishLoadForFrame(WKPageRef, WKFrameRef frame, WKTypeRef, const void*)
+{
+ // Only mark finished when the main frame loads
+ if (!WKFrameIsMainFrame(frame))
+ return;
+
+ finished = true;
+}
+
+static void setPageLoaderClient(WKPageRef page)
+{
+ WKPageLoaderClientV1 loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+
+ loaderClient.base.version = 1;
+ loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+
+ WKPageSetPageLoaderClient(page, &loaderClient.base);
+}
+
+static void didReceivePageMessageFromInjectedBundle(WKPageRef, WKStringRef messageName, WKTypeRef, const void*)
+{
+ if (WKStringIsEqualToUTF8CString(messageName, "DidRemoveFrameFromHierarchy"))
+ ++didRemoveFrameFromHierarchyCount;
+}
+
+static void setInjectedBundleClient(WKPageRef page)
+{
+ WKPageInjectedBundleClientV0 injectedBundleClient = {
+ { 0, nullptr },
+ didReceivePageMessageFromInjectedBundle,
+ nullptr,
+ };
+ WKPageSetPageInjectedBundleClient(page, &injectedBundleClient.base);
+}
+
+TEST(WebKit2, DidRemoveFrameFromHiearchyInPageCache)
+{
+ WKRetainPtr<WKContextRef> context = adoptWK(Util::createContextForInjectedBundleTest("DidRemoveFrameFromHiearchyInPageCache"));
+ // Enable the page cache so we can test the WKBundlePageDidRemoveFrameFromHierarchyCallback API
+ WKContextSetCacheModel(context.get(), kWKCacheModelPrimaryWebBrowser);
+
+ PlatformWebView webView(context.get());
+ setPageLoaderClient(webView.page());
+ setInjectedBundleClient(webView.page());
+
+ finished = false;
+ WKPageLoadURL(webView.page(), adoptWK(Util::createURLForResource("many-iframes", "html")).get());
+ Util::run(&finished);
+
+ // Perform a couple of loads so "many-iframes" gets kicked out of the PageCache.
+ finished = false;
+ WKPageLoadURL(webView.page(), adoptWK(Util::createURLForResource("simple", "html")).get());
+ Util::run(&finished);
+
+ finished = false;
+ WKPageLoadURL(webView.page(), adoptWK(Util::createURLForResource("simple2", "html")).get());
+ Util::run(&finished);
+
+ finished = false;
+ WKPageLoadURL(webView.page(), adoptWK(Util::createURLForResource("simple3", "html")).get());
+ Util::run(&finished);
+
+ EXPECT_EQ(didRemoveFrameFromHierarchyCount, 10);
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/DidRemoveFrameFromHiearchyInPageCache_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/DidRemoveFrameFromHiearchyInPageCache_Bundle.cpp
new file mode 100644
index 000000000..712b3fb06
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/DidRemoveFrameFromHiearchyInPageCache_Bundle.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "InjectedBundleTest.h"
+
+#include "PlatformUtilities.h"
+#include <WebKit/WKBundlePage.h>
+
+namespace TestWebKitAPI {
+
+class DidRemoveFrameFromHiearchyInPageCacheTest : public InjectedBundleTest {
+public:
+ DidRemoveFrameFromHiearchyInPageCacheTest(const std::string& identifier);
+
+ virtual void didCreatePage(WKBundleRef, WKBundlePageRef);
+};
+
+static InjectedBundleTest::Register<DidRemoveFrameFromHiearchyInPageCacheTest> registrar("DidRemoveFrameFromHiearchyInPageCache");
+
+static unsigned didRemoveFrameFromHierarchyCount;
+
+void didRemoveFrameFromHierarchyCallback(WKBundlePageRef page, WKBundleFrameRef, WKTypeRef*, const void*)
+{
+ didRemoveFrameFromHierarchyCount++;
+
+ WKRetainPtr<WKStringRef> message(AdoptWK, WKStringCreateWithUTF8CString("DidRemoveFrameFromHierarchy"));
+ WKBundlePagePostMessage(page, message.get(), message.get());
+}
+
+DidRemoveFrameFromHiearchyInPageCacheTest::DidRemoveFrameFromHiearchyInPageCacheTest(const std::string& identifier)
+ : InjectedBundleTest(identifier)
+{
+}
+
+void DidRemoveFrameFromHiearchyInPageCacheTest::didCreatePage(WKBundleRef bundle, WKBundlePageRef page)
+{
+ WKBundlePageLoaderClientV8 pageLoaderClient;
+ memset(&pageLoaderClient, 0, sizeof(pageLoaderClient));
+
+ pageLoaderClient.base.version = 8;
+ pageLoaderClient.base.clientInfo = this;
+ pageLoaderClient.didRemoveFrameFromHierarchy = didRemoveFrameFromHierarchyCallback;
+
+ WKBundlePageSetPageLoaderClient(page, &pageLoaderClient.base);
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash.cpp
index efdcd56a7..21bca74dd 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash.cpp
@@ -24,10 +24,13 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include "Test.h"
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -65,3 +68,5 @@ TEST(WebKit2, DocumentStartUserScriptAlertCrashTest)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash_Bundle.cpp
index 30805f759..18b9f1b48 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash_Bundle.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash_Bundle.cpp
@@ -24,11 +24,14 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "InjectedBundleTest.h"
-#include <WebKit2/WKBundlePageGroup.h>
-#include <WebKit2/WKBundlePrivate.h>
-#include <WebKit2/WKBundleScriptWorld.h>
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKBundlePageGroup.h>
+#include <WebKit/WKBundlePrivate.h>
+#include <WebKit/WKBundleScriptWorld.h>
+#include <WebKit/WKRetainPtr.h>
#include <assert.h>
namespace TestWebKitAPI {
@@ -53,3 +56,5 @@ public:
static InjectedBundleTest::Register<DocumentStartUserScriptAlertCrashTest> registrar("DocumentStartUserScriptAlertCrashTest");
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/DownloadDecideDestinationCrash.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/DownloadDecideDestinationCrash.cpp
index aaead72dd..eac36d87a 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/DownloadDecideDestinationCrash.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/DownloadDecideDestinationCrash.cpp
@@ -24,9 +24,12 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
-#include <WebKit2/WKDownload.h>
+#include <WebKit/WKDownload.h>
namespace TestWebKitAPI {
@@ -41,7 +44,7 @@ static WKStringRef decideDestinationWithSuggestedFilename(WKContextRef, WKDownlo
{
didDecideDestination = true;
WKDownloadCancel(download);
- return Util::toWK("does not matter").leakRef();
+ return Util::toWK("/tmp/WebKitAPITest/DownloadDecideDestinationCrash").leakRef();
}
static void setContextDownloadClient(WKContextRef context)
@@ -83,3 +86,5 @@ TEST(WebKit2, DownloadDecideDestinationCrash)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/EnumerateMediaDevices.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/EnumerateMediaDevices.cpp
new file mode 100644
index 000000000..0ac7d0fe1
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/EnumerateMediaDevices.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#if ENABLE(MEDIA_STREAM)
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include "Test.h"
+#include <WebKit/WKPreferencesRef.h>
+#include <WebKit/WKPreferencesRefPrivate.h>
+#include <WebKit/WKRetainPtr.h>
+#include <WebKit/WKUserMediaPermissionCheck.h>
+#include <string.h>
+#include <vector>
+
+namespace TestWebKitAPI {
+
+static bool loadedFirstTime;
+static bool loadedSecondTime;
+
+void checkUserMediaPermissionCallback(WKPageRef, WKFrameRef, WKSecurityOriginRef, WKSecurityOriginRef, WKUserMediaPermissionCheckRef permissionRequest, const void*)
+{
+ WKUserMediaPermissionCheckSetUserMediaAccessInfo(permissionRequest, WKStringCreateWithUTF8CString("0x123456789"), true);
+ if (!loadedFirstTime) {
+ loadedFirstTime = true;
+ return;
+ }
+
+ loadedSecondTime = true;
+}
+
+TEST(WebKit2, EnumerateDevices)
+{
+ auto context = adoptWK(WKContextCreate());
+
+ WKRetainPtr<WKPageGroupRef> pageGroup(AdoptWK, WKPageGroupCreateWithIdentifier(Util::toWK("EnumerateDevices").get()));
+ WKPreferencesRef preferences = WKPageGroupGetPreferences(pageGroup.get());
+ WKPreferencesSetMediaStreamEnabled(preferences, true);
+ WKPreferencesSetFileAccessFromFileURLsAllowed(preferences, true);
+ WKPreferencesSetMediaCaptureRequiresSecureConnection(preferences, false);
+
+ WKPageUIClientV6 uiClient;
+ memset(&uiClient, 0, sizeof(uiClient));
+ uiClient.base.version = 6;
+ uiClient.checkUserMediaPermissionForOrigin = checkUserMediaPermissionCallback;
+
+ PlatformWebView webView(context.get(), pageGroup.get());
+ WKPageSetPageUIClient(webView.page(), &uiClient.base);
+
+ auto url = adoptWK(Util::createURLForResource("enumerateMediaDevices", "html"));
+
+ // Load and kill the page.
+ WKPageLoadURL(webView.page(), url.get());
+ Util::run(&loadedFirstTime);
+ WKPageTerminate(webView.page());
+
+ // Load it again to make sure the user media process manager doesn't assert.
+ WKPageLoadURL(webView.page(), url.get());
+ Util::run(&loadedSecondTime);
+}
+
+} // namespace TestWebKitAPI
+
+#endif // ENABLE(MEDIA_STREAM)
+
+#endif // WK_HAVE_C_SPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/EphemeralSessionPushStateNoHistoryCallback.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/EphemeralSessionPushStateNoHistoryCallback.cpp
new file mode 100644
index 000000000..64b666ab4
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/EphemeralSessionPushStateNoHistoryCallback.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include "Test.h"
+#include <WebKit/WKRetainPtr.h>
+#include <WebKit/WKWebsiteDataStoreRef.h>
+
+namespace TestWebKitAPI {
+
+static bool testDone;
+
+static void didNavigateWithNavigationData(WKContextRef context, WKPageRef page, WKNavigationDataRef navigationData, WKFrameRef frame, const void* clientInfo)
+{
+ // This should never be called when navigating in Private Browsing.
+ FAIL();
+}
+
+static void didSameDocumentNavigationForFrame(WKPageRef page, WKFrameRef frame, WKSameDocumentNavigationType type, WKTypeRef userData, const void *clientInfo)
+{
+ testDone = true;
+}
+
+TEST(WebKit2, EphemeralSessionPushStateNoHistoryCallback)
+{
+ auto configuration = adoptWK(WKPageConfigurationCreate());
+
+ auto context = adoptWK(WKContextCreate());
+ WKPageConfigurationSetContext(configuration.get(), context.get());
+
+ auto websiteDataStore = adoptWK(WKWebsiteDataStoreCreateNonPersistentDataStore());
+ WKPageConfigurationSetWebsiteDataStore(configuration.get(), websiteDataStore.get());
+
+ WKContextHistoryClientV0 historyClient;
+ memset(&historyClient, 0, sizeof(historyClient));
+
+ historyClient.base.version = 0;
+ historyClient.didNavigateWithNavigationData = didNavigateWithNavigationData;
+
+ WKContextSetHistoryClient(context.get(), &historyClient.base);
+
+ PlatformWebView webView(configuration.get());
+
+ WKPageLoaderClientV0 pageLoaderClient;
+ memset(&pageLoaderClient, 0, sizeof(pageLoaderClient));
+
+ pageLoaderClient.base.version = 0;
+ pageLoaderClient.didSameDocumentNavigationForFrame = didSameDocumentNavigationForFrame;
+
+ WKPageSetPageLoaderClient(webView.page(), &pageLoaderClient.base);
+
+ WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("push-state", "html"));
+ WKPageLoadURL(webView.page(), url.get());
+
+ Util::run(&testDone);
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/EvaluateJavaScript.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/EvaluateJavaScript.cpp
index 90ad04fd1..a6b5a4dd5 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/EvaluateJavaScript.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/EvaluateJavaScript.cpp
@@ -24,11 +24,14 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include "Test.h"
-#include <WebKit2/WKRetainPtr.h>
-#include <WebKit2/WKSerializedScriptValue.h>
+#include <WebKit/WKRetainPtr.h>
+#include <WebKit/WKSerializedScriptValue.h>
namespace TestWebKitAPI {
@@ -58,3 +61,5 @@ TEST(WebKit2, EvaluateJavaScriptThatThrowsAnException)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/EventModifiers.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/EventModifiers.cpp
new file mode 100644
index 000000000..d2cc644e1
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/EventModifiers.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "JavaScriptTest.h"
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+
+namespace TestWebKitAPI {
+
+static bool didFinishLoad { false };
+static bool mouseMoveCallbackFinished { false };
+
+static void didFinishLoadForFrame(WKPageRef, WKFrameRef, WKTypeRef, const void*)
+{
+ didFinishLoad = true;
+}
+
+static void mouseDidMoveOverElement(WKPageRef, WKHitTestResultRef, WKEventModifiers modifiers, WKTypeRef, const void*)
+{
+ EXPECT_EQ(modifiers, kWKEventModifiersControlKey);
+ mouseMoveCallbackFinished = true;
+}
+
+static void setClients(WKPageRef page)
+{
+ WKPageLoaderClientV0 loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+ loaderClient.base.version = 0;
+ loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+ WKPageSetPageLoaderClient(page, &loaderClient.base);
+
+ WKPageUIClientV1 uiClient;
+ memset(&uiClient, 0, sizeof(uiClient));
+ uiClient.base.version = 1;
+ uiClient.mouseDidMoveOverElement = mouseDidMoveOverElement;
+ WKPageSetPageUIClient(page, &uiClient.base);
+}
+
+TEST(WebKit2, EventModifiers)
+{
+ WKRetainPtr<WKContextRef> context = adoptWK(WKContextCreate());
+
+ PlatformWebView webView(context.get());
+ setClients(webView.page());
+
+ WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("simple", "html"));
+ WKPageLoadURL(webView.page(), url.get());
+ Util::run(&didFinishLoad);
+
+ webView.simulateMouseMove(10, 10, kWKEventModifiersControlKey);
+ Util::run(&mouseMoveCallbackFinished);
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/FailedLoad.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/FailedLoad.cpp
index ac8d6a39d..c12b5366b 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/FailedLoad.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/FailedLoad.cpp
@@ -24,10 +24,13 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include "Test.h"
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -65,3 +68,5 @@ TEST(WebKit2, FailedLoad)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/Find.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/Find.cpp
index 41b52eacd..2e2189906 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/Find.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/Find.cpp
@@ -24,9 +24,12 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -79,3 +82,5 @@ TEST(WebKit2, Find)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/ForceRepaint.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/ForceRepaint.cpp
index 86c6754a2..6cd63fab4 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/ForceRepaint.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/ForceRepaint.cpp
@@ -24,10 +24,13 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include "Test.h"
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -67,3 +70,5 @@ TEST(WebKit2, ForceRepaint)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/FrameHandle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/FrameHandle.cpp
new file mode 100644
index 000000000..1e3281d89
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/FrameHandle.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include "Test.h"
+#include <WebKit/WKFrameHandleRef.h>
+#include <WebKit/WKFrameInfoRef.h>
+#include <WebKit/WKRetainPtr.h>
+
+namespace TestWebKitAPI {
+
+static bool done;
+
+static void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
+{
+ done = true;
+}
+
+TEST(WebKit2, FrameHandle)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+ PlatformWebView webView(context.get());
+
+ WKPageLoaderClientV0 loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+ loaderClient.base.version = 0;
+ loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+ WKPageSetPageLoaderClient(webView.page(), &loaderClient.base);
+
+ WKPageLoadURL(webView.page(), adoptWK(WKURLCreateWithUTF8CString("about:blank")).get());
+ Util::run(&done);
+
+ auto frame = WKPageGetMainFrame(webView.page());
+ auto frameInfo = adoptWK(WKFrameCreateFrameInfo(frame));
+ auto handleFromInfo = WKFrameInfoGetFrameHandleRef(frameInfo.get());
+ auto handleFromFrame = adoptWK(WKFrameCreateFrameHandle(frame));
+
+ EXPECT_EQ(WKFrameHandleGetFrameID(handleFromInfo), WKFrameHandleGetFrameID(handleFromFrame.get()));
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/FrameMIMETypeHTML.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/FrameMIMETypeHTML.cpp
index 093a5747b..2c9c11332 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/FrameMIMETypeHTML.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/FrameMIMETypeHTML.cpp
@@ -24,10 +24,13 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include "Test.h"
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -75,3 +78,5 @@ TEST(WebKit2, FrameMIMETypeHTML)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/FrameMIMETypePNG.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/FrameMIMETypePNG.cpp
index edaa7cada..eb3bf38a3 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/FrameMIMETypePNG.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/FrameMIMETypePNG.cpp
@@ -24,9 +24,12 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -74,3 +77,5 @@ TEST(WebKit2, FrameMIMETypePNG)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/Geolocation.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/Geolocation.cpp
index bf7a93726..90fd37937 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/Geolocation.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/Geolocation.cpp
@@ -24,10 +24,14 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include "Test.h"
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKContextPrivate.h>
+#include <WebKit/WKRetainPtr.h>
#include <string.h>
#include <vector>
@@ -103,7 +107,7 @@ void decidePolicyForGeolocationPermissionRequestCallBack(WKPageRef page, WKFrame
void setupGeolocationProvider(WKContextRef context, void *clientInfo)
{
WKGeolocationProviderV1 providerCallback;
- memset(&providerCallback, 0, sizeof(WKGeolocationProvider));
+ memset(&providerCallback, 0, sizeof(WKGeolocationProviderV1));
providerCallback.base.version = 1;
providerCallback.base.clientInfo = clientInfo;
@@ -209,14 +213,9 @@ TEST(WebKit2, GeolocationBasicWithHighAccuracy)
// Geolocation start without High Accuracy, then requires High Accuracy.
struct GeolocationTransitionToHighAccuracyStateTracker : GeolocationStateTracker {
- bool finishedFirstStep;
- bool finished;
-
- GeolocationTransitionToHighAccuracyStateTracker()
- : finishedFirstStep(false)
- , finished(false)
- {
- }
+ bool finishedFirstStep { false };
+ bool enabledHighAccuracy { false };
+ bool finished { false };
virtual void eventsChanged()
{
@@ -230,11 +229,19 @@ struct GeolocationTransitionToHighAccuracyStateTracker : GeolocationStateTracker
break;
case 3:
EXPECT_EQ(GeolocationEvent::EnableHighAccuracy, events[2]);
+ enabledHighAccuracy = true;
+ break;
+ case 4:
+ EXPECT_EQ(GeolocationEvent::DisableHighAccuracy, events[3]);
+ break;
+ case 5:
+ EXPECT_EQ(GeolocationEvent::StopUpdating, events[4]);
finished = true;
break;
default:
EXPECT_TRUE(false);
finishedFirstStep = true;
+ enabledHighAccuracy = true;
finished = true;
}
}
@@ -243,6 +250,7 @@ struct GeolocationTransitionToHighAccuracyStateTracker : GeolocationStateTracker
TEST(WebKit2, GeolocationTransitionToHighAccuracy)
{
WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+ WKContextSetMaximumNumberOfProcesses(context.get(), 1);
GeolocationTransitionToHighAccuracyStateTracker stateTracker;
setupGeolocationProvider(context.get(), &stateTracker);
@@ -257,19 +265,20 @@ TEST(WebKit2, GeolocationTransitionToHighAccuracy)
setupView(highAccuracyWebView);
WKRetainPtr<WKURLRef> highAccuracyURL(AdoptWK, Util::createURLForResource("geolocationWatchPositionWithHighAccuracy", "html"));
WKPageLoadURL(highAccuracyWebView.page(), highAccuracyURL.get());
+ Util::run(&stateTracker.enabledHighAccuracy);
+
+ WKRetainPtr<WKURLRef> resetUrl = adoptWK(WKURLCreateWithUTF8CString("about:blank"));
+ WKPageLoadURL(highAccuracyWebView.page(), resetUrl.get());
+ Util::run(&stateTracker.enabledHighAccuracy);
+ WKPageLoadURL(lowAccuracyWebView.page(), resetUrl.get());
Util::run(&stateTracker.finished);
}
// Geolocation start with High Accuracy, then should fall back to low accuracy.
struct GeolocationTransitionToLowAccuracyStateTracker : GeolocationStateTracker {
- bool finishedFirstStep;
- bool finished;
-
- GeolocationTransitionToLowAccuracyStateTracker()
- : finishedFirstStep(false)
- , finished(false)
- {
- }
+ bool finishedFirstStep { false };
+ bool disabledHighAccuracy { false };
+ bool finished { false };
virtual void eventsChanged()
{
@@ -283,11 +292,16 @@ struct GeolocationTransitionToLowAccuracyStateTracker : GeolocationStateTracker
break;
case 3:
EXPECT_EQ(GeolocationEvent::DisableHighAccuracy, events[2]);
+ disabledHighAccuracy = true;
+ break;
+ case 4:
+ EXPECT_EQ(GeolocationEvent::StopUpdating, events[3]);
finished = true;
break;
default:
EXPECT_TRUE(false);
finishedFirstStep = true;
+ disabledHighAccuracy = true;
finished = true;
}
}
@@ -301,6 +315,7 @@ static void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef us
TEST(WebKit2, GeolocationTransitionToLowAccuracy)
{
WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+ WKContextSetMaximumNumberOfProcesses(context.get(), 1);
GeolocationTransitionToLowAccuracyStateTracker stateTracker;
setupGeolocationProvider(context.get(), &stateTracker);
@@ -331,7 +346,11 @@ TEST(WebKit2, GeolocationTransitionToLowAccuracy)
WKRetainPtr<WKURLRef> resetUrl = adoptWK(WKURLCreateWithUTF8CString("about:blank"));
WKPageLoadURL(highAccuracyWebView.page(), resetUrl.get());
+ Util::run(&stateTracker.disabledHighAccuracy);
+ WKPageLoadURL(lowAccuracyWebView.page(), resetUrl.get());
Util::run(&stateTracker.finished);
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/GetInjectedBundleInitializationUserDataCallback.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/GetInjectedBundleInitializationUserDataCallback.cpp
index fe898ffa8..e3280a3b7 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/GetInjectedBundleInitializationUserDataCallback.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/GetInjectedBundleInitializationUserDataCallback.cpp
@@ -24,9 +24,12 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -65,3 +68,5 @@ TEST(WebKit2, GetInjectedBundleInitializationUserDataCallback)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/GetInjectedBundleInitializationUserDataCallback_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/GetInjectedBundleInitializationUserDataCallback_Bundle.cpp
index 97500b59b..bf8da42e3 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/GetInjectedBundleInitializationUserDataCallback_Bundle.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/GetInjectedBundleInitializationUserDataCallback_Bundle.cpp
@@ -24,9 +24,12 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "InjectedBundleTest.h"
#include "PlatformUtilities.h"
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -46,3 +49,5 @@ public:
static InjectedBundleTest::Register<GetInjectedBundleInitializationUserDataCallbackTest> registrar("GetInjectedBundleInitializationUserDataCallbackTest");
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/HitTestResultNodeHandle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/HitTestResultNodeHandle.cpp
index 2f7c7deed..1f4a3726c 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/HitTestResultNodeHandle.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/HitTestResultNodeHandle.cpp
@@ -24,9 +24,12 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -86,3 +89,5 @@ TEST(WebKit2, HitTestResultNodeHandle)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/HitTestResultNodeHandle_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/HitTestResultNodeHandle_Bundle.cpp
index c6aaa1fec..d68ff2193 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/HitTestResultNodeHandle_Bundle.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/HitTestResultNodeHandle_Bundle.cpp
@@ -24,12 +24,15 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "InjectedBundleTest.h"
#include "InjectedBundleController.h"
#include "PlatformUtilities.h"
-#include <WebKit2/WKBundlePage.h>
-#include <WebKit2/WKBundleHitTestResult.h>
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKBundlePage.h>
+#include <WebKit/WKBundleHitTestResult.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -46,7 +49,7 @@ public:
if (!nodeHandle)
return;
- WKBundlePostMessage(InjectedBundleController::shared().bundle(), Util::toWK("HitTestResultNodeHandleTestDoneMessageName").get(), Util::toWK("HitTestResultNodeHandleTestDoneMessageBody").get());
+ WKBundlePostMessage(InjectedBundleController::singleton().bundle(), Util::toWK("HitTestResultNodeHandleTestDoneMessageName").get(), Util::toWK("HitTestResultNodeHandleTestDoneMessageBody").get());
}
virtual void didCreatePage(WKBundleRef bundle, WKBundlePageRef page)
@@ -64,3 +67,5 @@ public:
static InjectedBundleTest::Register<HitTestResultNodeHandleTest> registrar("HitTestResultNodeHandleTest");
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleBasic.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleBasic.cpp
index 1b3b3b7b6..a1d4046ed 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleBasic.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleBasic.cpp
@@ -24,9 +24,12 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -77,3 +80,5 @@ TEST(WebKit2, InjectedBundleBasic)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleBasic_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleBasic_Bundle.cpp
index 6a597be41..4d8689b93 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleBasic_Bundle.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleBasic_Bundle.cpp
@@ -24,8 +24,11 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "InjectedBundleTest.h"
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -47,3 +50,5 @@ public:
static InjectedBundleTest::Register<InjectedBundleBasicTest> registrar("InjectedBundleBasicTest");
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleFrameHitTest.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleFrameHitTest.cpp
index acc76c01e..e178dc3cb 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleFrameHitTest.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleFrameHitTest.cpp
@@ -24,9 +24,12 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -66,3 +69,5 @@ TEST(WebKit2, InjectedBundleFrameHitTest)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleFrameHitTest_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleFrameHitTest_Bundle.cpp
index 6ae018765..747858501 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleFrameHitTest_Bundle.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleFrameHitTest_Bundle.cpp
@@ -24,13 +24,16 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "InjectedBundleTest.h"
#include "PlatformUtilities.h"
-#include <WebKit2/WKBundle.h>
-#include <WebKit2/WKBundleFramePrivate.h>
-#include <WebKit2/WKBundleHitTestResult.h>
-#include <WebKit2/WKBundlePage.h>
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKBundle.h>
+#include <WebKit/WKBundleFramePrivate.h>
+#include <WebKit/WKBundleHitTestResult.h>
+#include <WebKit/WKBundlePage.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -41,7 +44,7 @@ public:
{
}
- virtual void didCreatePage(WKBundleRef, WKBundlePageRef) override;
+ void didCreatePage(WKBundleRef, WKBundlePageRef) override;
void frameLoadFinished(WKBundleFrameRef);
WKBundleRef m_bundle;
@@ -76,3 +79,5 @@ void InjectedBundleFrameHitTestTest::frameLoadFinished(WKBundleFrameRef frame)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleInitializationUserDataCallbackWins.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleInitializationUserDataCallbackWins.cpp
index 407ecceb5..678aaa85b 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleInitializationUserDataCallbackWins.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleInitializationUserDataCallbackWins.cpp
@@ -24,9 +24,12 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -67,3 +70,5 @@ TEST(WebKit2, InjectedBundleInitializationUserDataCallbackWins)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleInitializationUserDataCallbackWins_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleInitializationUserDataCallbackWins_Bundle.cpp
index 36708a4d7..cac7738dd 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleInitializationUserDataCallbackWins_Bundle.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleInitializationUserDataCallbackWins_Bundle.cpp
@@ -24,9 +24,12 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "InjectedBundleTest.h"
#include "PlatformUtilities.h"
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -46,3 +49,5 @@ public:
static InjectedBundleTest::Register<InjectedBundleInitializationUserDataCallbackWinsTest> registrar("InjectedBundleInitializationUserDataCallbackWinsTest");
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleMakeAllShadowRootsOpen.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleMakeAllShadowRootsOpen.cpp
new file mode 100644
index 000000000..91fc88929
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleMakeAllShadowRootsOpen.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2010, 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include "Test.h"
+#include <WebKit/WKRetainPtr.h>
+
+namespace TestWebKitAPI {
+
+static unsigned testNumber = 0;
+static bool done;
+
+static void runJavaScriptAlert(WKPageRef page, WKStringRef alertText, WKFrameRef frame, const void* clientInfo)
+{
+ ASSERT_NOT_NULL(frame);
+
+ EXPECT_EQ(page, WKFrameGetPage(frame));
+ switch (++testNumber) {
+ case 1:
+ EXPECT_WK_STREQ("PASS: shadowRoot created in injected bundle", alertText);
+ break;
+ case 2:
+ EXPECT_WK_STREQ("PASS: shadowRoot created by normal world", alertText);
+ break;
+ case 3:
+ EXPECT_WK_STREQ("PASS: collectMatchingElementsInFlatTree exists", alertText);
+ break;
+ case 4:
+ EXPECT_WK_STREQ("PASS: collectMatchingElementsInFlatTree was not present in the normal world", alertText);
+ break;
+ case 5:
+ EXPECT_WK_STREQ("Found:1,2,3,4,5,6", alertText);
+ break;
+ case 6:
+ EXPECT_WK_STREQ("Found:2,3,4", alertText);
+ break;
+ case 7:
+ EXPECT_WK_STREQ("PASS: matchingElementInFlatTree exists", alertText);
+ break;
+ case 8:
+ EXPECT_WK_STREQ("PASS: matchingElementInFlatTree was not present in the normal world", alertText);
+ break;
+ case 9:
+ EXPECT_WK_STREQ("Found:1", alertText);
+ break;
+ case 10:
+ EXPECT_WK_STREQ("Found:2", alertText);
+ break;
+ case 11:
+ EXPECT_WK_STREQ("Found:0 divs", alertText);
+ break;
+ case 12:
+ EXPECT_WK_STREQ("Found:false", alertText);
+ done = true;
+ break;
+ }
+}
+
+TEST(WebKit2, InjectedBundleMakeAllShadowRootOpenTest)
+{
+ WKRetainPtr<WKPageGroupRef> pageGroup(AdoptWK, WKPageGroupCreateWithIdentifier(WKStringCreateWithUTF8CString("InjectedBundleMakeAllShadowRootOpenTestPageGroup")));
+
+ WKRetainPtr<WKContextRef> context(AdoptWK, Util::createContextForInjectedBundleTest("InjectedBundleMakeAllShadowRootOpenTest", pageGroup.get()));
+ PlatformWebView webView(context.get(), pageGroup.get());
+
+ WKPageUIClientV0 uiClient;
+ memset(&uiClient, 0, sizeof(uiClient));
+
+ uiClient.base.version = 0;
+ uiClient.runJavaScriptAlert = runJavaScriptAlert;
+
+ WKPageSetPageUIClient(webView.page(), &uiClient.base);
+
+ WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("closed-shadow-tree-test", "html"));
+ WKPageLoadURL(webView.page(), url.get());
+
+ Util::run(&done);
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleMakeAllShadowRootsOpen_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleMakeAllShadowRootsOpen_Bundle.cpp
new file mode 100644
index 000000000..ee5761993
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleMakeAllShadowRootsOpen_Bundle.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2010, 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "InjectedBundleTest.h"
+#include <WebKit/WKBundlePageGroup.h>
+#include <WebKit/WKBundlePrivate.h>
+#include <WebKit/WKBundleScriptWorld.h>
+#include <WebKit/WKRetainPtr.h>
+#include <assert.h>
+
+namespace TestWebKitAPI {
+
+class InjectedBundleMakeAllShadowRootOpenTest : public InjectedBundleTest {
+public:
+ InjectedBundleMakeAllShadowRootOpenTest(const std::string& identifier)
+ : InjectedBundleTest(identifier)
+ { }
+
+ virtual void initialize(WKBundleRef bundle, WKTypeRef userData)
+ {
+ assert(WKGetTypeID(userData) == WKBundlePageGroupGetTypeID());
+ WKBundlePageGroupRef pageGroup = static_cast<WKBundlePageGroupRef>(userData);
+
+ auto world = WKBundleScriptWorldCreateWorld();
+ WKBundleScriptWorldMakeAllShadowRootsOpen(world);
+
+ WKRetainPtr<WKStringRef> source(AdoptWK, WKStringCreateWithUTF8CString(
+ "window.onload = function () {\n"
+ " const element = document.createElement('div');\n"
+ " const queryMethodName = 'collectMatchingElementsInFlatTree';\n"
+ " element.attachShadow({mode: 'closed'});\n"
+ // Test 1
+ " alert(element.shadowRoot ? 'PASS: shadowRoot created in injected bundle' : 'FAIL');\n"
+ // Test 2
+ " alert(document.querySelector('shadow-host').shadowRoot ? 'PASS: shadowRoot created by normal world' : 'FAIL');\n"
+ // Test 3
+ " alert(window[queryMethodName] ? `PASS: ${queryMethodName} exists` : `FAIL: ${queryMethodName} does not exist`);\n"
+ // Test 4
+ " document.dispatchEvent(new CustomEvent('testnormalworld', {detail: queryMethodName}));\n"
+ // Test 5
+ " const queryMethod = window[queryMethodName];\n"
+ " let queryResult = Array.from(queryMethod(document, 'span'));\n"
+ " alert('Found:' + queryResult.map((span) => span.textContent).join(','));\n"
+ // Test 6
+ " const innerHost = queryMethod(document, 'inner-host')[0];\n"
+ " queryResult = Array.from(queryMethod(innerHost, 'span'));\n"
+ " alert('Found:' + queryResult.map((span) => span.textContent).join(','));\n"
+ // Test 7
+ " alert(window.matchingElementInFlatTree ? `PASS: matchingElementInFlatTree exists` : `FAIL: matchingElementInFlatTree does not exist`);\n"
+ // Test 8
+ " document.dispatchEvent(new CustomEvent('testnormalworld', {detail: 'matchingElementInFlatTree'}));\n"
+ // Test 9
+ " queryResult = window.matchingElementInFlatTree(document, 'span');\n"
+ " alert('Found:' + (queryResult ? queryResult.textContent : 'null'));\n"
+ // Test 10
+ " queryResult = window.matchingElementInFlatTree(innerHost, 'span');\n"
+ " alert('Found:' + (queryResult ? queryResult.textContent : 'null'));\n"
+ // Test 11
+ " alert(`Found:${queryMethod(document, 'div').length} divs`);\n"
+ // Test 12
+ " queryResult = window.matchingElementInFlatTree(document, 'div');\n"
+ " alert(`Found:${!!queryResult}`);\n"
+ "}\n"));
+ WKBundleAddUserScript(bundle, pageGroup, world, source.get(), 0, 0, 0, kWKInjectAtDocumentStart, kWKInjectInAllFrames);
+ }
+};
+
+static InjectedBundleTest::Register<InjectedBundleMakeAllShadowRootOpenTest> registrar("InjectedBundleMakeAllShadowRootOpenTest");
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/LayoutMilestonesWithAllContentInFrame.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/LayoutMilestonesWithAllContentInFrame.cpp
index ef53f5e91..aa294643c 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/LayoutMilestonesWithAllContentInFrame.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/LayoutMilestonesWithAllContentInFrame.cpp
@@ -24,11 +24,14 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include "Test.h"
-#include <WebKit2/WKContextPrivate.h>
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKContextPrivate.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -64,3 +67,5 @@ TEST(WebKit2, LayoutMilestonesWithAllContentInFrame)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/LimitTitleSize.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/LimitTitleSize.cpp
new file mode 100644
index 000000000..fde62c624
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/LimitTitleSize.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include "Test.h"
+#include <WebKit/WKRetainPtr.h>
+
+namespace TestWebKitAPI {
+
+static bool waitUntilLongTitleReceived = false;
+static bool didFinishLoad = false;
+static size_t maxTitleLength = 4096;
+
+static void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
+{
+ didFinishLoad = true;
+}
+
+static void didReceiveTitleForFrame(WKPageRef page, WKStringRef title, WKFrameRef, WKTypeRef, const void*)
+{
+ WKStringRef titleString = (WKStringRef)title;
+
+ if (WKStringIsEqualToUTF8CString(titleString, "Original Short Title"))
+ return;
+
+ EXPECT_LE(WKStringGetLength(titleString), maxTitleLength);
+ waitUntilLongTitleReceived = true;
+}
+
+TEST(WebKit2, LimitTitleSize)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+ PlatformWebView webView(context.get());
+
+ WKPageLoaderClientV0 loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+
+ loaderClient.base.version = 0;
+ loaderClient.didReceiveTitleForFrame = didReceiveTitleForFrame;
+ loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+
+ WKPageSetPageLoaderClient(webView.page(), &loaderClient.base);
+
+ WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("set-long-title", "html"));
+
+ WKPageLoadURL(webView.page(), url.get());
+ Util::run(&waitUntilLongTitleReceived);
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/LoadAlternateHTMLStringWithNonDirectoryURL.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/LoadAlternateHTMLStringWithNonDirectoryURL.cpp
index def60bcb9..acc23348b 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/LoadAlternateHTMLStringWithNonDirectoryURL.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/LoadAlternateHTMLStringWithNonDirectoryURL.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2015 Igalia S.L.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -24,13 +25,16 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "JavaScriptTest.h"
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
-#include <WebKit2/WKContext.h>
-#include <WebKit2/WKPage.h>
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKContext.h>
+#include <WebKit/WKPage.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -41,7 +45,7 @@ static void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef us
didFinishLoad = true;
}
-TEST(WebKit2, LoadAlternateHTMLStringWithNonDirectoryURL)
+static void loadAlternateHTMLString(WKURLRef baseURL, WKURLRef unreachableURL)
{
WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
PlatformWebView webView(context.get());
@@ -53,14 +57,29 @@ TEST(WebKit2, LoadAlternateHTMLStringWithNonDirectoryURL)
loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
WKPageSetPageLoaderClient(webView.page(), &loaderClient.base);
- WKRetainPtr<WKURLRef> fileURL(AdoptWK, Util::createURLForResource("simple", "html"));
WKRetainPtr<WKStringRef> alternateHTMLString(AdoptWK, WKStringCreateWithUTF8CString("<html><body><img src='icon.png'></body></html>"));
-
- // Call WKPageLoadAlternateHTMLString() with fileURL which does not point to a directory
- WKPageLoadAlternateHTMLString(webView.page(), alternateHTMLString.get(), fileURL.get(), fileURL.get());
-
+ WKPageLoadAlternateHTMLString(webView.page(), alternateHTMLString.get(), baseURL, unreachableURL);
+
// If we can finish loading the html without resulting in an invalid message being sent from the WebProcess, this test passes.
Util::run(&didFinishLoad);
}
+TEST(WebKit2, LoadAlternateHTMLStringWithNonDirectoryURL)
+{
+ // Call WKPageLoadAlternateHTMLString() with fileURL which does not point to a directory.
+ WKRetainPtr<WKURLRef> fileURL(AdoptWK, Util::createURLForResource("simple", "html"));
+ loadAlternateHTMLString(fileURL.get(), fileURL.get());
+}
+
+TEST(WebKit2, LoadAlternateHTMLStringWithEmptyBaseURL)
+{
+ // Call WKPageLoadAlternateHTMLString() with empty baseURL to make sure this test works
+ // when baseURL does not grant read access to the unreachableURL. We use a separate test
+ // to ensure the previous test does not pollute the result.
+ WKRetainPtr<WKURLRef> unreachableURL(AdoptWK, Util::URLForNonExistentResource());
+ loadAlternateHTMLString(nullptr, unreachableURL.get());
+}
+
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/LoadCanceledNoServerRedirectCallback.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/LoadCanceledNoServerRedirectCallback.cpp
index abf447155..ac45fba26 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/LoadCanceledNoServerRedirectCallback.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/LoadCanceledNoServerRedirectCallback.cpp
@@ -24,13 +24,16 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "JavaScriptTest.h"
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
-#include <WebKit2/WKContext.h>
-#include <WebKit2/WKFrame.h>
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKContext.h>
+#include <WebKit/WKFrame.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -93,3 +96,5 @@ TEST(WebKit2, LoadCanceledNoServerRedirectCallback)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/LoadCanceledNoServerRedirectCallback_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/LoadCanceledNoServerRedirectCallback_Bundle.cpp
index 13aa1106e..6ea0dc77d 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/LoadCanceledNoServerRedirectCallback_Bundle.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/LoadCanceledNoServerRedirectCallback_Bundle.cpp
@@ -24,13 +24,16 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "InjectedBundleTest.h"
#include "PlatformUtilities.h"
#include "Test.h"
-#include <WebKit2/WKBundlePage.h>
-#include <WebKit2/WKBundleFrame.h>
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKBundlePage.h>
+#include <WebKit/WKBundleFrame.h>
+#include <WebKit/WKRetainPtr.h>
#include <wtf/Assertions.h>
@@ -70,3 +73,5 @@ public:
static InjectedBundleTest::Register<LoadCanceledNoServerRedirectCallbackTest> registrar("LoadCanceledNoServerRedirectCallbackTest");
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/LoadPageOnCrash.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/LoadPageOnCrash.cpp
index 3228d084a..63ad664e2 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/LoadPageOnCrash.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/LoadPageOnCrash.cpp
@@ -24,10 +24,13 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include "Test.h"
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -103,3 +106,5 @@ TEST(WebKit2, LoadPageAfterCrash)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/MenuTypesForMouseEvents.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/MenuTypesForMouseEvents.cpp
new file mode 100644
index 000000000..f77a11ad8
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/MenuTypesForMouseEvents.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "JavaScriptTest.h"
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+
+namespace TestWebKitAPI {
+
+static bool didFinishLoad;
+
+static void didFinishLoadForFrame(WKPageRef, WKFrameRef, WKTypeRef, const void*)
+{
+ didFinishLoad = true;
+}
+
+static void setPageLoaderClient(WKPageRef page)
+{
+ WKPageLoaderClientV0 loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+
+ loaderClient.base.version = 0;
+ loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+
+ WKPageSetPageLoaderClient(page, &loaderClient.base);
+}
+
+static void buildAndPerformTest(WKEventMouseButton button, WKEventModifiers modifiers, const char* expectedButton, const char* expectedMenuType)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+ PlatformWebView webView(context.get());
+ setPageLoaderClient(webView.page());
+
+ WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("mouse-button-listener", "html"));
+ WKPageLoadURL(webView.page(), url.get());
+ Util::run(&didFinishLoad);
+
+ didFinishLoad = false;
+
+ webView.simulateButtonClick(button, 10, 10, modifiers);
+
+ EXPECT_JS_EQ(webView.page(), "pressedMouseButton()", expectedButton);
+ EXPECT_JS_EQ(webView.page(), "displayedMenu()", expectedMenuType);
+}
+
+TEST(WebKit2, MenuAndButtonForNormalLeftClick)
+{
+ buildAndPerformTest(kWKEventMouseButtonLeftButton, 0, "0", "none");
+}
+
+TEST(WebKit2, MenuAndButtonForNormalRightClick)
+{
+ buildAndPerformTest(kWKEventMouseButtonRightButton, 0, "2", "context");
+}
+
+TEST(WebKit2, MenuAndButtonForNormalMiddleClick)
+{
+ buildAndPerformTest(kWKEventMouseButtonMiddleButton, 0, "1", "none");
+}
+
+TEST(WebKit2, MenuAndButtonForControlLeftClick)
+{
+ buildAndPerformTest(kWKEventMouseButtonLeftButton, kWKEventModifiersControlKey, "0", "context");
+}
+
+TEST(WebKit2, MenuAndButtonForControlRightClick)
+{
+ buildAndPerformTest(kWKEventMouseButtonRightButton, kWKEventModifiersControlKey, "2", "context");
+}
+
+TEST(WebKit2, MenuAndButtonForControlMiddleClick)
+{
+ buildAndPerformTest(kWKEventMouseButtonMiddleButton, kWKEventModifiersControlKey, "1", "none");
+}
+
+TEST(WebKit2, MenuAndButtonForShiftLeftClick)
+{
+ buildAndPerformTest(kWKEventMouseButtonLeftButton, kWKEventModifiersShiftKey, "0", "none");
+}
+
+TEST(WebKit2, MenuAndButtonForShiftRightClick)
+{
+ buildAndPerformTest(kWKEventMouseButtonRightButton, kWKEventModifiersShiftKey, "2", "context");
+}
+
+TEST(WebKit2, MenuAndButtonForShiftMiddleClick)
+{
+ buildAndPerformTest(kWKEventMouseButtonMiddleButton, kWKEventModifiersShiftKey, "1", "none");
+}
+
+TEST(WebKit2, MenuAndButtonForCommandLeftClick)
+{
+ buildAndPerformTest(kWKEventMouseButtonLeftButton, kWKEventModifiersMetaKey, "0", "none");
+}
+
+TEST(WebKit2, MenuAndButtonForCommandRightClick)
+{
+ buildAndPerformTest(kWKEventMouseButtonRightButton, kWKEventModifiersMetaKey, "2", "context");
+}
+
+TEST(WebKit2, MenuAndButtonForCommandMiddleClick)
+{
+ buildAndPerformTest(kWKEventMouseButtonMiddleButton, kWKEventModifiersMetaKey, "1", "none");
+}
+
+TEST(WebKit2, MenuAndButtonForAltLeftClick)
+{
+ buildAndPerformTest(kWKEventMouseButtonLeftButton, kWKEventModifiersAltKey, "0", "none");
+}
+
+TEST(WebKit2, MenuAndButtonForAltRightClick)
+{
+ buildAndPerformTest(kWKEventMouseButtonRightButton, kWKEventModifiersAltKey, "2", "context");
+}
+
+TEST(WebKit2, MenuAndButtonForAltMiddleClick)
+{
+ buildAndPerformTest(kWKEventMouseButtonMiddleButton, kWKEventModifiersAltKey, "1", "none");
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/ModalAlertsSPI.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/ModalAlertsSPI.cpp
new file mode 100644
index 000000000..0278f005b
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/ModalAlertsSPI.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include "Test.h"
+#include <WebKit/WKFrame.h>
+#include <WebKit/WKRetainPtr.h>
+#include <WebKit/WKSecurityOriginRef.h>
+
+namespace TestWebKitAPI {
+
+static bool done;
+static unsigned dialogsSeen;
+static const unsigned dialogsExpected = 3;
+
+static void analyzeDialogArguments(WKPageRef page, WKFrameRef frame, WKSecurityOriginRef securityOrigin)
+{
+ EXPECT_EQ(page, WKFrameGetPage(frame));
+
+ WKRetainPtr<WKURLRef> url = adoptWK(WKFrameCopyURL(frame));
+ WKRetainPtr<WKStringRef> urlString = adoptWK(WKURLCopyString(url.get()));
+ EXPECT_WK_STREQ("about:blank", urlString.get());
+
+ WKRetainPtr<WKStringRef> protocol = adoptWK(WKSecurityOriginCopyProtocol(securityOrigin));
+ EXPECT_WK_STREQ("file", protocol.get());
+
+ WKRetainPtr<WKStringRef> host = adoptWK(WKSecurityOriginCopyHost(securityOrigin));
+ EXPECT_WK_STREQ("", host.get());
+
+ EXPECT_EQ(WKSecurityOriginGetPort(securityOrigin), 0);
+
+ if (++dialogsSeen == dialogsExpected)
+ done = true;
+}
+
+static void runJavaScriptAlert(WKPageRef page, WKStringRef, WKFrameRef frame, WKSecurityOriginRef securityOrigin, const void*)
+{
+ analyzeDialogArguments(page, frame, securityOrigin);
+}
+
+static bool runJavaScriptConfirm(WKPageRef page, WKStringRef, WKFrameRef frame, WKSecurityOriginRef securityOrigin, const void*)
+{
+ analyzeDialogArguments(page, frame, securityOrigin);
+ return false;
+}
+
+static WKStringRef runJavaScriptPrompt(WKPageRef page, WKStringRef, WKStringRef, WKFrameRef frame, WKSecurityOriginRef securityOrigin, const void*)
+{
+ analyzeDialogArguments(page, frame, securityOrigin);
+ return nullptr;
+}
+
+static std::unique_ptr<PlatformWebView> openedWebView;
+
+static WKPageRef createNewPage(WKPageRef page, WKURLRequestRef urlRequest, WKDictionaryRef features, WKEventModifiers modifiers, WKEventMouseButton mouseButton, const void *clientInfo)
+{
+ EXPECT_TRUE(openedWebView == nullptr);
+
+ openedWebView = std::make_unique<PlatformWebView>(page);
+
+ WKPageUIClientV5 uiClient;
+ memset(&uiClient, 0, sizeof(uiClient));
+
+ uiClient.base.version = 5;
+ uiClient.runJavaScriptAlert = runJavaScriptAlert;
+ uiClient.runJavaScriptConfirm = runJavaScriptConfirm;
+ uiClient.runJavaScriptPrompt = runJavaScriptPrompt;
+
+ WKPageSetPageUIClient(openedWebView->page(), &uiClient.base);
+
+ WKRetain(openedWebView->page());
+ return openedWebView->page();
+}
+
+TEST(WebKit2, ModalAlertsSPI)
+{
+ WKRetainPtr<WKContextRef> context = adoptWK(WKContextCreate());
+ PlatformWebView webView(context.get());
+
+ WKPageUIClientV5 uiClient;
+ memset(&uiClient, 0, sizeof(uiClient));
+
+ uiClient.base.version = 5;
+ uiClient.createNewPage = createNewPage;
+
+ WKPageSetPageUIClient(webView.page(), &uiClient.base);
+
+ WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("modal-alerts-in-new-about-blank-window", "html"));
+ WKPageLoadURL(webView.page(), url.get());
+
+ Util::run(&done);
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/MouseMoveAfterCrash.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/MouseMoveAfterCrash.cpp
index b75be6a1a..9d7f3997d 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/MouseMoveAfterCrash.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/MouseMoveAfterCrash.cpp
@@ -24,6 +24,9 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "JavaScriptTest.h"
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
@@ -48,11 +51,7 @@ static void setPageLoaderClient(WKPageRef page)
WKPageSetPageLoaderClient(page, &loaderClient.base);
}
-#if PLATFORM(WIN)
-TEST(WebKit2, DISABLED_MouseMoveAfterCrash)
-#else
TEST(WebKit2, MouseMoveAfterCrash)
-#endif
{
WKRetainPtr<WKContextRef> context = adoptWK(Util::createContextForInjectedBundleTest("MouseMoveAfterCrashTest"));
@@ -90,3 +89,5 @@ TEST(WebKit2, MouseMoveAfterCrash)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/MouseMoveAfterCrash_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/MouseMoveAfterCrash_Bundle.cpp
index a07562093..8d92f4209 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/MouseMoveAfterCrash_Bundle.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/MouseMoveAfterCrash_Bundle.cpp
@@ -24,6 +24,9 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "InjectedBundleTest.h"
#include "PlatformUtilities.h"
@@ -54,3 +57,5 @@ void MouseMoveAfterCrashTest::didReceiveMessage(WKBundleRef bundle, WKStringRef
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayout.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayout.cpp
index 640a825f8..778d285ba 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayout.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayout.cpp
@@ -24,9 +24,12 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
-#include <WebKit2/WKContextPrivate.h>
+#include <WebKit/WKContextPrivate.h>
namespace TestWebKitAPI {
@@ -86,3 +89,5 @@ TEST(WebKit2, DISABLED_NewFirstVisuallyNonEmptyLayout)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFails.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFails.cpp
index 1568b7663..5cff318fa 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFails.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFails.cpp
@@ -24,11 +24,14 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include "Test.h"
-#include <WebKit2/WKContextPrivate.h>
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKContextPrivate.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -86,3 +89,5 @@ TEST(WebKit2, NewFirstVisuallyNonEmptyLayoutFails)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFails_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFails_Bundle.cpp
index b909ec941..2700d66c8 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFails_Bundle.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFails_Bundle.cpp
@@ -24,11 +24,14 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "InjectedBundleTest.h"
#include "PlatformUtilities.h"
-#include <WebKit2/WKBundlePage.h>
-#include <WebKit2/WKBundlePagePrivate.h>
+#include <WebKit/WKBundlePage.h>
+#include <WebKit/WKBundlePagePrivate.h>
namespace TestWebKitAPI {
@@ -49,3 +52,5 @@ public:
static InjectedBundleTest::Register<NewFirstVisuallyNonEmptyLayoutFailsTest> registrar("NewFirstVisuallyNonEmptyLayoutFailsTest");
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutForImages.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutForImages.cpp
index 11fc17ebd..7bd1fd7b3 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutForImages.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutForImages.cpp
@@ -24,9 +24,12 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
-#include <WebKit2/WKContextPrivate.h>
+#include <WebKit/WKContextPrivate.h>
namespace TestWebKitAPI {
@@ -86,3 +89,5 @@ TEST(WebKit2, DISABLED_NewFirstVisuallyNonEmptyLayoutForImages)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutForImages_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutForImages_Bundle.cpp
index bdaade77b..d8644bb69 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutForImages_Bundle.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutForImages_Bundle.cpp
@@ -24,11 +24,14 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "InjectedBundleTest.h"
#include "PlatformUtilities.h"
-#include <WebKit2/WKBundlePage.h>
-#include <WebKit2/WKBundlePagePrivate.h>
+#include <WebKit/WKBundlePage.h>
+#include <WebKit/WKBundlePagePrivate.h>
namespace TestWebKitAPI {
@@ -49,3 +52,5 @@ public:
static InjectedBundleTest::Register<NewFirstVisuallyNonEmptyLayoutForImagesTest> registrar("NewFirstVisuallyNonEmptyLayoutForImagesTest");
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFrames.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFrames.cpp
index 04d6ee448..c7b24680e 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFrames.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFrames.cpp
@@ -24,11 +24,14 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include "Test.h"
-#include <WebKit2/WKContextPrivate.h>
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKContextPrivate.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -64,7 +67,7 @@ static void setPageLoaderClient(WKPageRef page)
WKPageLoaderClientV3 loaderClient;
memset(&loaderClient, 0, sizeof(loaderClient));
- loaderClient.base.version = kWKPageLoaderClientCurrentVersion;
+ loaderClient.base.version = 3;
loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
loaderClient.didLayout = didLayout;
@@ -90,3 +93,5 @@ TEST(WebKit2, NewFirstVisuallyNonEmptyLayoutFrames)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFrames_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFrames_Bundle.cpp
index 33e16bd3e..f66fc957d 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFrames_Bundle.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayoutFrames_Bundle.cpp
@@ -24,11 +24,14 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "InjectedBundleTest.h"
#include "PlatformUtilities.h"
-#include <WebKit2/WKBundlePage.h>
-#include <WebKit2/WKBundlePagePrivate.h>
+#include <WebKit/WKBundlePage.h>
+#include <WebKit/WKBundlePagePrivate.h>
namespace TestWebKitAPI {
@@ -49,3 +52,5 @@ public:
static InjectedBundleTest::Register<NewFirstVisuallyNonEmptyLayoutFramesTest> registrar("NewFirstVisuallyNonEmptyLayoutFramesTest");
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayout_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayout_Bundle.cpp
index c408c3b2c..8f1901d10 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayout_Bundle.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/NewFirstVisuallyNonEmptyLayout_Bundle.cpp
@@ -24,11 +24,14 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "InjectedBundleTest.h"
#include "PlatformUtilities.h"
-#include <WebKit2/WKBundlePage.h>
-#include <WebKit2/WKBundlePagePrivate.h>
+#include <WebKit/WKBundlePage.h>
+#include <WebKit/WKBundlePagePrivate.h>
namespace TestWebKitAPI {
@@ -49,3 +52,5 @@ public:
static InjectedBundleTest::Register<NewFirstVisuallyNonEmptyLayoutTest> registrar("NewFirstVisuallyNonEmptyLayoutTest");
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/PageGroup.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/PageGroup.cpp
new file mode 100644
index 000000000..c1a5071ab
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/PageGroup.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import <WebKit/WKFoundation.h>
+
+#if WK_HAVE_C_SPI
+
+#import "PlatformUtilities.h"
+#import "PlatformWebView.h"
+#import "Test.h"
+#import <WebKit/WKPageGroup.h>
+#import <WebKit/WKUserContentControllerRef.h>
+#import <WebKit/WKPageConfigurationRef.h>
+
+namespace TestWebKitAPI {
+
+TEST(PageGroup, DefaultUserContentController)
+{
+ auto pageConfiguration = adoptWK(WKPageConfigurationCreate());
+ auto context = adoptWK(WKContextCreate());
+ WKPageConfigurationSetContext(pageConfiguration.get(), context.get());
+ auto pageGroup = adoptWK(WKPageGroupCreateWithIdentifier(Util::toWK("TestPageGroup").get()));
+ WKPageConfigurationSetPageGroup(pageConfiguration.get(), pageGroup.get());
+
+ auto pageGroupUserContentController = retainWK(WKPageGroupGetUserContentController(pageGroup.get()));
+
+ EXPECT_NULL(WKPageConfigurationGetUserContentController(pageConfiguration.get()));
+
+ PlatformWebView webView(pageConfiguration.get());
+ auto copiedPageConfiguration = adoptWK(WKPageCopyPageConfiguration(webView.page()));
+
+ ASSERT_EQ(pageGroupUserContentController.get(), WKPageConfigurationGetUserContentController(copiedPageConfiguration.get()));
+}
+
+TEST(PageGroup, CustomUserContentController)
+{
+ auto pageConfiguration = adoptWK(WKPageConfigurationCreate());
+ auto context = adoptWK(WKContextCreate());
+ WKPageConfigurationSetContext(pageConfiguration.get(), context.get());
+ auto pageGroup = adoptWK(WKPageGroupCreateWithIdentifier(Util::toWK("TestPageGroup").get()));
+ WKPageConfigurationSetPageGroup(pageConfiguration.get(), pageGroup.get());
+ auto userContentController = adoptWK(WKUserContentControllerCreate());
+ WKPageConfigurationSetUserContentController(pageConfiguration.get(), userContentController.get());
+
+ auto pageGroupUserContentController = retainWK(WKPageGroupGetUserContentController(pageGroup.get()));
+
+ EXPECT_EQ(userContentController.get(), WKPageConfigurationGetUserContentController(pageConfiguration.get()));
+
+ PlatformWebView webView(pageConfiguration.get());
+ auto copiedPageConfiguration = adoptWK(WKPageCopyPageConfiguration(webView.page()));
+
+ EXPECT_EQ(userContentController.get(), WKPageConfigurationGetUserContentController(copiedPageConfiguration.get()));
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/PageLoadBasic.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/PageLoadBasic.cpp
index 26a6fddfd..7ac216b2a 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/PageLoadBasic.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/PageLoadBasic.cpp
@@ -24,10 +24,13 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include "Test.h"
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -151,4 +154,26 @@ TEST(WebKit2, PageLoadBasic)
Util::run(&test1Done);
}
+TEST(WebKit2, PageReload)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+ PlatformWebView webView(context.get());
+
+ // Reload test before url loading.
+ WKPageReload(webView.page());
+ WKPageReload(webView.page());
+
+ WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("simple", "html"));
+ WKPageLoadURL(webView.page(), url.get());
+
+ // Reload test after url loading.
+ WKPageReload(webView.page());
+
+ WKRetainPtr<WKURLRef> activeUrl = adoptWK(WKPageCopyActiveURL(webView.page()));
+ ASSERT_NOT_NULL(activeUrl.get());
+ EXPECT_TRUE(WKURLIsEqual(activeUrl.get(), url.get()));
+}
+
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/PageLoadDidChangeLocationWithinPageForFrame.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/PageLoadDidChangeLocationWithinPageForFrame.cpp
index 8ef9bb66d..46838db93 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/PageLoadDidChangeLocationWithinPageForFrame.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/PageLoadDidChangeLocationWithinPageForFrame.cpp
@@ -24,9 +24,12 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -84,3 +87,5 @@ TEST(WebKit2, PageLoadDidChangeLocationWithinPageForFrame)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/ParentFrame.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/ParentFrame.cpp
index ec97ac0b0..7953608c8 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/ParentFrame.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/ParentFrame.cpp
@@ -24,9 +24,12 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
-#include <WebKit2/WKContextPrivate.h>
+#include <WebKit/WKContextPrivate.h>
namespace TestWebKitAPI {
@@ -68,3 +71,5 @@ TEST(WebKit2, ParentFrame)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/ParentFrame_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/ParentFrame_Bundle.cpp
index b23336293..e1da9ee02 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/ParentFrame_Bundle.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/ParentFrame_Bundle.cpp
@@ -24,12 +24,15 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "InjectedBundleTest.h"
#include "PlatformUtilities.h"
-#include <WebKit2/WKBundlePage.h>
-#include <WebKit2/WKBundleFrame.h>
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKBundlePage.h>
+#include <WebKit/WKBundleFrame.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -77,3 +80,5 @@ void ParentFrameTest::didCreatePage(WKBundleRef bundle, WKBundlePageRef page)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/PasteboardNotifications_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/PasteboardNotifications_Bundle.cpp
new file mode 100644
index 000000000..8c1404e7a
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/PasteboardNotifications_Bundle.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "InjectedBundleTest.h"
+
+#include "PlatformUtilities.h"
+#include <WebKit/WKArray.h>
+#include <WebKit/WKBundlePage.h>
+#include <WebKit/WKBundleBackForwardListItem.h>
+#include <WebKit/WKWebArchive.h>
+
+namespace TestWebKitAPI {
+
+class PasteboardNotificationsTest : public InjectedBundleTest {
+public:
+ PasteboardNotificationsTest(const std::string& identifier);
+
+ virtual void didCreatePage(WKBundleRef, WKBundlePageRef);
+};
+
+static InjectedBundleTest::Register<PasteboardNotificationsTest> registrar("PasteboardNotificationsTest");
+
+static void willWriteToPasteboard(WKBundlePageRef page, WKBundleRangeHandleRef range, const void*)
+{
+ if (!range)
+ WKBundlePostMessage(InjectedBundleController::singleton().bundle(), Util::toWK("PasteboardNotificationTestDoneMessageName").get(), Util::toWK("willWritetoPasteboardFail").get());
+}
+
+static void getPasteboardDataForRange(WKBundlePageRef, WKBundleRangeHandleRef range, WKArrayRef* pasteboardTypes, WKArrayRef* pasteboardData, const void*)
+{
+ WKTypeRef typeName = WKStringCreateWithUTF8CString("AnotherArchivePasteboardType");
+ *pasteboardTypes = WKArrayCreateAdoptingValues(&typeName, 1);
+ WKTypeRef typeData = WKWebArchiveCopyData(WKWebArchiveCreateFromRange(range));
+ *pasteboardData = WKArrayCreateAdoptingValues(&typeData, 1);
+}
+
+static void didWriteToPasteboard(WKBundlePageRef, const void*)
+{
+ WKBundlePostMessage(InjectedBundleController::singleton().bundle(), Util::toWK("PasteboardNotificationTestDoneMessageName").get(), Util::toWK("didWriteToPasteboard").get());
+}
+
+PasteboardNotificationsTest::PasteboardNotificationsTest(const std::string& identifier)
+ : InjectedBundleTest(identifier)
+{
+}
+
+void PasteboardNotificationsTest::didCreatePage(WKBundleRef bundle, WKBundlePageRef page)
+{
+ WKBundlePageEditorClientV1 pageEditorClient;
+ memset(&pageEditorClient, 0, sizeof(pageEditorClient));
+
+ pageEditorClient.base.version = 1;
+ pageEditorClient.base.clientInfo = this;
+ pageEditorClient.willWriteToPasteboard = willWriteToPasteboard;
+ pageEditorClient.getPasteboardDataForRange = getPasteboardDataForRange;
+ pageEditorClient.didWriteToPasteboard = didWriteToPasteboard;
+
+ WKBundlePageSetEditorClient(page, &pageEditorClient.base);
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/PendingAPIRequestURL.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/PendingAPIRequestURL.cpp
new file mode 100644
index 000000000..22a8f04fa
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/PendingAPIRequestURL.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include "Test.h"
+#include <WebKit/WKRetainPtr.h>
+
+namespace TestWebKitAPI {
+
+static bool done;
+
+TEST(WebKit2, PendingAPIRequestURL)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+ PlatformWebView webView(context.get());
+
+ WKPageLoaderClientV0 loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+ loaderClient.base.version = 0;
+ loaderClient.didFinishLoadForFrame = [](WKPageRef, WKFrameRef, WKTypeRef, const void*) { done = true; };
+ WKPageSetPageLoaderClient(webView.page(), &loaderClient.base);
+
+ WKRetainPtr<WKURLRef> activeURL = adoptWK(WKPageCopyActiveURL(webView.page()));
+ EXPECT_NULL(activeURL.get());
+
+ WKRetainPtr<WKURLRef> url = adoptWK(Util::createURLForResource("simple", "html"));
+ WKPageLoadURL(webView.page(), url.get());
+ activeURL = adoptWK(WKPageCopyActiveURL(webView.page()));
+ ASSERT_NOT_NULL(activeURL.get());
+ EXPECT_TRUE(WKURLIsEqual(activeURL.get(), url.get()));
+ Util::run(&done);
+ done = false;
+
+ WKPageReload(webView.page());
+ activeURL = adoptWK(WKPageCopyActiveURL(webView.page()));
+ ASSERT_NOT_NULL(activeURL.get());
+ EXPECT_TRUE(WKURLIsEqual(activeURL.get(), url.get()));
+ Util::run(&done);
+ done = false;
+
+ WKRetainPtr<WKStringRef> htmlString = Util::toWK("<body>Hello, World</body>");
+ WKRetainPtr<WKURLRef> blankURL = adoptWK(WKURLCreateWithUTF8CString("about:blank"));
+ WKPageLoadHTMLString(webView.page(), htmlString.get(), nullptr);
+ activeURL = adoptWK(WKPageCopyActiveURL(webView.page()));
+ ASSERT_NOT_NULL(activeURL.get());
+ EXPECT_TRUE(WKURLIsEqual(activeURL.get(), blankURL.get()));
+ Util::run(&done);
+ done = false;
+
+ WKPageReload(webView.page());
+ activeURL = adoptWK(WKPageCopyActiveURL(webView.page()));
+ ASSERT_NOT_NULL(activeURL.get());
+ EXPECT_TRUE(WKURLIsEqual(activeURL.get(), blankURL.get()));
+ Util::run(&done);
+ done = false;
+
+ url = adoptWK(Util::createURLForResource("simple2", "html"));
+ WKPageLoadHTMLString(webView.page(), htmlString.get(), url.get());
+ activeURL = adoptWK(WKPageCopyActiveURL(webView.page()));
+ ASSERT_NOT_NULL(activeURL.get());
+ EXPECT_TRUE(WKURLIsEqual(activeURL.get(), url.get()));
+ Util::run(&done);
+ done = false;
+
+ WKPageReload(webView.page());
+ activeURL = adoptWK(WKPageCopyActiveURL(webView.page()));
+ ASSERT_NOT_NULL(activeURL.get());
+ EXPECT_TRUE(WKURLIsEqual(activeURL.get(), url.get()));
+ Util::run(&done);
+ done = false;
+
+ WKRetainPtr<WKDataRef> data = adoptWK(WKDataCreate(nullptr, 0));
+ WKPageLoadData(webView.page(), data.get(), nullptr, nullptr, nullptr);
+ activeURL = adoptWK(WKPageCopyActiveURL(webView.page()));
+ ASSERT_NOT_NULL(activeURL.get());
+ EXPECT_TRUE(WKURLIsEqual(activeURL.get(), blankURL.get()));
+ Util::run(&done);
+ done = false;
+
+ WKPageReload(webView.page());
+ activeURL = adoptWK(WKPageCopyActiveURL(webView.page()));
+ ASSERT_NOT_NULL(activeURL.get());
+ EXPECT_TRUE(WKURLIsEqual(activeURL.get(), blankURL.get()));
+ Util::run(&done);
+ done = false;
+
+ WKPageLoadData(webView.page(), data.get(), nullptr, nullptr, url.get());
+ activeURL = adoptWK(WKPageCopyActiveURL(webView.page()));
+ ASSERT_NOT_NULL(activeURL.get());
+ EXPECT_TRUE(WKURLIsEqual(activeURL.get(), url.get()));
+ Util::run(&done);
+ done = false;
+
+ WKPageReload(webView.page());
+ activeURL = adoptWK(WKPageCopyActiveURL(webView.page()));
+ ASSERT_NOT_NULL(activeURL.get());
+ EXPECT_TRUE(WKURLIsEqual(activeURL.get(), url.get()));
+ Util::run(&done);
+ done = false;
+
+ WKPageLoadAlternateHTMLString(webView.page(), htmlString.get(), nullptr, url.get());
+ activeURL = adoptWK(WKPageCopyActiveURL(webView.page()));
+ ASSERT_NOT_NULL(activeURL.get());
+ EXPECT_TRUE(WKURLIsEqual(activeURL.get(), url.get()));
+ Util::run(&done);
+ done = false;
+
+ WKPageReload(webView.page());
+ activeURL = adoptWK(WKPageCopyActiveURL(webView.page()));
+ ASSERT_NOT_NULL(activeURL.get());
+ EXPECT_TRUE(WKURLIsEqual(activeURL.get(), url.get()));
+ Util::run(&done);
+ done = false;
+
+ WKRetainPtr<WKStringRef> plainTextString = Util::toWK("Hello, World");
+ WKPageLoadPlainTextString(webView.page(), plainTextString.get());
+ activeURL = adoptWK(WKPageCopyActiveURL(webView.page()));
+ ASSERT_NOT_NULL(activeURL.get());
+ EXPECT_TRUE(WKURLIsEqual(activeURL.get(), blankURL.get()));
+ Util::run(&done);
+ done = false;
+
+ WKPageReload(webView.page());
+ activeURL = adoptWK(WKPageCopyActiveURL(webView.page()));
+ ASSERT_NOT_NULL(activeURL.get());
+ EXPECT_TRUE(WKURLIsEqual(activeURL.get(), blankURL.get()));
+ Util::run(&done);
+ done = false;
+
+ url = adoptWK(WKURLCreateWithUTF8CString("file:///tmp/index.html"));
+ WKPageLoadFile(webView.page(), url.get(), nullptr);
+ activeURL = adoptWK(WKPageCopyActiveURL(webView.page()));
+ ASSERT_NOT_NULL(activeURL.get());
+ EXPECT_TRUE(WKURLIsEqual(activeURL.get(), url.get()));
+ WKPageStopLoading(webView.page());
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/PreventEmptyUserAgent.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/PreventEmptyUserAgent.cpp
index c5acb6172..7712b142c 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/PreventEmptyUserAgent.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/PreventEmptyUserAgent.cpp
@@ -24,12 +24,15 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include "Test.h"
#include <JavaScriptCore/JSContextRef.h>
-#include <WebKit2/WKRetainPtr.h>
-#include <WebKit2/WKSerializedScriptValue.h>
+#include <WebKit/WKRetainPtr.h>
+#include <WebKit/WKSerializedScriptValue.h>
namespace TestWebKitAPI {
@@ -68,3 +71,5 @@ TEST(WebKit2, PreventEmptyUserAgent)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/PrivateBrowsingPushStateNoHistoryCallback.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/PrivateBrowsingPushStateNoHistoryCallback.cpp
index 3d0db3d2f..532c92373 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/PrivateBrowsingPushStateNoHistoryCallback.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/PrivateBrowsingPushStateNoHistoryCallback.cpp
@@ -24,24 +24,33 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include "Test.h"
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
-static bool testDone;
+static bool didNavigate;
+static bool didSameDocumentNavigation;
-static void didNavigateWithNavigationData(WKContextRef context, WKPageRef page, WKNavigationDataRef navigationData, WKFrameRef frame, const void* clientInfo)
+static void didNavigateWithoutNavigationData(WKContextRef context, WKPageRef page, WKNavigationDataRef navigationData, WKFrameRef frame, const void* clientInfo)
{
// This should never be called when navigating in Private Browsing.
FAIL();
}
+static void didNavigateWithNavigationData(WKContextRef context, WKPageRef page, WKNavigationDataRef navigationData, WKFrameRef frame, const void* clientInfo)
+{
+ didNavigate = true;
+}
+
static void didSameDocumentNavigationForFrame(WKPageRef page, WKFrameRef frame, WKSameDocumentNavigationType type, WKTypeRef userData, const void *clientInfo)
{
- testDone = true;
+ didSameDocumentNavigation = true;
}
TEST(WebKit2, PrivateBrowsingPushStateNoHistoryCallback)
@@ -52,7 +61,7 @@ TEST(WebKit2, PrivateBrowsingPushStateNoHistoryCallback)
memset(&historyClient, 0, sizeof(historyClient));
historyClient.base.version = 0;
- historyClient.didNavigateWithNavigationData = didNavigateWithNavigationData;
+ historyClient.didNavigateWithNavigationData = didNavigateWithoutNavigationData;
WKContextSetHistoryClient(context.get(), &historyClient.base);
@@ -75,7 +84,18 @@ TEST(WebKit2, PrivateBrowsingPushStateNoHistoryCallback)
WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("push-state", "html"));
WKPageLoadURL(webView.page(), url.get());
- Util::run(&testDone);
+ Util::run(&didSameDocumentNavigation);
+
+ WKPreferencesSetPrivateBrowsingEnabled(preferences.get(), false);
+
+ historyClient.didNavigateWithNavigationData = didNavigateWithNavigationData;
+ WKContextSetHistoryClient(context.get(), &historyClient.base);
+
+ WKPageLoadURL(webView.page(), url.get());
+
+ Util::run(&didNavigate);
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/ProvisionalURLAfterWillSendRequestCallback.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/ProvisionalURLAfterWillSendRequestCallback.cpp
new file mode 100644
index 000000000..2979f792c
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/ProvisionalURLAfterWillSendRequestCallback.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include "Test.h"
+#include <WebKit/WKContext.h>
+#include <WebKit/WKFrame.h>
+#include <WebKit/WKRetainPtr.h>
+
+namespace TestWebKitAPI {
+
+static bool committedLoad;
+
+static void didCommitLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void*)
+{
+ if (!WKFrameIsMainFrame(frame))
+ return;
+
+ // The provisional URL should be null.
+ EXPECT_NULL(WKFrameCopyProvisionalURL(frame));
+
+ // The committed URL is the last known provisional URL.
+ WKRetainPtr<WKURLRef> committedURL = adoptWK(WKFrameCopyURL(frame));
+ ASSERT_NOT_NULL(committedURL.get());
+ WKRetainPtr<WKURLRef> activeURL = adoptWK(WKPageCopyActiveURL(page));
+ ASSERT_NOT_NULL(activeURL.get());
+ EXPECT_TRUE(WKURLIsEqual(committedURL.get(), activeURL.get()));
+ assert(WKGetTypeID(userData) == WKURLGetTypeID());
+ EXPECT_TRUE(WKURLIsEqual(committedURL.get(), static_cast<WKURLRef>(userData)));
+
+ WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("simple2", "html"));
+ EXPECT_TRUE(WKURLIsEqual(committedURL.get(), url.get()));
+
+ committedLoad = true;
+}
+
+TEST(WebKit2, ProvisionalURLAfterWillSendRequestCallback)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, Util::createContextForInjectedBundleTest("ProvisionalURLAfterWillSendRequestCallbackTest"));
+
+ WKContextInjectedBundleClientV0 injectedBundleClient;
+ memset(&injectedBundleClient, 0, sizeof(injectedBundleClient));
+ injectedBundleClient.base.version = 0;
+ WKContextSetInjectedBundleClient(context.get(), &injectedBundleClient.base);
+
+ PlatformWebView webView(context.get());
+
+ WKPageLoaderClientV0 loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+
+ loaderClient.base.version = 0;
+ loaderClient.didCommitLoadForFrame = didCommitLoadForFrame;
+ WKPageSetPageLoaderClient(webView.page(), &loaderClient.base);
+
+ WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("simple", "html"));
+ WKPageLoadURL(webView.page(), url.get());
+ Util::run(&committedLoad);
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/ProvisionalURLAfterWillSendRequestCallback_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/ProvisionalURLAfterWillSendRequestCallback_Bundle.cpp
new file mode 100644
index 000000000..6c3d74a95
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/ProvisionalURLAfterWillSendRequestCallback_Bundle.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2016 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "InjectedBundleTest.h"
+#include "PlatformUtilities.h"
+#include "Test.h"
+#include <WebKit/WKBundleFrame.h>
+#include <WebKit/WKBundlePage.h>
+#include <WebKit/WKRetainPtr.h>
+
+namespace TestWebKitAPI {
+
+class ProvisionalURLAfterWillSendRequestCallbackTest : public InjectedBundleTest {
+public:
+ ProvisionalURLAfterWillSendRequestCallbackTest(const std::string& identifier)
+ : InjectedBundleTest(identifier)
+ {
+ }
+
+ static WKURLRequestRef willSendRequestForFrame(WKBundlePageRef, WKBundleFrameRef frame, uint64_t resourceIdentifier, WKURLRequestRef request, WKURLResponseRef redirectResponse, const void*)
+ {
+ if (!WKBundleFrameIsMainFrame(frame)) {
+ WKRetainPtr<WKURLRequestRef> newRequest = request;
+ return newRequest.leakRef();
+ }
+
+ // Change the main frame URL.
+ WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("simple2", "html"));
+ return WKURLRequestCreateWithWKURL(url.get());
+ }
+
+ static void didCommitLoadForFrame(WKBundlePageRef, WKBundleFrameRef frame, WKTypeRef* userData, const void*)
+ {
+ if (!WKBundleFrameIsMainFrame(frame))
+ return;
+ *userData = WKBundleFrameCopyURL(frame);
+ }
+
+ void didCreatePage(WKBundleRef bundle, WKBundlePageRef page) override
+ {
+ WKBundlePageResourceLoadClientV0 resourceLoadClient;
+ memset(&resourceLoadClient, 0, sizeof(resourceLoadClient));
+ resourceLoadClient.base.version = 0;
+ resourceLoadClient.willSendRequestForFrame = willSendRequestForFrame;
+ WKBundlePageSetResourceLoadClient(page, &resourceLoadClient.base);
+
+ WKBundlePageLoaderClientV0 pageLoaderClient;
+ memset(&pageLoaderClient, 0, sizeof(pageLoaderClient));
+ pageLoaderClient.base.version = 0;
+ pageLoaderClient.didCommitLoadForFrame = didCommitLoadForFrame;
+ WKBundlePageSetPageLoaderClient(page, &pageLoaderClient.base);
+ }
+};
+
+static InjectedBundleTest::Register<ProvisionalURLAfterWillSendRequestCallbackTest> registrar("ProvisionalURLAfterWillSendRequestCallbackTest");
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/ReloadPageAfterCrash.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/ReloadPageAfterCrash.cpp
index fb265abc1..190c85341 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/ReloadPageAfterCrash.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/ReloadPageAfterCrash.cpp
@@ -24,10 +24,13 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include "Test.h"
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -86,3 +89,5 @@ TEST(WebKit2, ReloadPageAfterCrash)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/ResizeReversePaginatedWebView.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/ResizeReversePaginatedWebView.cpp
index af1f1e705..f2e1ae17f 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/ResizeReversePaginatedWebView.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/ResizeReversePaginatedWebView.cpp
@@ -24,14 +24,17 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "JavaScriptTest.h"
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include "Test.h"
#include <JavaScriptCore/JSContextRef.h>
-#include <WebKit2/WKContextPrivate.h>
-#include <WebKit2/WKPagePrivate.h>
-#include <WebKit2/WKSerializedScriptValue.h>
+#include <WebKit/WKContextPrivate.h>
+#include <WebKit/WKPagePrivate.h>
+#include <WebKit/WKSerializedScriptValue.h>
namespace TestWebKitAPI {
@@ -88,3 +91,5 @@ TEST(WebKit2, ResizeReversePaginatedWebView)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/ResizeWindowAfterCrash.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/ResizeWindowAfterCrash.cpp
index 4cd9eddb4..2dfc8b4c2 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/ResizeWindowAfterCrash.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/ResizeWindowAfterCrash.cpp
@@ -24,10 +24,13 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include "Test.h"
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -97,3 +100,5 @@ TEST(WebKit2, ResizeWindowAfterCrash)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/ResponsivenessTimerDoesntFireEarly.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/ResponsivenessTimerDoesntFireEarly.cpp
index 9de11a286..a034637e3 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/ResponsivenessTimerDoesntFireEarly.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/ResponsivenessTimerDoesntFireEarly.cpp
@@ -24,6 +24,9 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
@@ -96,3 +99,5 @@ TEST(WebKit2, ResponsivenessTimerDoesntFireEarly)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/ResponsivenessTimerDoesntFireEarly_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/ResponsivenessTimerDoesntFireEarly_Bundle.cpp
index 50d664f38..ddd2ca158 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/ResponsivenessTimerDoesntFireEarly_Bundle.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/ResponsivenessTimerDoesntFireEarly_Bundle.cpp
@@ -24,6 +24,9 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "InjectedBundleTest.h"
#include "PlatformUtilities.h"
@@ -57,3 +60,5 @@ void ResponsivenessTimerDoesntFireEarlyTest::didReceiveMessage(WKBundleRef bundl
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/RestoreSessionStateContainingFormData.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/RestoreSessionStateContainingFormData.cpp
index 079c51856..b16537e70 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/RestoreSessionStateContainingFormData.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/RestoreSessionStateContainingFormData.cpp
@@ -24,10 +24,14 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "JavaScriptTest.h"
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include "Test.h"
+#include <WebKit/WKSessionStateRef.h>
namespace TestWebKitAPI {
@@ -49,7 +53,7 @@ static void setPageLoaderClient(WKPageRef page)
WKPageSetPageLoaderClient(page, &loaderClient.base);
}
-static WKRetainPtr<WKDataRef> createSessionStateContainingFormData(WKContextRef context)
+static WKRetainPtr<WKDataRef> createSessionStateDataContainingFormData(WKContextRef context)
{
PlatformWebView webView(context);
setPageLoaderClient(webView.page());
@@ -62,7 +66,8 @@ static WKRetainPtr<WKDataRef> createSessionStateContainingFormData(WKContextRef
Util::run(&didFinishLoad);
didFinishLoad = false;
- return adoptWK(WKPageCopySessionState(webView.page(), 0, 0));
+ auto sessionState = adoptWK(static_cast<WKSessionStateRef>(WKPageCopySessionState(webView.page(), reinterpret_cast<void*>(1), nullptr)));
+ return adoptWK(WKSessionStateCopyData(sessionState.get()));
}
TEST(WebKit2, RestoreSessionStateContainingFormData)
@@ -75,13 +80,17 @@ TEST(WebKit2, RestoreSessionStateContainingFormData)
PlatformWebView webView(context.get());
setPageLoaderClient(webView.page());
- WKRetainPtr<WKDataRef> data = createSessionStateContainingFormData(context.get());
+ WKRetainPtr<WKDataRef> data = createSessionStateDataContainingFormData(context.get());
EXPECT_NOT_NULL(data);
- WKPageRestoreFromSessionState(webView.page(), data.get());
+ auto sessionState = adoptWK(WKSessionStateCreateFromData(data.get()));
+ WKPageRestoreFromSessionState(webView.page(), sessionState.get());
+
Util::run(&didFinishLoad);
EXPECT_TRUE(WKPageCanGoBack(webView.page()));
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/RestoreSessionStateWithoutNavigation.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/RestoreSessionStateWithoutNavigation.cpp
new file mode 100644
index 000000000..d597ba5fd
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/RestoreSessionStateWithoutNavigation.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "JavaScriptTest.h"
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include "Test.h"
+#include <WebKit/WKPagePrivate.h>
+#include <WebKit/WKSessionStateRef.h>
+
+namespace TestWebKitAPI {
+
+static bool didFinishLoad;
+static bool didChangeBackForwardList;
+
+static void didFinishLoadForFrame(WKPageRef, WKFrameRef, WKTypeRef, const void*)
+{
+ didFinishLoad = true;
+}
+
+static void didChangeBackForwardListForPage(WKPageRef, WKBackForwardListItemRef addedItem, WKArrayRef, const void*)
+{
+ didChangeBackForwardList = true;
+}
+
+static void setPageLoaderClient(WKPageRef page)
+{
+ WKPageLoaderClientV0 loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+
+ loaderClient.base.version = 0;
+ loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+ loaderClient.didChangeBackForwardList = didChangeBackForwardListForPage;
+
+ WKPageSetPageLoaderClient(page, &loaderClient.base);
+}
+
+static WKRetainPtr<WKDataRef> createSessionStateData(WKContextRef context)
+{
+ PlatformWebView webView(context);
+ setPageLoaderClient(webView.page());
+
+ WKPageLoadURL(webView.page(), adoptWK(Util::createURLForResource("simple", "html")).get());
+ Util::run(&didFinishLoad);
+ didFinishLoad = false;
+
+ auto sessionState = adoptWK(static_cast<WKSessionStateRef>(WKPageCopySessionState(webView.page(), reinterpret_cast<void*>(1), nullptr)));
+ return adoptWK(WKSessionStateCopyData(sessionState.get()));
+}
+
+TEST(WebKit2, RestoreSessionStateWithoutNavigation)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+
+ PlatformWebView webView(context.get());
+ setPageLoaderClient(webView.page());
+
+ WKRetainPtr<WKDataRef> data = createSessionStateData(context.get());
+ EXPECT_NOT_NULL(data);
+
+ auto sessionState = adoptWK(WKSessionStateCreateFromData(data.get()));
+ WKPageRestoreFromSessionStateWithoutNavigation(webView.page(), sessionState.get());
+
+ Util::run(&didChangeBackForwardList);
+
+ WKRetainPtr<WKURLRef> committedURL = adoptWK(WKPageCopyCommittedURL(webView.page()));
+ EXPECT_NULL(committedURL.get());
+
+ auto backForwardList = WKPageGetBackForwardList(webView.page());
+ auto currentItem = WKBackForwardListGetCurrentItem(backForwardList);
+ auto currentItemURL = adoptWK(WKBackForwardListItemCopyURL(currentItem));
+ auto expectedURL = adoptWK(Util::createURLForResource("simple", "html"));
+ EXPECT_NOT_NULL(expectedURL);
+ EXPECT_TRUE(WKURLIsEqual(currentItemURL.get(), expectedURL.get()));
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/ScrollPinningBehaviors.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/ScrollPinningBehaviors.cpp
index 5b628a932..015571f5f 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/ScrollPinningBehaviors.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/ScrollPinningBehaviors.cpp
@@ -24,15 +24,18 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "JavaScriptTest.h"
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include "Test.h"
#include <JavaScriptCore/JSContextRef.h>
-#include <WebKit2/WKContextPrivate.h>
-#include <WebKit2/WKPagePrivate.h>
-#include <WebKit2/WKPreferencesPrivate.h>
-#include <WebKit2/WKSerializedScriptValue.h>
+#include <WebKit/WKContextPrivate.h>
+#include <WebKit/WKPagePrivate.h>
+#include <WebKit/WKPreferencesRefPrivate.h>
+#include <WebKit/WKSerializedScriptValue.h>
namespace TestWebKitAPI {
@@ -95,3 +98,5 @@ TEST(WebKit2, ScrollPinningBehaviors)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/ShouldGoToBackForwardListItem.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/ShouldGoToBackForwardListItem.cpp
index 5754155ed..f41e44a5e 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/ShouldGoToBackForwardListItem.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/ShouldGoToBackForwardListItem.cpp
@@ -24,11 +24,14 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include "Test.h"
-#include <WebKit2/WKString.h>
+#include <WebKit/WKString.h>
namespace TestWebKitAPI {
@@ -90,3 +93,5 @@ TEST(WebKit2, ShouldGoToBackForwardListItem)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/ShouldGoToBackForwardListItem_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/ShouldGoToBackForwardListItem_Bundle.cpp
index dd81bf3bf..5eba75a9e 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/ShouldGoToBackForwardListItem_Bundle.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/ShouldGoToBackForwardListItem_Bundle.cpp
@@ -24,11 +24,14 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "InjectedBundleTest.h"
#include "PlatformUtilities.h"
-#include <WebKit2/WKBundlePage.h>
-#include <WebKit2/WKBundleBackForwardListItem.h>
+#include <WebKit/WKBundlePage.h>
+#include <WebKit/WKBundleBackForwardListItem.h>
namespace TestWebKitAPI {
@@ -68,3 +71,5 @@ void ShouldGoToBackForwardListItemTest::didCreatePage(WKBundleRef bundle, WKBund
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/ShouldKeepCurrentBackForwardListItemInList.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/ShouldKeepCurrentBackForwardListItemInList.cpp
new file mode 100644
index 000000000..f8098e6f1
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/ShouldKeepCurrentBackForwardListItemInList.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include "Test.h"
+
+// This test navigates from simple.html, to simple2.html, to simple3.html
+// When navigating from simple2 to simple3, it disallows the simple2 back/forward list item from staying in the list
+// It then navigates back from simple3, expecting to land at simple.
+
+namespace TestWebKitAPI {
+
+static bool finished = false;
+static bool successfulSoFar = true;
+static int navigationNumber = 0;
+
+static bool itemURLLastComponentIsString(WKBackForwardListItemRef item, const char* string)
+{
+ WKRetainPtr<WKURLRef> url = adoptWK(WKBackForwardListItemCopyURL(item));
+ WKRetainPtr<WKStringRef> path = adoptWK(WKURLCopyLastPathComponent(url.get()));
+
+ return WKStringIsEqualToUTF8CString(path.get(), string);
+}
+
+static void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef, const void*)
+{
+ // Only mark finished when the main frame loads
+ if (!WKFrameIsMainFrame(frame))
+ return;
+
+ finished = true;
+ navigationNumber++;
+
+ WKBackForwardListRef list = WKPageGetBackForwardList(page);
+ WKBackForwardListItemRef currentItem = WKBackForwardListGetCurrentItem(list);
+ WKBackForwardListItemRef backItem = WKBackForwardListGetBackItem(list);
+ WKBackForwardListItemRef forwardItem = WKBackForwardListGetForwardItem(list);
+ unsigned forwardCount = WKBackForwardListGetForwardListCount(list);
+
+ // This test should never have a forward list.
+ if (forwardCount)
+ successfulSoFar = false;
+
+ if (navigationNumber == 1) {
+ // We've only performed 1 navigation, we should only have a current item.
+ if (!currentItem || !itemURLLastComponentIsString(currentItem, "simple.html"))
+ successfulSoFar = false;
+ if (backItem || forwardItem)
+ successfulSoFar = false;
+ } else if (navigationNumber == 2) {
+ // On the second navigation, simple2 should be current and simple should be the back item.
+ if (!currentItem || !itemURLLastComponentIsString(currentItem, "simple2.html"))
+ successfulSoFar = false;
+ if (!backItem || !itemURLLastComponentIsString(backItem, "simple.html"))
+ successfulSoFar = false;
+ if (forwardItem)
+ successfulSoFar = false;
+ } else if (navigationNumber == 3) {
+ // On the third navigation the item for simple2 should have been removed.
+ // So simple3 should be current and simple should still be the back item.
+ if (!currentItem || !itemURLLastComponentIsString(currentItem, "simple3.html"))
+ successfulSoFar = false;
+ if (!backItem || !itemURLLastComponentIsString(backItem, "simple.html"))
+ successfulSoFar = false;
+ if (forwardItem)
+ successfulSoFar = false;
+ } else if (navigationNumber == 4) {
+ // After the fourth navigation (which was a "back" navigation), the item for simple3 should have been removed.
+ // So simple should be current and there should be no other items.
+ if (!currentItem || !itemURLLastComponentIsString(currentItem, "simple.html"))
+ successfulSoFar = false;
+ if (backItem || forwardItem)
+ successfulSoFar = false;
+ }
+}
+
+static void willGoToBackForwardListItem(WKPageRef, WKBackForwardListItemRef item, WKTypeRef userData, const void*)
+{
+ if (!itemURLLastComponentIsString(item, "simple.html"))
+ successfulSoFar = false;
+}
+
+static bool shouldKeepCurrentBackForwardListItemInList(WKPageRef page, WKBackForwardListItemRef item, const void*)
+{
+ // We make sure the item for "simple2.html" is removed when we navigate to "simple3.html"
+ // We also want to make sure the item for "simple3.html" is removed when we go back to "simple.html"
+ // So we only want to keep "simple.html"
+ return itemURLLastComponentIsString(item, "simple.html");
+}
+
+static void setPageLoaderClient(WKPageRef page)
+{
+ WKPageLoaderClientV5 loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+
+ loaderClient.base.version = 5;
+ loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+ loaderClient.shouldKeepCurrentBackForwardListItemInList = shouldKeepCurrentBackForwardListItemInList;
+ loaderClient.willGoToBackForwardListItem = willGoToBackForwardListItem;
+
+ WKPageSetPageLoaderClient(page, &loaderClient.base);
+}
+
+TEST(WebKit2, ShouldKeepCurrentBackForwardListItemInList)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+
+ PlatformWebView webView(context.get());
+ setPageLoaderClient(webView.page());
+
+ WKPageLoadURL(webView.page(), adoptWK(Util::createURLForResource("simple", "html")).get());
+ Util::run(&finished);
+ EXPECT_EQ(successfulSoFar, true);
+
+ finished = false;
+ WKPageLoadURL(webView.page(), adoptWK(Util::createURLForResource("simple2", "html")).get());
+ Util::run(&finished);
+ EXPECT_EQ(successfulSoFar, true);
+
+ finished = false;
+ WKPageLoadURL(webView.page(), adoptWK(Util::createURLForResource("simple3", "html")).get());
+ Util::run(&finished);
+ EXPECT_EQ(successfulSoFar, true);
+
+ finished = false;
+ WKPageGoBack(webView.page());
+ Util::run(&finished);
+
+ EXPECT_EQ(successfulSoFar, true);
+ EXPECT_EQ(navigationNumber, 4);
+}
+
+} // namespace TestWebKitAPI
+
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/SpacebarScrolling.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/SpacebarScrolling.cpp
index 577e0d77c..226f52cc2 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/SpacebarScrolling.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/SpacebarScrolling.cpp
@@ -24,11 +24,14 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "JavaScriptTest.h"
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
-#include <WebKit2/WKRetainPtr.h>
-#include <WebKit2/WKPreferencesPrivate.h>
+#include <WebKit/WKRetainPtr.h>
+#include <WebKit/WKPreferencesPrivate.h>
namespace TestWebKitAPI {
@@ -86,13 +89,11 @@ TEST(WebKit2, SpacebarScrolling)
EXPECT_JS_FALSE(webView.page(), "isDocumentScrolled()");
EXPECT_JS_TRUE(webView.page(), "textFieldContainsSpace()");
- // On Mac, a key down event represents both a raw key down and a key press. On Windows, a key
- // down event only represents a raw key down. We expect the key press to be handled (because it
- // inserts text into the text field). But the raw key down should not be handled.
-#if PLATFORM(MAC)
+ // On Mac, a key down event represents both a raw key down and a key press.
+ // We expect the key press to be handled (because it inserts text into the text field),
+ // but the raw key down should not be handled.
+#if PLATFORM(COCOA)
EXPECT_FALSE(didNotHandleKeyDownEvent);
-#elif PLATFORM(WIN)
- EXPECT_TRUE(didNotHandleKeyDownEvent);
#endif
EXPECT_JS_EQ(webView.page(), "blurTextField()", "undefined");
@@ -100,18 +101,14 @@ TEST(WebKit2, SpacebarScrolling)
didNotHandleKeyDownEvent = false;
webView.simulateSpacebarKeyPress();
- // This EXPECT_JS_TRUE test fails on Windows port
- // https://bugs.webkit.org/show_bug.cgi?id=84961
-#if !PLATFORM(WIN)
EXPECT_JS_TRUE(webView.page(), "isDocumentScrolled()");
-#endif
EXPECT_JS_TRUE(webView.page(), "textFieldContainsSpace()");
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
EXPECT_FALSE(didNotHandleKeyDownEvent);
-#elif PLATFORM(WIN)
- EXPECT_TRUE(didNotHandleKeyDownEvent);
#endif
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/StopLoadingDuringDidFailProvisionalLoad.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/StopLoadingDuringDidFailProvisionalLoad.cpp
new file mode 100644
index 000000000..386dfd303
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/StopLoadingDuringDidFailProvisionalLoad.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include "Test.h"
+#include <WebKit/WKRetainPtr.h>
+
+namespace TestWebKitAPI {
+
+static bool done;
+static bool receivedMessageFromBundle;
+
+static void didReceiveMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo)
+{
+ if (WKStringIsEqualToUTF8CString(messageName, "StopLoadingDuringDidFailProvisionalLoadTestDone"))
+ receivedMessageFromBundle = true;
+}
+
+static void setInjectedBundleClient(WKContextRef context)
+{
+ WKContextInjectedBundleClientV0 injectedBundleClient;
+ memset(&injectedBundleClient, 0, sizeof(injectedBundleClient));
+
+ injectedBundleClient.didReceiveMessageFromInjectedBundle = didReceiveMessageFromInjectedBundle;
+
+ WKContextSetInjectedBundleClient(context, &injectedBundleClient.base);
+}
+
+static void didFailProvisionalLoadWithErrorForFrame(WKPageRef, WKFrameRef, WKErrorRef, WKTypeRef, const void*)
+{
+ // The injected bundle is notified of the failed load first. If we also receive this callback, the test didn't crash.
+ EXPECT_TRUE(receivedMessageFromBundle);
+ done = true;
+}
+
+TEST(WebKit2, StopLoadingDuringDidFailProvisionalLoadTest)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, Util::createContextForInjectedBundleTest("StopLoadingDuringDidFailProvisionalLoadTest"));
+ setInjectedBundleClient(context.get());
+
+ PlatformWebView webView(context.get());
+
+ WKPageLoaderClientV0 loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+ loaderClient.didFailProvisionalLoadWithErrorForFrame = didFailProvisionalLoadWithErrorForFrame;
+ WKPageSetPageLoaderClient(webView.page(), &loaderClient.base);
+
+ WKRetainPtr<WKURLRef> url(AdoptWK, Util::URLForNonExistentResource());
+ WKPageLoadURL(webView.page(), url.get());
+
+ Util::run(&done);
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/StopLoadingDuringDidFailProvisionalLoad_bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/StopLoadingDuringDidFailProvisionalLoad_bundle.cpp
new file mode 100644
index 000000000..ad302ff51
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/StopLoadingDuringDidFailProvisionalLoad_bundle.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "InjectedBundleTest.h"
+#include "PlatformUtilities.h"
+#include <WebKit/WKBundle.h>
+#include <WebKit/WKBundleFramePrivate.h>
+#include <WebKit/WKBundlePage.h>
+#include <WebKit/WKBundlePagePrivate.h>
+
+namespace TestWebKitAPI {
+
+class StopLoadingDuringDidFailProvisionalLoadTest : public InjectedBundleTest {
+public:
+ StopLoadingDuringDidFailProvisionalLoadTest(const std::string& identifier)
+ : InjectedBundleTest(identifier)
+ {
+ }
+
+ void didCreatePage(WKBundleRef, WKBundlePageRef) override;
+ void didFailProvisionalLoad(WKBundlePageRef, WKBundleFrameRef);
+
+ WKBundleRef m_bundle;
+};
+
+static InjectedBundleTest::Register<StopLoadingDuringDidFailProvisionalLoadTest> registrar("StopLoadingDuringDidFailProvisionalLoadTest");
+
+static void didFailProvisionalLoadWithErrorForFrameCallback(WKBundlePageRef page, WKBundleFrameRef frame, WKErrorRef, WKTypeRef*, const void *clientInfo)
+{
+ ((StopLoadingDuringDidFailProvisionalLoadTest*)clientInfo)->didFailProvisionalLoad(page, frame);
+}
+
+void StopLoadingDuringDidFailProvisionalLoadTest::didCreatePage(WKBundleRef bundle, WKBundlePageRef page)
+{
+ m_bundle = bundle;
+
+ WKBundlePageLoaderClientV2 pageLoaderClient;
+ memset(&pageLoaderClient, 0, sizeof(pageLoaderClient));
+
+ pageLoaderClient.base.version = 2;
+ pageLoaderClient.base.clientInfo = this;
+ pageLoaderClient.didFailProvisionalLoadWithErrorForFrame = didFailProvisionalLoadWithErrorForFrameCallback;
+
+ WKBundlePageSetPageLoaderClient(page, &pageLoaderClient.base);
+}
+
+void StopLoadingDuringDidFailProvisionalLoadTest::didFailProvisionalLoad(WKBundlePageRef page, WKBundleFrameRef)
+{
+ WKBundlePageStopLoading(page);
+ WKBundlePostMessage(m_bundle, Util::toWK("StopLoadingDuringDidFailProvisionalLoadTestDone").get(), nullptr);
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/TerminateTwice.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/TerminateTwice.cpp
index 879312520..5d5c2f79d 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/TerminateTwice.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/TerminateTwice.cpp
@@ -24,6 +24,9 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
@@ -64,3 +67,4 @@ TEST(WebKit2, TerminateTwice)
} // namespace TestWebKitAPI
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/TextFieldDidBeginAndEndEditing.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/TextFieldDidBeginAndEndEditing.cpp
new file mode 100644
index 000000000..731e8e51e
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/TextFieldDidBeginAndEndEditing.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include "Test.h"
+#include <wtf/StdLibExtras.h>
+
+namespace TestWebKitAPI {
+
+struct WebKit2TextFieldBeginAndEditEditingTest : public ::testing::Test {
+ std::unique_ptr<PlatformWebView> webView;
+
+ WKRetainPtr<WKStringRef> messageName;
+
+ bool didFinishLoad { false };
+ bool didReceiveMessage { false };
+
+ static void didReceiveMessageFromInjectedBundle(WKContextRef, WKStringRef messageName, WKTypeRef, const void* clientInfo)
+ {
+ WebKit2TextFieldBeginAndEditEditingTest& client = *static_cast<WebKit2TextFieldBeginAndEditEditingTest*>(const_cast<void*>(clientInfo));
+ client.messageName = messageName;
+ client.didReceiveMessage = true;
+ }
+
+ static void didFinishLoadForFrame(WKPageRef, WKFrameRef, WKTypeRef, const void* clientInfo)
+ {
+ WebKit2TextFieldBeginAndEditEditingTest& client = *static_cast<WebKit2TextFieldBeginAndEditEditingTest*>(const_cast<void*>(clientInfo));
+ client.didFinishLoad = true;
+ }
+
+ static void setInjectedBundleClient(WKContextRef context, const void* clientInfo)
+ {
+ WKContextInjectedBundleClientV1 injectedBundleClient;
+ memset(&injectedBundleClient, 0, sizeof(injectedBundleClient));
+
+ injectedBundleClient.base.version = 1;
+ injectedBundleClient.base.clientInfo = clientInfo;
+ injectedBundleClient.didReceiveMessageFromInjectedBundle = didReceiveMessageFromInjectedBundle;
+
+ WKContextSetInjectedBundleClient(context, &injectedBundleClient.base);
+ }
+
+ static void setPageLoaderClient(WKPageRef page, const void* clientInfo)
+ {
+ WKPageLoaderClientV6 loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+
+ loaderClient.base.version = 6;
+ loaderClient.base.clientInfo = clientInfo;
+ loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+
+ WKPageSetPageLoaderClient(page, &loaderClient.base);
+ }
+
+ static void nullJavaScriptCallback(WKSerializedScriptValueRef, WKErrorRef, void*)
+ {
+ }
+
+ void executeJavaScriptAndCheckDidReceiveMessage(const char* javaScriptCode, const char* expectedMessageName)
+ {
+ didReceiveMessage = false;
+ WKPageRunJavaScriptInMainFrame(webView->page(), Util::toWK(javaScriptCode).get(), 0, nullJavaScriptCallback);
+ Util::run(&didReceiveMessage);
+ EXPECT_WK_STREQ(expectedMessageName, messageName);
+ }
+
+ // From ::testing::Test
+ void SetUp() override
+ {
+ WKRetainPtr<WKContextRef> context = adoptWK(Util::createContextForInjectedBundleTest("TextFieldDidBeginAndEndEditingEventsTest"));
+ setInjectedBundleClient(context.get(), this);
+
+ webView = std::make_unique<PlatformWebView>(context.get());
+ setPageLoaderClient(webView->page(), this);
+
+ didFinishLoad = false;
+ didReceiveMessage = false;
+
+ WKPageLoadURL(webView->page(), adoptWK(Util::createURLForResource("input-focus-blur", "html")).get());
+ Util::run(&didFinishLoad);
+ }
+};
+
+TEST_F(WebKit2TextFieldBeginAndEditEditingTest, TextFieldDidBeginAndEndEditingEvents)
+{
+ executeJavaScriptAndCheckDidReceiveMessage("focusTextField('input')", "DidReceiveTextFieldDidBeginEditing");
+ executeJavaScriptAndCheckDidReceiveMessage("blurTextField('input')", "DidReceiveTextFieldDidEndEditing");
+}
+
+TEST_F(WebKit2TextFieldBeginAndEditEditingTest, TextFieldDidBeginAndEndEditingEventsInReadOnlyField)
+{
+ executeJavaScriptAndCheckDidReceiveMessage("focusTextField('readonly')", "DidReceiveTextFieldDidBeginEditing");
+ executeJavaScriptAndCheckDidReceiveMessage("blurTextField('readonly')", "DidReceiveTextFieldDidEndEditing");
+}
+
+TEST_F(WebKit2TextFieldBeginAndEditEditingTest, TextFieldDidBeginShouldNotBeDispatchedForAlreadyFocusedField)
+{
+ executeJavaScriptAndCheckDidReceiveMessage("focusTextField('input'); focusTextField('input')", "DidReceiveTextFieldDidBeginEditing");
+ executeJavaScriptAndCheckDidReceiveMessage("blurTextField('input')", "DidReceiveTextFieldDidEndEditing");
+}
+
+TEST_F(WebKit2TextFieldBeginAndEditEditingTest, TextFieldDidEndShouldBeDispatchedForRemovedFocusField)
+{
+ executeJavaScriptAndCheckDidReceiveMessage("focusTextField('input')", "DidReceiveTextFieldDidBeginEditing");
+ executeJavaScriptAndCheckDidReceiveMessage("removeTextField('input')", "DidReceiveTextFieldDidEndEditing");
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/TextFieldDidBeginAndEndEditing_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/TextFieldDidBeginAndEndEditing_Bundle.cpp
new file mode 100644
index 000000000..347ce826c
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/TextFieldDidBeginAndEndEditing_Bundle.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "InjectedBundleTest.h"
+
+#include "PlatformUtilities.h"
+#include <WebKit/WKBundlePage.h>
+
+namespace TestWebKitAPI {
+
+class TextFieldDidBeginAndEndEditingEventsTest : public InjectedBundleTest {
+public:
+ TextFieldDidBeginAndEndEditingEventsTest(const std::string& identifier);
+
+ virtual void didCreatePage(WKBundleRef, WKBundlePageRef);
+};
+
+static InjectedBundleTest::Register<TextFieldDidBeginAndEndEditingEventsTest> registrar("TextFieldDidBeginAndEndEditingEventsTest");
+
+static void textFieldDidBeginEditing(WKBundlePageRef, WKBundleNodeHandleRef inputElement, WKBundleFrameRef, const void*)
+{
+ WKBundlePostMessage(InjectedBundleController::singleton().bundle(), Util::toWK("DidReceiveTextFieldDidBeginEditing").get(), nullptr);
+}
+
+static void textFieldDidEndEditing(WKBundlePageRef, WKBundleNodeHandleRef inputElement, WKBundleFrameRef, const void*)
+{
+ WKBundlePostMessage(InjectedBundleController::singleton().bundle(), Util::toWK("DidReceiveTextFieldDidEndEditing").get(), nullptr);
+}
+
+TextFieldDidBeginAndEndEditingEventsTest::TextFieldDidBeginAndEndEditingEventsTest(const std::string& identifier)
+ : InjectedBundleTest(identifier)
+{
+}
+
+void TextFieldDidBeginAndEndEditingEventsTest::didCreatePage(WKBundleRef bundle, WKBundlePageRef page)
+{
+ WKBundlePageFormClientV2 formClient;
+ memset(&formClient, 0, sizeof(formClient));
+
+ formClient.base.version = 2;
+ formClient.base.clientInfo = this;
+ formClient.textFieldDidBeginEditing = textFieldDidBeginEditing;
+ formClient.textFieldDidEndEditing = textFieldDidEndEditing;
+
+ WKBundlePageSetFormClient(page, &formClient.base);
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/UserMedia.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/UserMedia.cpp
new file mode 100644
index 000000000..fc7ade42f
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/UserMedia.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2014 Igalia S.L
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#if ENABLE(MEDIA_STREAM)
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include "Test.h"
+#include <WebKit/WKRetainPtr.h>
+#include <string.h>
+#include <vector>
+
+namespace TestWebKitAPI {
+
+static bool done;
+
+void decidePolicyForUserMediaPermissionRequestCallBack(WKPageRef, WKFrameRef, WKSecurityOriginRef, WKSecurityOriginRef, WKUserMediaPermissionRequestRef permissionRequest, const void* /* clientInfo */)
+{
+ WKRetainPtr<WKArrayRef> audioDeviceUIDs = WKUserMediaPermissionRequestAudioDeviceUIDs(permissionRequest);
+ WKRetainPtr<WKArrayRef> videoDeviceUIDs = WKUserMediaPermissionRequestVideoDeviceUIDs(permissionRequest);
+
+ if (WKArrayGetSize(videoDeviceUIDs.get()) || WKArrayGetSize(audioDeviceUIDs.get())) {
+ WKRetainPtr<WKStringRef> videoDeviceUID;
+ if (WKArrayGetSize(videoDeviceUIDs.get()))
+ videoDeviceUID = reinterpret_cast<WKStringRef>(WKArrayGetItemAtIndex(videoDeviceUIDs.get(), 0));
+ else
+ videoDeviceUID = WKStringCreateWithUTF8CString("");
+
+ WKRetainPtr<WKStringRef> audioDeviceUID;
+ if (WKArrayGetSize(audioDeviceUIDs.get()))
+ audioDeviceUID = reinterpret_cast<WKStringRef>(WKArrayGetItemAtIndex(audioDeviceUIDs.get(), 0));
+ else
+ audioDeviceUID = WKStringCreateWithUTF8CString("");
+
+ WKUserMediaPermissionRequestAllow(permissionRequest, audioDeviceUID.get(), videoDeviceUID.get());
+ }
+
+ done = true;
+}
+
+TEST(WebKit2, DISABLED_UserMediaBasic)
+{
+ auto context = adoptWK(WKContextCreate());
+ PlatformWebView webView(context.get());
+ WKPageUIClientV5 uiClient;
+ memset(&uiClient, 0, sizeof(uiClient));
+
+
+ uiClient.base.version = 5;
+ uiClient.decidePolicyForUserMediaPermissionRequest = decidePolicyForUserMediaPermissionRequestCallBack;
+
+ WKPageSetPageUIClient(webView.page(), &uiClient.base);
+
+ done = false;
+ auto url = adoptWK(Util::createURLForResource("getUserMedia", "html"));
+ WKPageLoadURL(webView.page(), url.get());
+
+ Util::run(&done);
+}
+
+} // namespace TestWebKitAPI
+
+#endif // ENABLE(MEDIA_STREAM)
+
+#endif // WK_HAVE_C_SPI
+
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/UserMessage.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/UserMessage.cpp
index 2585a06ff..064cbb838 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/UserMessage.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/UserMessage.cpp
@@ -24,12 +24,13 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "Test.h"
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
-#include <wtf/OwnPtr.h>
-#include <wtf/PassOwnPtr.h>
namespace TestWebKitAPI {
@@ -42,7 +43,7 @@ public:
}
WKRetainPtr<WKContextRef> context;
- OwnPtr<PlatformWebView> webView;
+ std::unique_ptr<PlatformWebView> webView;
WKRetainPtr<WKTypeRef> recievedBody;
@@ -80,7 +81,7 @@ public:
WKPageLoaderClientV3 loaderClient;
memset(&loaderClient, 0, sizeof(loaderClient));
- loaderClient.base.version = kWKPageLoaderClientCurrentVersion;
+ loaderClient.base.version = 3;
loaderClient.base.clientInfo = clientInfo;
loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
@@ -92,7 +93,7 @@ public:
context = adoptWK(Util::createContextForInjectedBundleTest("UserMessageTest"));
setInjectedBundleClient(context.get(), this);
- webView = adoptPtr(new PlatformWebView(context.get()));
+ webView = std::make_unique<PlatformWebView>(context.get());
setPageLoaderClient(webView->page(), this);
didFinishLoad = false;
@@ -157,3 +158,5 @@ TEST_F(WebKit2UserMessageRoundTripTest, WKString)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/UserMessage_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/UserMessage_Bundle.cpp
index 29ede3d83..cec713655 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/UserMessage_Bundle.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/UserMessage_Bundle.cpp
@@ -24,6 +24,9 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "InjectedBundleTest.h"
#include "PlatformUtilities.h"
@@ -50,3 +53,5 @@ private:
static InjectedBundleTest::Register<UserMessageTest> registrar("UserMessageTest");
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/WKBundleFileHandle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/WKBundleFileHandle.cpp
new file mode 100644
index 000000000..b9a84ff80
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/WKBundleFileHandle.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include "Test.h"
+
+namespace TestWebKitAPI {
+
+static bool done;
+static bool loadDone;
+
+static void didReceiveMessageFromInjectedBundle(WKContextRef, WKStringRef messageName, WKTypeRef body, const void*)
+{
+ if (!WKStringIsEqualToUTF8CString(messageName, "SUCCESS"))
+ FAIL();
+ else
+ SUCCEED();
+
+ done = true;
+}
+
+static void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void*)
+{
+ loadDone = true;
+}
+
+TEST(WebKit2, WKBundleFileHandle)
+{
+ WKRetainPtr<WKContextRef> context = adoptWK(Util::createContextForInjectedBundleTest("WKBundleFileHandleTest"));
+
+ WKContextInjectedBundleClientV0 injectedBundleClient;
+ memset(&injectedBundleClient, 0, sizeof(injectedBundleClient));
+ injectedBundleClient.base.version = 0;
+ injectedBundleClient.didReceiveMessageFromInjectedBundle = didReceiveMessageFromInjectedBundle;
+ WKContextSetInjectedBundleClient(context.get(), &injectedBundleClient.base);
+
+ PlatformWebView webView(context.get());
+
+ WKPageLoaderClientV0 loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+ loaderClient.base.version = 0;
+ loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+ WKPageSetPageLoaderClient(webView.page(), &loaderClient.base);
+
+ WKPageLoadURL(webView.page(), adoptWK(Util::createURLForResource("bundle-file", "html")).get());
+ Util::run(&loadDone);
+
+ // Get path to a file.
+ auto urlToFile = adoptWK(Util::createURLForResource("simple", "html"));
+ auto pathToFile = adoptWK(WKURLCopyPath(urlToFile.get()));
+
+ WKContextPostMessageToInjectedBundle(context.get(), Util::toWK("TestFile").get(), pathToFile.get());
+
+ Util::run(&done);
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/WKBundleFileHandle_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/WKBundleFileHandle_Bundle.cpp
new file mode 100644
index 000000000..fcb0ab7a0
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/WKBundleFileHandle_Bundle.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "InjectedBundleTest.h"
+
+#include "PlatformUtilities.h"
+#include <WebKit/WKBundlePage.h>
+#include <WebKit/WKBundleFileHandleRef.h>
+#include <WebKit/WKBundleFrame.h>
+#include <WebKit/WKBundleScriptWorld.h>
+
+namespace TestWebKitAPI {
+
+static WKBundlePageRef loadedPage;
+
+class WKBundleFileHandleTest : public InjectedBundleTest {
+public:
+ WKBundleFileHandleTest(const std::string& identifier)
+ : InjectedBundleTest(identifier)
+ {
+ }
+
+private:
+ void didReceiveMessage(WKBundleRef bundle, WKStringRef messageName, WKTypeRef messageBody) override
+ {
+ if (!WKStringIsEqualToUTF8CString(messageName, "TestFile")) {
+ WKBundlePostMessage(bundle, Util::toWK("FAIL").get(), Util::toWK("Recieved invalid message").get());
+ return;
+ }
+
+ if (!loadedPage) {
+ WKBundlePostMessage(bundle, Util::toWK("FAIL").get(), Util::toWK("No loaded page").get());
+ return;
+ }
+
+ if (WKGetTypeID(messageBody) != WKStringGetTypeID()) {
+ WKBundlePostMessage(bundle, Util::toWK("FAIL").get(), Util::toWK("Message body has invalid type").get());
+ return;
+ }
+
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(loadedPage);
+ WKBundleScriptWorldRef world = WKBundleScriptWorldNormalWorld();
+
+ JSGlobalContextRef globalContext = WKBundleFrameGetJavaScriptContextForWorld(mainFrame, world);
+
+ auto fileHandle = adoptWK(WKBundleFileHandleCreateWithPath((WKStringRef)messageBody));
+ JSValueRef jsFileHandle = WKBundleFrameGetJavaScriptWrapperForFileForWorld(mainFrame, fileHandle.get(), world);
+
+ JSObjectRef globalObject = JSContextGetGlobalObject(globalContext);
+
+ JSStringRef jsString = JSStringCreateWithUTF8CString("testFile");
+ JSValueRef function = JSObjectGetProperty(globalContext, globalObject, jsString, nullptr);
+ JSStringRelease(jsString);
+
+ JSValueRef result = JSObjectCallAsFunction(globalContext, (JSObjectRef)function, globalObject, 1, &jsFileHandle, nullptr);
+
+ if (JSValueToBoolean(globalContext, result))
+ WKBundlePostMessage(bundle, Util::toWK("SUCCESS").get(), nullptr);
+ else
+ WKBundlePostMessage(bundle, Util::toWK("FAIL").get(), Util::toWK("Script failed").get());
+ }
+
+ void didCreatePage(WKBundleRef bundle, WKBundlePageRef page) override
+ {
+ loadedPage = page;
+ }
+};
+
+static InjectedBundleTest::Register<WKBundleFileHandleTest> registrar("WKBundleFileHandleTest");
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/WKImageCreateCGImageCrash.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/WKImageCreateCGImageCrash.cpp
new file mode 100644
index 000000000..f0d19025f
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/WKImageCreateCGImageCrash.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include <WebKit/WKImageCG.h>
+
+namespace TestWebKitAPI {
+
+TEST(WebKit2, WKImageCreateCGImageCrash)
+{
+ EXPECT_FALSE(WKImageCreateCGImage(nullptr));
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/WKPageConfiguration.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/WKPageConfiguration.cpp
new file mode 100644
index 000000000..d041eeaed
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/WKPageConfiguration.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include "Test.h"
+
+#include <WebKit/WKWebsiteDataStoreRef.h>
+
+namespace TestWebKitAPI {
+
+TEST(WebKit2, WKPageConfigurationEmpty)
+{
+ WKRetainPtr<WKPageConfigurationRef> configuration = adoptWK(WKPageConfigurationCreate());
+
+ ASSERT_NULL(WKPageConfigurationGetContext(configuration.get()));
+ ASSERT_NULL(WKPageConfigurationGetUserContentController(configuration.get()));
+ ASSERT_NULL(WKPageConfigurationGetPageGroup(configuration.get()));
+ ASSERT_NULL(WKPageConfigurationGetPreferences(configuration.get()));
+ ASSERT_NULL(WKPageConfigurationGetRelatedPage(configuration.get()));
+}
+
+static bool didFinishLoad;
+
+static void didFinishLoadForFrame(WKPageRef, WKFrameRef, WKTypeRef, const void*)
+{
+ didFinishLoad = true;
+}
+
+static void setPageLoaderClient(WKPageRef page)
+{
+ WKPageLoaderClientV0 loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+
+ loaderClient.base.version = 0;
+ loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+
+ WKPageSetPageLoaderClient(page, &loaderClient.base);
+}
+
+TEST(WebKit2, WKPageConfigurationBasic)
+{
+ WKRetainPtr<WKPageConfigurationRef> configuration = adoptWK(WKPageConfigurationCreate());
+ WKRetainPtr<WKContextRef> context = adoptWK(WKContextCreate());
+ WKPageConfigurationSetContext(configuration.get(), context.get());
+
+ PlatformWebView webView(configuration.get());
+ setPageLoaderClient(webView.page());
+
+ WKRetainPtr<WKPageConfigurationRef> copiedConfiguration = adoptWK(WKPageCopyPageConfiguration(webView.page()));
+ ASSERT_EQ(context.get(), WKPageConfigurationGetContext(copiedConfiguration.get()));
+
+ WKRetainPtr<WKURLRef> url = adoptWK(Util::createURLForResource("simple", "html"));
+ WKPageLoadURL(webView.page(), url.get());
+
+ didFinishLoad = false;
+ Util::run(&didFinishLoad);
+}
+
+TEST(WebKit2, WKPageConfigurationBasicWithDataStore)
+{
+ WKRetainPtr<WKPageConfigurationRef> configuration = adoptWK(WKPageConfigurationCreate());
+ WKRetainPtr<WKContextRef> context = adoptWK(WKContextCreate());
+ WKPageConfigurationSetContext(configuration.get(), context.get());
+ WKRetainPtr<WKWebsiteDataStoreRef> websiteDataStore = WKWebsiteDataStoreGetDefaultDataStore();
+ WKPageConfigurationSetWebsiteDataStore(configuration.get(), websiteDataStore.get());
+
+ PlatformWebView webView(configuration.get());
+ setPageLoaderClient(webView.page());
+
+ WKRetainPtr<WKPageConfigurationRef> copiedConfiguration = adoptWK(WKPageCopyPageConfiguration(webView.page()));
+ ASSERT_EQ(context.get(), WKPageConfigurationGetContext(copiedConfiguration.get()));
+ ASSERT_EQ(WKWebsiteDataStoreGetDefaultDataStore(), WKPageConfigurationGetWebsiteDataStore(copiedConfiguration.get()));
+
+ WKRetainPtr<WKURLRef> url = adoptWK(Util::createURLForResource("simple", "html"));
+ WKPageLoadURL(webView.page(), url.get());
+
+ didFinishLoad = false;
+ Util::run(&didFinishLoad);
+}
+
+TEST(WebKit2, WKPageConfigurationBasicWithNonPersistentDataStore)
+{
+ WKRetainPtr<WKPageConfigurationRef> configuration = adoptWK(WKPageConfigurationCreate());
+ WKRetainPtr<WKContextRef> context = adoptWK(WKContextCreate());
+ WKPageConfigurationSetContext(configuration.get(), context.get());
+ WKRetainPtr<WKWebsiteDataStoreRef> websiteDataStore = adoptWK(WKWebsiteDataStoreCreateNonPersistentDataStore());
+ WKPageConfigurationSetWebsiteDataStore(configuration.get(), websiteDataStore.get());
+
+ PlatformWebView webView(configuration.get());
+ setPageLoaderClient(webView.page());
+
+ WKRetainPtr<WKPageConfigurationRef> copiedConfiguration = adoptWK(WKPageCopyPageConfiguration(webView.page()));
+ ASSERT_EQ(context.get(), WKPageConfigurationGetContext(copiedConfiguration.get()));
+ ASSERT_EQ(websiteDataStore.get(), WKPageConfigurationGetWebsiteDataStore(copiedConfiguration.get()));
+
+ WKRetainPtr<WKURLRef> url = adoptWK(Util::createURLForResource("simple", "html"));
+ WKPageLoadURL(webView.page(), url.get());
+
+ didFinishLoad = false;
+ Util::run(&didFinishLoad);
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/WKPageCopySessionStateWithFiltering.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/WKPageCopySessionStateWithFiltering.cpp
new file mode 100644
index 000000000..6ce49a13b
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/WKPageCopySessionStateWithFiltering.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include "Test.h"
+
+namespace TestWebKitAPI {
+
+static bool didFinishLoad;
+static WKRetainPtr<WKSessionStateRef> sessionStateWithFirstItemRemoved;
+static WKRetainPtr<WKSessionStateRef> sessionStateWithAllItemsRemoved;
+
+static void didFinishLoadForFrame(WKPageRef, WKFrameRef, WKTypeRef, const void*)
+{
+ didFinishLoad = true;
+}
+
+static void setPageLoaderClient(WKPageRef page)
+{
+ WKPageLoaderClientV0 loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+
+ loaderClient.base.version = 0;
+ loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+
+ WKPageSetPageLoaderClient(page, &loaderClient.base);
+}
+
+static bool filterFirstItemCallback(WKPageRef page, WKStringRef valueType, WKTypeRef value, void* context)
+{
+ if (!WKStringIsEqual(valueType, WKPageGetSessionBackForwardListItemValueType()))
+ return true;
+
+ ASSERT(WKGetTypeID(value) == WKBackForwardListItemGetTypeID());
+ WKBackForwardListItemRef backForwardListItem = static_cast<WKBackForwardListItemRef>(value);
+
+ WKRetainPtr<WKURLRef> url = adoptWK(WKBackForwardListItemCopyURL(backForwardListItem));
+ WKRetainPtr<WKStringRef> path = adoptWK(WKURLCopyLastPathComponent(url.get()));
+
+ return !WKStringIsEqualToUTF8CString(path.get(), "simple.html");
+}
+
+static bool filterAllItemsCallback(WKPageRef page, WKStringRef valueType, WKTypeRef value, void* context)
+{
+ return false;
+}
+
+static void createSessionStates(WKContextRef context)
+{
+ PlatformWebView webView(context);
+ setPageLoaderClient(webView.page());
+
+ WKPageLoadURL(webView.page(), adoptWK(Util::createURLForResource("simple", "html")).get());
+ Util::run(&didFinishLoad);
+ didFinishLoad = false;
+
+ WKPageLoadURL(webView.page(), adoptWK(Util::createURLForResource("simple2", "html")).get());
+ Util::run(&didFinishLoad);
+ didFinishLoad = false;
+
+ WKPageLoadURL(webView.page(), adoptWK(Util::createURLForResource("simple3", "html")).get());
+ Util::run(&didFinishLoad);
+ didFinishLoad = false;
+
+ WKPageGoBack(webView.page());
+ Util::run(&didFinishLoad);
+ didFinishLoad = false;
+
+ WKPageGoBack(webView.page());
+ Util::run(&didFinishLoad);
+ didFinishLoad = false;
+
+ // Should be back on simple.html at this point.
+
+ sessionStateWithFirstItemRemoved = adoptWK(static_cast<WKSessionStateRef>(WKPageCopySessionState(webView.page(), reinterpret_cast<void*>(1), filterFirstItemCallback)));
+ sessionStateWithAllItemsRemoved = adoptWK(static_cast<WKSessionStateRef>(WKPageCopySessionState(webView.page(), reinterpret_cast<void*>(1), filterAllItemsCallback)));
+}
+
+TEST(WebKit2, WKPageCopySessionStateWithFiltering)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+
+ createSessionStates(context.get());
+
+ EXPECT_NOT_NULL(sessionStateWithFirstItemRemoved);
+ PlatformWebView webView1(context.get());
+ setPageLoaderClient(webView1.page());
+ WKPageRestoreFromSessionState(webView1.page(), sessionStateWithFirstItemRemoved.get());
+ Util::run(&didFinishLoad);
+ didFinishLoad = false;
+
+ WKBackForwardListRef backForwardList1 = WKPageGetBackForwardList(webView1.page());
+ EXPECT_EQ(0u, WKBackForwardListGetBackListCount(backForwardList1));
+ EXPECT_EQ(1u, WKBackForwardListGetForwardListCount(backForwardList1));
+
+ EXPECT_NOT_NULL(sessionStateWithAllItemsRemoved);
+ PlatformWebView webView2(context.get());
+ setPageLoaderClient(webView2.page());
+ WKPageRestoreFromSessionState(webView2.page(), sessionStateWithAllItemsRemoved.get());
+ // Because the session state ends up being empty, nothing is actually loaded.
+
+ WKBackForwardListRef backForwardList2 = WKPageGetBackForwardList(webView2.page());
+ EXPECT_EQ(0u, WKBackForwardListGetBackListCount(backForwardList2));
+ EXPECT_EQ(0u, WKBackForwardListGetForwardListCount(backForwardList2));
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/WKPageGetScaleFactorNotZero.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/WKPageGetScaleFactorNotZero.cpp
index 8ecf1659f..929baaa71 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/WKPageGetScaleFactorNotZero.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/WKPageGetScaleFactorNotZero.cpp
@@ -24,6 +24,9 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include "Test.h"
@@ -48,7 +51,7 @@ static void setPageLoaderClient(WKPageRef page)
WKPageSetPageLoaderClient(page, &loaderClient.base);
}
-static WKRetainPtr<WKDataRef> createSessionState(WKContextRef context)
+static WKRetainPtr<WKSessionStateRef> createSessionState(WKContextRef context)
{
PlatformWebView webView(context);
setPageLoaderClient(webView.page());
@@ -57,7 +60,7 @@ static WKRetainPtr<WKDataRef> createSessionState(WKContextRef context)
Util::run(&didFinishLoad);
didFinishLoad = false;
- return adoptWK(WKPageCopySessionState(webView.page(), 0, 0));
+ return adoptWK(static_cast<WKSessionStateRef>(WKPageCopySessionState(webView.page(), reinterpret_cast<void*>(1), nullptr)));
}
TEST(WebKit2, WKPageGetScaleFactorNotZero)
@@ -67,13 +70,15 @@ TEST(WebKit2, WKPageGetScaleFactorNotZero)
PlatformWebView webView(context.get());
setPageLoaderClient(webView.page());
- WKRetainPtr<WKDataRef> data = createSessionState(context.get());
- EXPECT_NOT_NULL(data);
+ auto sessionState = createSessionState(context.get());
+ EXPECT_NOT_NULL(sessionState);
- WKPageRestoreFromSessionState(webView.page(), data.get());
+ WKPageRestoreFromSessionState(webView.page(), sessionState.get());
Util::run(&didFinishLoad);
EXPECT_TRUE(WKPageGetScaleFactor(webView.page()) == 1.0);
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/WKPageIsPlayingAudio.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/WKPageIsPlayingAudio.cpp
new file mode 100644
index 000000000..1e848133f
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/WKPageIsPlayingAudio.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include "Test.h"
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <JavaScriptCore/JavaScriptCore.h>
+#include <WebKit/WKSerializedScriptValue.h>
+#include <WebKit/WKPagePrivate.h>
+#include <WebKit/WKPreferencesRef.h>
+#include <WebKit/WKPreferencesRefPrivate.h>
+
+// This test loads file-with-video.html. It first checks to make sure WKPageIsPlayingAudio() returns
+// false for the page. Then it calls a JavaScript method to play the video, waits for
+// WKPageUIClient::isPlayingAudioDidChange() to get called, and checks that WKPageIsPlayingAudio() now
+// returns true for the page.
+
+namespace TestWebKitAPI {
+
+static bool isMSEEnabledChanged;
+static bool isMSEEnabled;
+static bool didFinishLoad;
+static bool isPlayingAudioChanged;
+
+static void nullJavaScriptCallback(WKSerializedScriptValueRef, WKErrorRef error, void*)
+{
+}
+
+static void isMSEEnabledCallback(WKSerializedScriptValueRef serializedResultValue, WKErrorRef error, void*)
+{
+ JSGlobalContextRef scriptContext = JSGlobalContextCreate(0);
+
+ JSValueRef resultValue = WKSerializedScriptValueDeserialize(serializedResultValue, scriptContext, 0);
+ EXPECT_TRUE(JSValueIsBoolean(scriptContext, resultValue));
+
+ isMSEEnabledChanged = true;
+ isMSEEnabled = JSValueToBoolean(scriptContext, resultValue);
+
+ JSGlobalContextRelease(scriptContext);
+}
+
+static void didFinishLoadForFrame(WKPageRef page, WKFrameRef, WKTypeRef, const void*)
+{
+ didFinishLoad = true;
+}
+
+static void isPlayingAudioDidChangeCallback(WKPageRef page, const void*)
+{
+ isPlayingAudioChanged = true;
+}
+
+static void setUpClients(WKPageRef page)
+{
+ WKPageLoaderClientV0 loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+
+ loaderClient.base.version = 0;
+ loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+
+ WKPageSetPageLoaderClient(page, &loaderClient.base);
+
+ WKPageUIClientV5 uiClient;
+ memset(&uiClient, 0, sizeof(uiClient));
+
+ uiClient.base.version = 5;
+ uiClient.isPlayingAudioDidChange = isPlayingAudioDidChangeCallback;
+
+ WKPageSetPageUIClient(page, &uiClient.base);
+}
+
+TEST(WebKit2, WKPageIsPlayingAudio)
+{
+ WKRetainPtr<WKContextRef> context = adoptWK(WKContextCreate());
+
+ PlatformWebView webView(context.get());
+ setUpClients(webView.page());
+
+ WKRetainPtr<WKURLRef> url = adoptWK(Util::createURLForResource("file-with-video", "html"));
+ WKPageLoadURL(webView.page(), url.get());
+
+ Util::run(&didFinishLoad);
+
+ EXPECT_FALSE(WKPageIsPlayingAudio(webView.page()));
+ WKPageRunJavaScriptInMainFrame(webView.page(), Util::toWK("playVideo()").get(), 0, nullJavaScriptCallback);
+
+ Util::run(&isPlayingAudioChanged);
+ EXPECT_TRUE(WKPageIsPlayingAudio(webView.page()));
+}
+
+TEST(WebKit2, MSEIsPlayingAudio)
+{
+ WKRetainPtr<WKContextRef> context = adoptWK(WKContextCreate());
+
+ WKRetainPtr<WKPageGroupRef> pageGroup(AdoptWK, WKPageGroupCreateWithIdentifier(Util::toWK("MSEIsPlayingAudioPageGroup").get()));
+ WKPreferencesRef preferences = WKPageGroupGetPreferences(pageGroup.get());
+ WKPreferencesSetMediaSourceEnabled(preferences, true);
+ WKPreferencesSetFileAccessFromFileURLsAllowed(preferences, true);
+
+ PlatformWebView webView(context.get(), pageGroup.get());
+ setUpClients(webView.page());
+
+ WKRetainPtr<WKURLRef> url = adoptWK(Util::createURLForResource("file-with-mse", "html"));
+ didFinishLoad = false;
+ WKPageLoadURL(webView.page(), url.get());
+
+ Util::run(&didFinishLoad);
+
+ // Bail out of the test early if the platform does not support MSE.
+ isMSEEnabledChanged = false;
+ WKPageRunJavaScriptInMainFrame(webView.page(), Util::toWK("window.MediaSource !== undefined").get(), 0, isMSEEnabledCallback);
+ Util::run(&isMSEEnabledChanged);
+ if (!isMSEEnabled)
+ return;
+
+ EXPECT_FALSE(WKPageIsPlayingAudio(webView.page()));
+ isPlayingAudioChanged = false;
+ WKPageRunJavaScriptInMainFrame(webView.page(), Util::toWK("playVideo()").get(), 0, nullJavaScriptCallback);
+
+ Util::run(&isPlayingAudioChanged);
+ EXPECT_TRUE(WKPageIsPlayingAudio(webView.page()));
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/WKPreferences.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/WKPreferences.cpp
index 976e7041b..7f8616f5d 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/WKPreferences.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/WKPreferences.cpp
@@ -24,9 +24,12 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
-#include <WebKit2/WKPreferencesPrivate.h>
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKPreferencesRefPrivate.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -41,15 +44,15 @@ TEST(WebKit2, WKPreferencesBasic)
TEST(WebKit2, WKPreferencesDefaults)
{
-#if PLATFORM(WIN)
- static const char* expectedStandardFontFamily = "Times New Roman";
+#if PLATFORM(GTK) || PLATFORM(EFL)
+ static const char* expectedStandardFontFamily = "Times";
static const char* expectedFixedFontFamily = "Courier New";
- static const char* expectedSerifFontFamily = "Times New Roman";
- static const char* expectedSansSerifFontFamily = "Arial";
+ static const char* expectedSerifFontFamily = "Times";
+ static const char* expectedSansSerifFontFamily = "Helvetica";
static const char* expectedCursiveFontFamily = "Comic Sans MS";
- static const char* expectedFantasyFontFamily = "Comic Sans MS";
- static const char* expectedPictographFontFamily = "Times New Roman";
-#elif PLATFORM(MAC)
+ static const char* expectedFantasyFontFamily = "Impact";
+ static const char* expectedPictographFontFamily = "Times";
+#elif WK_HAVE_C_SPI
static const char* expectedStandardFontFamily = "Times";
static const char* expectedFixedFontFamily = "Courier";
static const char* expectedSerifFontFamily = "Times";
@@ -57,21 +60,21 @@ TEST(WebKit2, WKPreferencesDefaults)
static const char* expectedCursiveFontFamily = "Apple Chancery";
static const char* expectedFantasyFontFamily = "Papyrus";
static const char* expectedPictographFontFamily = "Apple Color Emoji";
-#elif PLATFORM(GTK) || PLATFORM(EFL)
+#elif PLATFORM(IOS)
static const char* expectedStandardFontFamily = "Times";
- static const char* expectedFixedFontFamily = "Courier New";
+ static const char* expectedFixedFontFamily = "Courier";
static const char* expectedSerifFontFamily = "Times";
static const char* expectedSansSerifFontFamily = "Helvetica";
- static const char* expectedCursiveFontFamily = "Comic Sans MS";
- static const char* expectedFantasyFontFamily = "Impact";
- static const char* expectedPictographFontFamily = "Times";
+ static const char* expectedCursiveFontFamily = "Snell Roundhand";
+ static const char* expectedFantasyFontFamily = "Papyrus";
+ static const char* expectedPictographFontFamily = "AppleColorEmoji";
#endif
WKPreferencesRef preference = WKPreferencesCreate();
EXPECT_TRUE(WKPreferencesGetJavaScriptEnabled(preference));
EXPECT_TRUE(WKPreferencesGetLoadsImagesAutomatically(preference));
- EXPECT_FALSE(WKPreferencesGetOfflineWebApplicationCacheEnabled(preference));
+ EXPECT_TRUE(WKPreferencesGetOfflineWebApplicationCacheEnabled(preference));
EXPECT_TRUE(WKPreferencesGetLocalStorageEnabled(preference));
EXPECT_TRUE(WKPreferencesGetXSSAuditorEnabled(preference));
EXPECT_FALSE(WKPreferencesGetFrameFlatteningEnabled(preference));
@@ -91,11 +94,7 @@ TEST(WebKit2, WKPreferencesDefaults)
EXPECT_FALSE(WKPreferencesGetDeveloperExtrasEnabled(preference));
EXPECT_TRUE(WKPreferencesGetTextAreasAreResizable(preference));
-#if PLATFORM(WIN)
- EXPECT_EQ(kWKFontSmoothingLevelWindows, WKPreferencesGetFontSmoothingLevel(preference));
-#else
EXPECT_EQ(kWKFontSmoothingLevelMedium, WKPreferencesGetFontSmoothingLevel(preference));
-#endif
EXPECT_TRUE(WKPreferencesGetAcceleratedCompositingEnabled(preference));
EXPECT_FALSE(WKPreferencesGetCompositingBordersVisible(preference));
@@ -122,3 +121,5 @@ TEST(WebKit2, WKPreferencesCopying)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/GtkLauncher/LauncherInspectorWindow.h b/Tools/TestWebKitAPI/Tests/WebKit2/WKRetainPtr.cpp
index f7091d238..860d7d48d 100644
--- a/Tools/GtkLauncher/LauncherInspectorWindow.h
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/WKRetainPtr.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Igalia S.L.
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,29 +23,36 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef LauncherInspectorWindow_h
-#define LauncherInspectorWindow_h
+#include "config.h"
-#include <gtk/gtk.h>
-#include <webkit/webkit.h>
+#if WK_HAVE_C_SPI
-G_BEGIN_DECLS
+#include "PlatformUtilities.h"
+#include <wtf/HashMap.h>
-#define LAUNCHER_TYPE_INSPECTOR_WINDOW (launcher_inspector_window_get_type())
-#define LAUNCHER_INSPECTOR_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), LAUNCHER_TYPE_INSPECTOR_WINDOW, LauncherInspectorWindow))
-#define LAUNCHER_IS_INSPECTOR_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), LAUNCHER_TYPE_INSPECTOR_WINDOW))
-#define LAUNCHER_INSPECTOR_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), LAUNCHER_TYPE_INSPECTOR_WINDOW, LauncherInspectorWindowClass))
-#define LAUNCHER_IS_INSPECTOR_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), LAUNCHER_TYPE_INSPECTOR_WINDOW))
-#define LAUNCHER_INSPECTOR_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), LAUNCHER_TYPE_INSPECTOR_WINDOW, LauncherInspectorWindowClass))
+namespace TestWebKitAPI {
-typedef struct _LauncherInspectorWindow LauncherInspectorWindow;
-typedef struct _LauncherInspectorWindowClass LauncherInspectorWindowClass;
+TEST(WebKit2, WKRetainPtr)
+{
+ WKRetainPtr<WKStringRef> string1 = adoptWK(WKStringCreateWithUTF8CString("a"));
+ WKRetainPtr<WKStringRef> string2 = adoptWK(WKStringCreateWithUTF8CString("a"));
+ WKRetainPtr<WKStringRef> string3 = adoptWK(WKStringCreateWithUTF8CString("a"));
+ WKRetainPtr<WKStringRef> string4 = adoptWK(WKStringCreateWithUTF8CString("a"));
-GType launcher_inspector_window_get_type(void);
+ HashMap<WKRetainPtr<WKStringRef>, int> map;
-GtkWidget *launcherInspectorWindowNew(WebKitWebInspector *, GtkWindow *parent);
-WebKitWebView *launcherInspectorWindowGetWebView(LauncherInspectorWindow *);
+ map.set(string2, 2);
+ map.set(string1, 1);
-G_END_DECLS
+ EXPECT_TRUE(map.contains(string1));
+ EXPECT_TRUE(map.contains(string2));
+ EXPECT_FALSE(map.contains(string3));
+ EXPECT_FALSE(map.contains(string4));
+
+ EXPECT_EQ(1, map.get(string1));
+ EXPECT_EQ(2, map.get(string2));
+}
+
+} // namespace TestWebKitAPI
#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/WKString.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/WKString.cpp
index b67235932..b4167be81 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/WKString.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/WKString.cpp
@@ -25,6 +25,8 @@
#include "config.h"
+#if WK_HAVE_C_SPI
+
namespace TestWebKitAPI {
TEST(WebKit2, WKString)
@@ -69,3 +71,5 @@ TEST(WebKit2, WKString)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/WKStringJSString.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/WKStringJSString.cpp
index cdba57de4..8b6e08b9d 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/WKStringJSString.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/WKStringJSString.cpp
@@ -24,7 +24,10 @@
*/
#include "config.h"
-#include <WebKit2/WKStringPrivate.h>
+
+#if WK_HAVE_C_SPI
+
+#include <WebKit/WKStringPrivate.h>
#include <JavaScriptCore/JSStringRef.h>
namespace TestWebKitAPI {
@@ -48,3 +51,5 @@ TEST(WebKit2, WKStringJSString)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/WebArchive.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/WebArchive.cpp
new file mode 100644
index 000000000..06d673e21
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/WebArchive.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include <CoreFoundation/CoreFoundation.h>
+#include <WebKit/WKURLCF.h>
+#include <WebKit/WKContextPrivate.h>
+#include <wtf/RetainPtr.h>
+
+namespace TestWebKitAPI {
+
+static bool didFinishLoad;
+static bool didReceiveMessage;
+
+static void didReceiveMessageFromInjectedBundle(WKContextRef, WKStringRef messageName, WKTypeRef body, const void*)
+{
+ didReceiveMessage = true;
+
+ EXPECT_WK_STREQ("DidGetWebArchive", messageName);
+ EXPECT_TRUE(body);
+ EXPECT_EQ(WKDataGetTypeID(), WKGetTypeID(body));
+ WKDataRef receivedData = static_cast<WKDataRef>(body);
+
+ // Do basic sanity checks on the returned webarchive. We have more thorough checks in LayoutTests.
+ size_t size = WKDataGetSize(receivedData);
+ const unsigned char* bytes = WKDataGetBytes(receivedData);
+ RetainPtr<CFDataRef> data = adoptCF(CFDataCreate(0, bytes, size));
+ RetainPtr<CFPropertyListRef> propertyList = adoptCF(CFPropertyListCreateWithData(0, data.get(), kCFPropertyListImmutable, 0, 0));
+ EXPECT_TRUE(propertyList);
+
+ // It should be a dictionary.
+ EXPECT_EQ(CFDictionaryGetTypeID(), CFGetTypeID(propertyList.get()));
+ CFDictionaryRef dictionary = (CFDictionaryRef)propertyList.get();
+
+ // It should have a main resource.
+ CFTypeRef mainResource = CFDictionaryGetValue(dictionary, CFSTR("WebMainResource"));
+ EXPECT_TRUE(mainResource);
+ EXPECT_EQ(CFDictionaryGetTypeID(), CFGetTypeID(mainResource));
+ CFDictionaryRef mainResourceDictionary = (CFDictionaryRef)mainResource;
+
+ // Main resource should have a non-empty url and mime type.
+ CFTypeRef url = CFDictionaryGetValue(mainResourceDictionary, CFSTR("WebResourceURL"));
+ EXPECT_TRUE(url);
+ EXPECT_EQ(CFStringGetTypeID(), CFGetTypeID(url));
+ EXPECT_NE(CFStringGetLength((CFStringRef)url), 0);
+
+ CFTypeRef mimeType = CFDictionaryGetValue(mainResourceDictionary, CFSTR("WebResourceMIMEType"));
+ EXPECT_TRUE(mimeType);
+ EXPECT_EQ(CFStringGetTypeID(), CFGetTypeID(mimeType));
+ EXPECT_NE(CFStringGetLength((CFStringRef)mimeType), 0);
+
+ // Main resource dictionary should have a "WebResourceData" key.
+ CFTypeRef resourceData = CFDictionaryGetValue(mainResourceDictionary, CFSTR("WebResourceData"));
+ EXPECT_TRUE(resourceData);
+ EXPECT_EQ(CFDataGetTypeID(), CFGetTypeID(resourceData));
+
+ RetainPtr<CFStringRef> stringData = adoptCF(CFStringCreateFromExternalRepresentation(0, (CFDataRef)resourceData, kCFStringEncodingUTF8));
+ EXPECT_TRUE(stringData);
+
+ // It should contain the string "Simple HTML file." in it.
+ bool foundString = CFStringFind(stringData.get(), CFSTR("Simple HTML file."), 0).location != kCFNotFound;
+ EXPECT_TRUE(foundString);
+}
+
+static void setInjectedBundleClient(WKContextRef context)
+{
+ WKContextInjectedBundleClientV0 injectedBundleClient;
+ memset(&injectedBundleClient, 0, sizeof(injectedBundleClient));
+
+ injectedBundleClient.base.version = 0;
+ injectedBundleClient.didReceiveMessageFromInjectedBundle = didReceiveMessageFromInjectedBundle;
+
+ WKContextSetInjectedBundleClient(context, &injectedBundleClient.base);
+}
+
+static void didFinishLoadForFrame(WKPageRef page, WKFrameRef, WKTypeRef, const void*)
+{
+ didFinishLoad = true;
+}
+
+TEST(WebKit2, WebArchive)
+{
+ WKRetainPtr<WKContextRef> context = adoptWK(Util::createContextForInjectedBundleTest("WebArchiveTest"));
+ setInjectedBundleClient(context.get());
+
+ PlatformWebView webView(context.get());
+
+ WKPageLoaderClientV3 loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+
+ loaderClient.base.version = 3;
+ loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+
+ WKPageSetPageLoaderClient(webView.page(), &loaderClient.base);
+
+ WKPageLoadURL(webView.page(), adoptWK(Util::createURLForResource("simple", "html")).get());
+
+ // Wait till the load finishes before getting the web archive.
+ Util::run(&didFinishLoad);
+ WKContextPostMessageToInjectedBundle(context.get(), Util::toWK("GetWebArchive").get(), webView.page());
+
+ // Wait till we have received the web archive from the injected bundle.
+ Util::run(&didReceiveMessage);
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/WebArchive_Bundle.cpp
index e3cf58c2c..11109fee0 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/WebArchive_Bundle.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -24,57 +24,46 @@
*/
#include "config.h"
-#include "JSWrapper.h"
-#include <JavaScriptCore/JSContextRefPrivate.h>
+#if WK_HAVE_C_SPI
-namespace WTR {
+#include "InjectedBundleTest.h"
-JSValueRef JSWrapper::wrap(JSContextRef context, JSWrappable* object)
-{
- ASSERT_ARG(context, context);
+#include "PlatformUtilities.h"
+#include <WebKit/WKBundlePage.h>
+#include <WebKit/WKBundleFrame.h>
- if (!object)
- return JSValueMakeNull(context);
+namespace TestWebKitAPI {
- JSClassRef objectClass = object->wrapperClass();
- ASSERT(objectClass);
- JSObjectRef wrapperObject = JSObjectMake(context, objectClass, object);
- ASSERT(wrapperObject);
+class WebArchiveTest : public InjectedBundleTest {
+public:
+ WebArchiveTest(const std::string& identifier);
- return wrapperObject;
-}
+private:
+ virtual void didReceiveMessage(WKBundleRef, WKStringRef messageName, WKTypeRef messageBody);
+};
-JSWrappable* JSWrapper::unwrap(JSContextRef context, JSValueRef value)
-{
- ASSERT_ARG(context, context);
- ASSERT_ARG(value, value);
- if (!context || !value)
- return 0;
- return static_cast<JSWrappable*>(JSObjectGetPrivate(JSValueToObject(context, value, 0)));
-}
+static InjectedBundleTest::Register<WebArchiveTest> registrar("WebArchiveTest");
-static JSWrappable* unwrapObject(JSObjectRef object)
+WebArchiveTest::WebArchiveTest(const std::string& identifier)
+ : InjectedBundleTest(identifier)
{
- JSWrappable* wrappable = static_cast<JSWrappable*>(JSObjectGetPrivate(object));
- ASSERT(wrappable);
- return wrappable;
}
-void JSWrapper::initialize(JSContextRef ctx, JSObjectRef object)
+void WebArchiveTest::didReceiveMessage(WKBundleRef bundle, WKStringRef messageName, WKTypeRef body)
{
- JSWrappable* wrappable = unwrapObject(object);
- if (!wrappable)
+ if (!WKStringIsEqualToUTF8CString(messageName, "GetWebArchive"))
return;
- wrappable->ref();
-}
-void JSWrapper::finalize(JSObjectRef object)
-{
- JSWrappable* wrappable = unwrapObject(object);
- if (!wrappable)
+ if (WKGetTypeID(body) != WKBundlePageGetTypeID())
return;
- wrappable->deref();
+
+ WKBundleFrameRef frame = WKBundlePageGetMainFrame(static_cast<WKBundlePageRef>(body));
+ if (!frame)
+ return;
+ WKBundlePostMessage(bundle, Util::toWK("DidGetWebArchive").get(), adoptWK(WKBundleFrameCopyWebArchive(frame)).get());
}
-} // namespace WTR
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/WebCoreStatisticsWithNoWebProcess.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/WebCoreStatisticsWithNoWebProcess.cpp
new file mode 100644
index 000000000..ff5eef04d
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/WebCoreStatisticsWithNoWebProcess.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "PlatformUtilities.h"
+#include "Test.h"
+
+namespace TestWebKitAPI {
+
+static bool done;
+
+// Callback for WKContextGetStatistics.
+static void wkContextGetStatisticsCallback(WKDictionaryRef statistics, WKErrorRef error, void* functionContext)
+{
+ EXPECT_NOT_NULL(error);
+ done = true;
+}
+
+TEST(WebKit2, WebCoreStatisticsWithNoWebProcess)
+{
+ WKRetainPtr<WKContextRef> context = adoptWK(WKContextCreate());
+
+ WKContextGetStatistics(context.get(), 0, wkContextGetStatisticsCallback);
+
+ Util::run(&done);
+}
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/WillLoad.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/WillLoad.cpp
index 0f0bf4caf..83d63ab18 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/WillLoad.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/WillLoad.cpp
@@ -24,12 +24,13 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "Test.h"
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
-#include <wtf/OwnPtr.h>
-#include <wtf/PassOwnPtr.h>
namespace TestWebKitAPI {
@@ -41,7 +42,7 @@ public:
}
WKRetainPtr<WKContextRef> context;
- OwnPtr<PlatformWebView> webView;
+ std::unique_ptr<PlatformWebView> webView;
WKRetainPtr<WKStringRef> messageName;
WKRetainPtr<WKTypeRef> messageBody;
@@ -71,7 +72,7 @@ public:
context = adoptWK(Util::createContextForInjectedBundleTest("WillLoadTest"));
setInjectedBundleClient(context.get(), this);
- webView = adoptPtr(new PlatformWebView(context.get()));
+ webView = std::make_unique<PlatformWebView>(context.get());
didReceiveMessage = false;
}
@@ -239,3 +240,5 @@ TEST_F(WebKit2WillLoadTest, WKPageLoadPlainTextString)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/WillLoad_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/WillLoad_Bundle.cpp
index 783aebe7a..906ff05b7 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/WillLoad_Bundle.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/WillLoad_Bundle.cpp
@@ -24,11 +24,14 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "InjectedBundleTest.h"
#include "PlatformUtilities.h"
-#include <WebKit2/WKBundlePage.h>
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKBundlePage.h>
+#include <WebKit/WKRetainPtr.h>
namespace TestWebKitAPI {
@@ -47,7 +50,7 @@ private:
WKDictionarySetItem(messageBody.get(), Util::toWK("URLRequestReturn").get(), request);
WKDictionarySetItem(messageBody.get(), Util::toWK("UserDataReturn").get(), userData);
- WKBundlePostMessage(InjectedBundleController::shared().bundle(), Util::toWK("WillLoadURLRequestReturn").get(), messageBody.get());
+ WKBundlePostMessage(InjectedBundleController::singleton().bundle(), Util::toWK("WillLoadURLRequestReturn").get(), messageBody.get());
}
static void willLoadDataRequest(WKBundlePageRef page, WKURLRequestRef request, WKDataRef data, WKStringRef MIMEType, WKStringRef encodingName, WKURLRef unreachableURL, WKTypeRef userData, const void *clientInfo)
@@ -61,11 +64,11 @@ private:
WKDictionarySetItem(messageBody.get(), Util::toWK("UnreachableURLReturn").get(), unreachableURL);
WKDictionarySetItem(messageBody.get(), Util::toWK("UserDataReturn").get(), userData);
- WKBundlePostMessage(InjectedBundleController::shared().bundle(), Util::toWK("WillLoadDataRequestReturn").get(), messageBody.get());
+ WKBundlePostMessage(InjectedBundleController::singleton().bundle(), Util::toWK("WillLoadDataRequestReturn").get(), messageBody.get());
}
- virtual void didCreatePage(WKBundleRef, WKBundlePageRef bundlePage) override
+ void didCreatePage(WKBundleRef, WKBundlePageRef bundlePage) override
{
WKBundlePageLoaderClientV6 pageLoaderClient;
memset(&pageLoaderClient, 0, sizeof(pageLoaderClient));
@@ -82,3 +85,5 @@ private:
static InjectedBundleTest::Register<WillLoadTest> registrar("WillLoadTest");
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/WillSendSubmitEvent.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/WillSendSubmitEvent.cpp
index ee5934688..951aaf005 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/WillSendSubmitEvent.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/WillSendSubmitEvent.cpp
@@ -24,6 +24,9 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include "Test.h"
@@ -77,3 +80,5 @@ TEST(WebKit2, WillSendSubmitEvent)
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/WillSendSubmitEvent_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/WillSendSubmitEvent_Bundle.cpp
index e85ca256f..fa7d2a9a7 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/WillSendSubmitEvent_Bundle.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/WillSendSubmitEvent_Bundle.cpp
@@ -24,10 +24,13 @@
*/
#include "config.h"
+
+#if WK_HAVE_C_SPI
+
#include "InjectedBundleTest.h"
#include "PlatformUtilities.h"
-#include <WebKit2/WKBundlePage.h>
+#include <WebKit/WKBundlePage.h>
namespace TestWebKitAPI {
@@ -42,7 +45,7 @@ static InjectedBundleTest::Register<WillSendSubmitEventTest> registrar("WillSend
static void willSendSubmitEvent(WKBundlePageRef, WKBundleNodeHandleRef, WKBundleFrameRef, WKBundleFrameRef, WKDictionaryRef values, const void*)
{
- WKBundlePostMessage(InjectedBundleController::shared().bundle(), Util::toWK("DidReceiveWillSendSubmitEvent").get(), values);
+ WKBundlePostMessage(InjectedBundleController::singleton().bundle(), Util::toWK("DidReceiveWillSendSubmitEvent").get(), values);
}
WillSendSubmitEventTest::WillSendSubmitEventTest(const std::string& identifier)
@@ -63,3 +66,5 @@ void WillSendSubmitEventTest::didCreatePage(WKBundleRef bundle, WKBundlePageRef
}
} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/all-content-in-one-iframe.html b/Tools/TestWebKitAPI/Tests/WebKit2/all-content-in-one-iframe.html
new file mode 100644
index 000000000..6f45cbd6b
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/all-content-in-one-iframe.html
@@ -0,0 +1 @@
+<iframe src="lots-of-text.html"></iframe>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/associate-form-controls.html b/Tools/TestWebKitAPI/Tests/WebKit2/associate-form-controls.html
new file mode 100644
index 000000000..906246a54
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/associate-form-controls.html
@@ -0,0 +1,31 @@
+<html>
+<head>
+ <script>
+ function addForm()
+ {
+ var form = document.createElement("form");
+ form.id = "login_form";
+
+ var usernameField = document.createElement("input");
+ usernameField.id = "username";
+ usernameField.type = "text";
+ form.appendChild(usernameField);
+
+ document.body.appendChild(form);
+ }
+
+ function addPasswordFieldToForm()
+ {
+ var passwordField = document.createElement("input");
+ passwordField.id = "password";
+ passwordField.type = "password";
+
+ var form = document.getElementById("login_form");
+ form.appendChild(passwordField);
+ }
+ </script>
+</head>
+<body onload="addForm()">
+<button onclick="addPasswordFieldToForm()">Manual Testing: Add the password field</button>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/auto-submitting-form.html b/Tools/TestWebKitAPI/Tests/WebKit2/auto-submitting-form.html
new file mode 100644
index 000000000..9ed815e03
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/auto-submitting-form.html
@@ -0,0 +1,20 @@
+<html>
+ <head>
+ <script>
+ function submitFormIfNecessary()
+ {
+ if (window.location.search)
+ return;
+ document.forms[0].submit.click();
+ }
+ </script>
+ </head>
+ <body onload="submitFormIfNecessary()">
+ <form action="#" method="GET">
+ <input type="text" name="textField" value="text field">
+ <input type="password" name="passwordField" value="password field">
+ <input type="hidden" name="hiddenField" value="hidden field">
+ <input type="submit" name="submit">
+ </form>
+ </body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/autoplay-check-frame.html b/Tools/TestWebKitAPI/Tests/WebKit2/autoplay-check-frame.html
new file mode 100644
index 000000000..2c43fda1a
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/autoplay-check-frame.html
@@ -0,0 +1,16 @@
+<html>
+ <head>
+ <script>
+ function pageLoaded() {
+ document.getElementById("video").play().then(function() {
+ window.parent.postMessage('autoplayed', '*');
+ }).catch(function() {
+ window.parent.postMessage('did-not-play', '*');
+ });
+ }
+ </script>
+ </head>
+ <body onload="pageLoaded()">
+ <video id="video" playsinline src="test.mp4" />
+ </body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/autoplay-check-in-iframe.html b/Tools/TestWebKitAPI/Tests/WebKit2/autoplay-check-in-iframe.html
new file mode 100644
index 000000000..f1a3cbc8f
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/autoplay-check-in-iframe.html
@@ -0,0 +1,16 @@
+<html>
+ <head>
+ <script>
+ function pageLoaded() {
+ window.onmessage = function(event) {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage(event.data);
+ } catch(e) { }
+ };
+ }
+ </script>
+ </head>
+ <body onload="pageLoaded()">
+ <iframe src="autoplay-check-frame.html"></iframe>
+ </body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/autoplay-check.html b/Tools/TestWebKitAPI/Tests/WebKit2/autoplay-check.html
new file mode 100644
index 000000000..ecc3c884e
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/autoplay-check.html
@@ -0,0 +1,20 @@
+<html>
+ <head>
+ <script>
+ function pageLoaded() {
+ document.getElementById("video").play().then(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("autoplayed");
+ } catch(e) { }
+ }).catch(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("did-not-play");
+ } catch(e) { }
+ });
+ }
+ </script>
+ </head>
+ <body onload="pageLoaded()">
+ <video id="video" playsinline src="test.mp4" />
+ </body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/autoplay-no-audio-check.html b/Tools/TestWebKitAPI/Tests/WebKit2/autoplay-no-audio-check.html
new file mode 100644
index 000000000..dc1cc7325
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/autoplay-no-audio-check.html
@@ -0,0 +1,20 @@
+<html>
+ <head>
+ <script>
+ function pageLoaded() {
+ document.getElementById("video").play().then(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("autoplayed");
+ } catch(e) { }
+ }).catch(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("did-not-play");
+ } catch(e) { }
+ });
+ }
+ </script>
+ </head>
+ <body onload="pageLoaded()">
+ <video id="video" playsinline src="test-without-audio-track.mp4" />
+ </body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/autoplay-with-controls.html b/Tools/TestWebKitAPI/Tests/WebKit2/autoplay-with-controls.html
new file mode 100644
index 000000000..cf80a6578
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/autoplay-with-controls.html
@@ -0,0 +1,19 @@
+<html>
+ <head>
+ <script>
+ function pageLoaded() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("loaded");
+ } catch(e) { }
+ }
+
+ function play() {
+ document.getElementById("video").play();
+ }
+ </script>
+ </head>
+ <body onload="pageLoaded()">
+ <button onclick="play()">Play</button>
+ <video id="video" autoplay src="test.mp4" />
+ </body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/bundle-file.html b/Tools/TestWebKitAPI/Tests/WebKit2/bundle-file.html
new file mode 100644
index 000000000..f426ebdb0
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/bundle-file.html
@@ -0,0 +1,16 @@
+<html>
+<head>
+ <script>
+ function testFile(file)
+ {
+ if (!(file instanceof File))
+ return false;
+
+ return true;
+ }
+ </script>
+</head>
+<body>
+ File test.
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/chinese-character-with-image.html b/Tools/TestWebKitAPI/Tests/WebKit2/chinese-character-with-image.html
new file mode 100644
index 000000000..179085749
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/chinese-character-with-image.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<meta http-equiv='content-type' content='text/html; charset=utf-8'>
+<body>
+<div contenteditable>
+<p><br></p>
+<p style="text-align: center; font-size: 15px;"><img src="icon.png">你</p>
+<p>hello, world</p>
+</div>
+<script>
+document.querySelector('div').focus();
+getSelection().setPosition(document.querySelector('img').parentNode, 1);
+</script>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/close-from-within-create-page.html b/Tools/TestWebKitAPI/Tests/WebKit2/close-from-within-create-page.html
new file mode 100644
index 000000000..51c7981c1
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/close-from-within-create-page.html
@@ -0,0 +1,16 @@
+<html>
+<script>
+function runTest()
+{
+ if (document.location.search === "?opened-window") {
+ alert(window.sessionStorage['storageKey'])
+ return;
+ }
+
+ window.sessionStorage['storageKey'] = 'value';
+ window.open("close-from-within-create-page.html?opened-window");
+}
+</script>
+<body onload="runTest()">
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/closed-shadow-tree-test.html b/Tools/TestWebKitAPI/Tests/WebKit2/closed-shadow-tree-test.html
new file mode 100644
index 000000000..a161563e2
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/closed-shadow-tree-test.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<body>
+<shadow-host><span>5</span><span slot="bar">2</span></shadow-host>
+<input type="text">
+<script>
+const shadowRoot = document.querySelector('shadow-host').attachShadow({mode: 'closed'});
+shadowRoot.innerHTML = `
+ <span>1</span>
+ <inner-host>
+ <slot name="bar" slot="foo"><span>FAIL - named slot fallback</span></slot>
+ <span>FAIL - unassigned content</span>
+ <span slot="foo">3</span>
+ </inner-host>
+ <slot><span>FAIL - default slot fallback</span></slot>
+ <span>6</span>`;
+const innerHost = shadowRoot.querySelector('inner-host');
+innerHost.attachShadow({mode: 'closed'}).innerHTML = `
+ <slot name="foo"></slot>
+ <span>4</span>`;
+
+document.addEventListener('testnormalworld', function (event) {
+ alert(window[event.detail] ? `FAIL: ${event.detail} was present in the normal world` : `PASS: ${event.detail} was not present in the normal world`);
+});
+
+</script>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/contentBlockerCheck.html b/Tools/TestWebKitAPI/Tests/WebKit2/contentBlockerCheck.html
new file mode 100644
index 000000000..c791a857a
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/contentBlockerCheck.html
@@ -0,0 +1,13 @@
+<html>
+ <head>
+ <script>
+ function sendMessage() { alert(getComputedStyle(document.querySelector(".hidden")).display == "none" ? "content blockers enabled" :"content blockers disabled"); }
+ </script>
+ </head>
+ <body onload="sendMessage()">
+ <p class="hidden">
+ This text exists to determine if content blockers are enabled.
+ If they're enabled, the computed style of this text will be display:none.
+ </p>
+ </body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/custom-protocol-sync-xhr.html b/Tools/TestWebKitAPI/Tests/WebKit2/custom-protocol-sync-xhr.html
new file mode 100644
index 000000000..6cf00b6ca
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/custom-protocol-sync-xhr.html
@@ -0,0 +1,6 @@
+<script>
+ var request = new XMLHttpRequest();
+ request.open('GET', 'http://test', false);
+ request.send(null);
+ window._testResult = request.responseText;
+</script> \ No newline at end of file
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/enumerateMediaDevices.html b/Tools/TestWebKitAPI/Tests/WebKit2/enumerateMediaDevices.html
new file mode 100644
index 000000000..ffde3ced5
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/enumerateMediaDevices.html
@@ -0,0 +1,24 @@
+<html>
+ <head>
+ <script>
+ function enumerate(devices)
+ {
+ console.log("enumerateDevices succeeded");
+ }
+
+ function userMediaError(error)
+ {
+ console.log(error);
+ }
+
+ function test()
+ {
+ navigator.mediaDevices.enumerateDevices()
+ .then(enumerate)
+ .catch(userMediaError);
+ }
+ </script>
+ </head>
+ <body onload="test()">
+ </body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/execCopy.html b/Tools/TestWebKitAPI/Tests/WebKit2/execCopy.html
new file mode 100644
index 000000000..cf4608ebd
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/execCopy.html
@@ -0,0 +1,15 @@
+<html>
+<head>
+<script type="text/javascript">
+ function doCopy() {
+ document.execCommand("selectAll", true);
+ document.execCommand("copy");
+ }
+</script>
+</head>
+<body onLoad="doCopy()">
+ <div>Hello world.</div>
+ <div><b>Hello</b><i> world</i></div>
+ <div style="border: solid red 1px">Hello world</div>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/file-with-anchor.html b/Tools/TestWebKitAPI/Tests/WebKit2/file-with-anchor.html
new file mode 100644
index 000000000..8ea866ba9
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/file-with-anchor.html
@@ -0,0 +1,19 @@
+<html>
+<head>
+ <script>
+ function clickLink()
+ {
+ var evt = document.createEvent("MouseEvent");
+ evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
+ var link = document.querySelector('a');
+ link.dispatchEvent(evt);
+ }
+ </script>
+</head>
+<body>
+ <a href="#anchor">Link to anchor</a><br>
+ In between.<br>
+ <span id="anchor">Anchor</span><br>
+ After the anchor.<br>
+ </body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/file-with-mse.html b/Tools/TestWebKitAPI/Tests/WebKit2/file-with-mse.html
new file mode 100644
index 000000000..4cc910135
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/file-with-mse.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script>
+ var source;
+ var request;
+
+ function playVideo()
+ {
+ document.getElementById('test-video').play();
+ request = new XMLHttpRequest();
+ request.responseType = 'arraybuffer';
+ request.open('GET', 'test-mse.mp4', true);
+ request.addEventListener('load', load);
+ request.send();
+ }
+
+ function load(event)
+ {
+ source = new MediaSource();
+ source.addEventListener('sourceopen', sourceopen);
+ var video = document.getElementById('test-video');
+ video.src = URL.createObjectURL(source);
+ }
+
+ function sourceopen(event)
+ {
+ var sourceBuffer = source.addSourceBuffer('video/mp4;codecs="avc1.4D4001,mp4a.40.2"');
+ sourceBuffer.appendBuffer(request.response);
+ }
+ </script>
+</head>
+<body>
+ <p>
+ <video id="test-video" controls></video>
+ </p>
+ <p>
+ <button onclick="playVideo()">Play video</button>
+ </p>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/file-with-video.html b/Tools/TestWebKitAPI/Tests/WebKit2/file-with-video.html
new file mode 100644
index 000000000..aa2259a0f
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/file-with-video.html
@@ -0,0 +1,18 @@
+<html>
+<head>
+ <script>
+ function playVideo()
+ {
+ document.getElementById("test-video").play();
+ }
+ </script>
+</head>
+<body>
+ <p>
+ <video id="test-video" src="test.mp4" controls></video>
+ </p>
+ <p>
+ <button onclick="playVideo()">Play Video</button>
+ </p>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/find.html b/Tools/TestWebKitAPI/Tests/WebKit2/find.html
new file mode 100644
index 000000000..d9659119d
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/find.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+ Test search. Hello Hello Hello!
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/findRanges.html b/Tools/TestWebKitAPI/Tests/WebKit2/findRanges.html
new file mode 100644
index 000000000..e10bbeb47
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/findRanges.html
@@ -0,0 +1,11 @@
+<html>
+<body>Test search. Hello world, Hello crazy world, Hello!</body>
+<script>
+ var s = window.getSelection();
+ var r = document.createRange();
+
+ r.setStart(document.body.firstChild, 38);
+ r.setEnd(document.body.firstChild, 43);
+ s.addRange(r);
+</script>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/geolocationGetCurrentPosition.html b/Tools/TestWebKitAPI/Tests/WebKit2/geolocationGetCurrentPosition.html
new file mode 100644
index 000000000..099f51536
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/geolocationGetCurrentPosition.html
@@ -0,0 +1,3 @@
+<script>
+navigator.geolocation.getCurrentPosition(function() { });
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/geolocationGetCurrentPositionWithHighAccuracy.html b/Tools/TestWebKitAPI/Tests/WebKit2/geolocationGetCurrentPositionWithHighAccuracy.html
new file mode 100644
index 000000000..26a314858
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/geolocationGetCurrentPositionWithHighAccuracy.html
@@ -0,0 +1,3 @@
+<script>
+navigator.geolocation.getCurrentPosition(function() { }, function() {}, { enableHighAccuracy:true });
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/geolocationWatchPosition.html b/Tools/TestWebKitAPI/Tests/WebKit2/geolocationWatchPosition.html
new file mode 100644
index 000000000..24788b780
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/geolocationWatchPosition.html
@@ -0,0 +1,3 @@
+<script>
+navigator.geolocation.watchPosition(function() { });
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/geolocationWatchPositionWithHighAccuracy.html b/Tools/TestWebKitAPI/Tests/WebKit2/geolocationWatchPositionWithHighAccuracy.html
new file mode 100644
index 000000000..aba98fce7
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/geolocationWatchPositionWithHighAccuracy.html
@@ -0,0 +1,3 @@
+<script>
+navigator.geolocation.watchPosition(function() { }, function() {}, { enableHighAccuracy:true });
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/getUserMedia.html b/Tools/TestWebKitAPI/Tests/WebKit2/getUserMedia.html
new file mode 100644
index 000000000..e54f853bf
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/getUserMedia.html
@@ -0,0 +1,14 @@
+<script>
+function gotUserMedia(mediaStream)
+{
+ console.log("Got user media");
+}
+
+function userMediaError(error)
+{
+ console.log(error);
+}
+
+var options = { audio: false, video: true};
+navigator.webkitGetUserMedia(options, gotUserMedia, userMediaError);
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/gtk/InputMethodFilter.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/gtk/InputMethodFilter.cpp
index 4aab7c0a2..4a0e684d6 100644
--- a/Tools/TestWebKitAPI/Tests/gtk/InputMethodFilter.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/gtk/InputMethodFilter.cpp
@@ -25,44 +25,45 @@
#include "config.h"
-#include "GtkInputMethodFilter.h"
#include "WTFStringUtilities.h"
+#include <WebKit/InputMethodFilter.h>
#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
-#include <wtf/gobject/GUniquePtr.h>
-#include <wtf/gobject/GRefPtr.h>
+#include <wtf/glib/GRefPtr.h>
+#include <wtf/glib/GUniquePtr.h>
#include <wtf/text/CString.h>
-using namespace WebCore;
+using namespace WebKit;
namespace TestWebKitAPI {
-class TestInputMethodFilter : public GtkInputMethodFilter {
+class TestInputMethodFilter : public InputMethodFilter {
public:
TestInputMethodFilter()
: m_testWindow(gtk_window_new(GTK_WINDOW_POPUP))
{
- gtk_widget_show(m_testWindow.get());
- setWidget(m_testWindow.get());
+ setTestingMode(true);
- // Focus in is necessary to activate the default input method in the multicontext.
- notifyFocusedIn();
+ gtk_widget_show(m_testWindow);
+ gtk_im_context_set_client_window(context(), gtk_widget_get_window(m_testWindow));
+
+ setEnabled(true);
}
- Vector<String>& events() { return m_events; }
+ ~TestInputMethodFilter()
+ {
+ gtk_widget_destroy(m_testWindow);
+ }
- void sendKeyEventToFilter(unsigned int gdkKeyValue, GdkEventType type, unsigned int modifiers = 0)
+ void sendKeyEventToFilter(unsigned gdkKeyValue, GdkEventType type, unsigned modifiers = 0)
{
GdkEvent* event = gdk_event_new(type);
event->key.keyval = gdkKeyValue;
event->key.state = modifiers;
- event->key.window = gtk_widget_get_window(m_testWindow.get());
+ event->key.window = gtk_widget_get_window(m_testWindow);
event->key.time = GDK_CURRENT_TIME;
g_object_ref(event->key.window);
-
-#ifndef GTK_API_VERSION_2
gdk_event_set_device(event, gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(gdk_display_get_default())));
-#endif
GUniqueOutPtr<GdkKeymapKey> keys;
gint nKeys;
@@ -73,70 +74,17 @@ public:
gdk_event_free(event);
}
- void sendPressAndReleaseKeyEventPairToFilter(unsigned int gdkKeyValue, unsigned int modifiers = 0)
+ void sendPressAndReleaseKeyEventPairToFilter(unsigned gdkKeyValue, unsigned modifiers = 0)
{
sendKeyEventToFilter(gdkKeyValue, GDK_KEY_PRESS, modifiers);
sendKeyEventToFilter(gdkKeyValue, GDK_KEY_RELEASE, modifiers);
}
-protected:
- virtual bool sendSimpleKeyEvent(GdkEventKey* event, WTF::String eventString, EventFakedForComposition faked)
- {
- const char* eventType = event->type == GDK_KEY_RELEASE ? "release" : "press";
- const char* fakedString = faked == EventFaked ? " (faked)" : "";
- if (!eventString.isNull())
- m_events.append(String::format("sendSimpleKeyEvent type=%s keycode=%x text='%s'%s", eventType, event->keyval, eventString.utf8().data(), fakedString));
- else
- m_events.append(String::format("sendSimpleKeyEvent type=%s keycode=%x%s", eventType, event->keyval, fakedString));
-
- return true;
- }
-
- virtual bool sendKeyEventWithCompositionResults(GdkEventKey* event, ResultsToSend resultsToSend, EventFakedForComposition faked)
- {
- const char* eventType = event->type == GDK_KEY_RELEASE ? "release" : "press";
- const char* fakedString = faked == EventFaked ? " (faked)" : "";
- m_events.append(String::format("sendKeyEventWithCompositionResults type=%s keycode=%u%s", eventType, event->keyval, fakedString));
-
- if (resultsToSend & Composition && !m_confirmedComposition.isNull())
- confirmCompositionText(m_confirmedComposition);
- if (resultsToSend & Preedit && !m_preedit.isNull())
- setPreedit(m_preedit, m_cursorOffset);
-
- return true;
- }
-
- virtual bool canEdit()
- {
- return true;
- }
-
- virtual void confirmCompositionText(String text)
- {
- m_events.append(String::format("confirmComposition '%s'", text.utf8().data()));
- }
-
- virtual void confirmCurrentComposition()
- {
- m_events.append(String("confirmCurrentcomposition"));
- }
-
- virtual void cancelCurrentComposition()
- {
- m_events.append(String("cancelCurrentComposition"));
- }
-
- virtual void setPreedit(String preedit, int cursorOffset)
- {
- m_events.append(String::format("setPreedit text='%s' cursorOffset=%i", preedit.utf8().data(), cursorOffset));
- }
-
private:
- GRefPtr<GtkWidget> m_testWindow;
- Vector<String> m_events;
+ GtkWidget* m_testWindow;
};
-TEST(GTK, GtkInputMethodFilterSimple)
+TEST(WebKit2, InputMethodFilterSimple)
{
TestInputMethodFilter inputMethodFilter;
inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_g);
@@ -154,7 +102,7 @@ TEST(GTK, GtkInputMethodFilterSimple)
ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=6b"), events[5]);
}
-TEST(GTK, GtkInputMethodFilterUnicodeSequence)
+TEST(WebKit2, InputMethodFilterUnicodeSequence)
{
TestInputMethodFilter inputMethodFilter;
@@ -201,7 +149,7 @@ TEST(GTK, GtkInputMethodFilterUnicodeSequence)
ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=ffe3"), events[20]);
}
-TEST(GTK, GtkInputMethodFilterComposeKey)
+TEST(WebKit2, InputMethodFilterComposeKey)
{
TestInputMethodFilter inputMethodFilter;
@@ -225,7 +173,7 @@ static void temporaryGetPreeditStringOverride(GtkIMContext*, char** string, Pang
*cursorPosition = 3;
}
-TEST(GTK, GtkInputMethodFilterContextEventsWithoutKeyEvents)
+TEST(WebKit2, InputMethodFilterContextEventsWithoutKeyEvents)
{
TestInputMethodFilter inputMethodFilter;
@@ -267,7 +215,7 @@ static void verifyCanceledComposition(const Vector<String>& events)
ASSERT(gSawContextReset);
}
-TEST(GTK, GtkInputMethodFilterContextFocusOutDuringOngoingComposition)
+TEST(WebKit2, InputMethodFilterContextFocusOutDuringOngoingComposition)
{
TestInputMethodFilter inputMethodFilter;
@@ -287,7 +235,7 @@ TEST(GTK, GtkInputMethodFilterContextFocusOutDuringOngoingComposition)
contextClass->reset = previousCallback;
}
-TEST(GTK, GtkInputMethodFilterContextMouseClickDuringOngoingComposition)
+TEST(WebKit2, InputMethodFilterContextMouseClickDuringOngoingComposition)
{
TestInputMethodFilter inputMethodFilter;
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/icon.png b/Tools/TestWebKitAPI/Tests/WebKit2/icon.png
new file mode 100644
index 000000000..79e459894
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/icon.png
Binary files differ
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/input-focus-blur.html b/Tools/TestWebKitAPI/Tests/WebKit2/input-focus-blur.html
new file mode 100644
index 000000000..05d84902b
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/input-focus-blur.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<body>
+<div tabindex=0></div>
+<input id="input" type="text">
+<input id="readonly" type="text" readonly>
+<script>
+
+document.querySelector('div').focus();
+
+function focusTextField(id)
+{
+ document.getElementById(id).focus();
+}
+
+function blurTextField(id)
+{
+ document.getElementById(id).blur();
+}
+
+function removeTextField(id)
+{
+ document.getElementById(id).remove();
+}
+
+</script>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/js-play-with-controls.html b/Tools/TestWebKitAPI/Tests/WebKit2/js-play-with-controls.html
new file mode 100644
index 000000000..da9cb1c07
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/js-play-with-controls.html
@@ -0,0 +1,20 @@
+<html>
+ <head>
+ <script>
+ function pageLoaded() {
+ document.getElementById("video").play();
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("loaded");
+ } catch(e) { }
+ }
+
+ function play() {
+ document.getElementById("video").play();
+ }
+ </script>
+ </head>
+ <body onload="pageLoaded()">
+ <button onclick="play()">Play</button>
+ <video id="video" src="test.mp4" />
+ </body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/link-with-download-attribute.html b/Tools/TestWebKitAPI/Tests/WebKit2/link-with-download-attribute.html
new file mode 100644
index 000000000..c05594518
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/link-with-download-attribute.html
@@ -0,0 +1,10 @@
+<html>
+ <body>
+ <a id="testAnchor" style="display: block; height: 100%; width: 100%" download="downloadAttributeValue.txt"></a>
+ <script>
+ var blob = new Blob(["Hello world!"], {type: "application/octet-stream"});
+ var link = document.getElementById("testAnchor");
+ link.href = window.URL.createObjectURL(blob);
+ </script>
+ </body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/link-with-title.html b/Tools/TestWebKitAPI/Tests/WebKit2/link-with-title.html
new file mode 100644
index 000000000..971ed281b
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/link-with-title.html
@@ -0,0 +1,5 @@
+<html>
+ <body>
+ <a href="#" style="display: block; height: 100%;" title="HitTestLinkTitle"></a>
+ </body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/lots-of-iframes.html b/Tools/TestWebKitAPI/Tests/WebKit2/lots-of-iframes.html
new file mode 100644
index 000000000..5436310c8
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/lots-of-iframes.html
@@ -0,0 +1,35 @@
+<html>
+<head>
+<script type="text/javascript">
+ var maxNumberOfFrames = 100;
+
+ function createIFrames() {
+ var str = "<div id=\"status\"></div>";
+ for (var i = 0; i < maxNumberOfFrames + 1; i++) {
+ str += "<iframe id=\"i" + i + "\" src=\"data:text/html,iframe_" + i + "\"></iframe>";
+ }
+ document.getElementsByTagName("body")[0].innerHTML = str;
+
+ var results = "";
+
+ var f = document.getElementById("i" + (maxNumberOfFrames - 1));
+ if (f && f.contentWindow) {
+ results += "Sucessfully created " + maxNumberOfFrames + " frames.<br>";
+ } else {
+ results += "Failed to create " + maxNumberOfFrames + " frames.<br>";
+ }
+
+ var g = document.getElementById("i" + maxNumberOfFrames);
+ if (g && g.contentWindow) {
+ results += "Failed to block creation of frame number " + (maxNumberOfFrames + 1) + ".";
+ } else {
+ results += "Successfully blocked creation of frame number " + (maxNumberOfFrames + 1) + ".";
+ }
+
+ document.getElementById("status").innerHTML = results;
+ }
+</script>
+</head>
+<body onLoad="createIFrames()">
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/lots-of-images.html b/Tools/TestWebKitAPI/Tests/WebKit2/lots-of-images.html
new file mode 100644
index 000000000..2233b8e0b
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/lots-of-images.html
@@ -0,0 +1,17 @@
+<img src="icon.png"/>
+<img src="icon.png"/>
+<img src="icon.png"/>
+<img src="icon.png"/>
+<img src="icon.png"/>
+<img src="icon.png"/>
+<img src="icon.png"/>
+<img src="icon.png"/>
+<img src="icon.png"/>
+<img src="icon.png"/>
+<img src="icon.png"/>
+<img src="icon.png"/>
+<img src="icon.png"/>
+<img src="icon.png"/>
+<img src="icon.png"/>
+<img src="icon.png"/>
+<img src="icon.png"/>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/lots-of-text-vertical-lr.html b/Tools/TestWebKitAPI/Tests/WebKit2/lots-of-text-vertical-lr.html
new file mode 100644
index 000000000..9598a3efa
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/lots-of-text-vertical-lr.html
@@ -0,0 +1,3 @@
+<body style="-webkit-writing-mode: vertical-lr;">
+You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!
+</body>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/lots-of-text.html b/Tools/TestWebKitAPI/Tests/WebKit2/lots-of-text.html
new file mode 100644
index 000000000..3cd1b4c52
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/lots-of-text.html
@@ -0,0 +1,3 @@
+<body style="width:800px">
+You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too! You say it's your Birthday. It's my Birthday too!
+</body>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/many-iframes.html b/Tools/TestWebKitAPI/Tests/WebKit2/many-iframes.html
new file mode 100644
index 000000000..44f17f586
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/many-iframes.html
@@ -0,0 +1,15 @@
+<html>
+<body>
+ Simple HTML file with many iframes.
+ <iframe src="simple.html"></iframe>
+ <iframe src="simple.html"></iframe>
+ <iframe src="simple.html"></iframe>
+ <iframe src="simple.html"></iframe>
+ <iframe src="simple.html"></iframe>
+ <iframe src="simple.html"></iframe>
+ <iframe src="simple.html"></iframe>
+ <iframe src="simple.html"></iframe>
+ <iframe src="simple.html"></iframe>
+ <iframe src="simple.html"></iframe>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/modal-alerts-in-new-about-blank-window.html b/Tools/TestWebKitAPI/Tests/WebKit2/modal-alerts-in-new-about-blank-window.html
new file mode 100644
index 000000000..f76cb650b
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/modal-alerts-in-new-about-blank-window.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+
+var newWindow = window.open("about:blank");
+newWindow.alert("Testing alert");
+newWindow.confirm("Testing confirm");
+newWindow.prompt("Testing prompt", "Default text");
+
+</script>
+</head>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/mouse-button-listener.html b/Tools/TestWebKitAPI/Tests/WebKit2/mouse-button-listener.html
new file mode 100644
index 000000000..1fdbb1a95
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/mouse-button-listener.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<script>
+ var mouseButton = -1;
+ var menuType = "none";
+
+ function mouseDownHandler(event)
+ {
+ mouseButton = event.button;
+ event.preventDefault();
+ }
+
+ function pressedMouseButton()
+ {
+ return mouseButton;
+ }
+
+ function contextMenuHandler(event)
+ {
+ menuType = "context";
+ event.preventDefault();
+ }
+
+ function displayedMenu()
+ {
+ return menuType;
+ }
+
+ addEventListener("mousedown", mouseDownHandler);
+ addEventListener("contextmenu", contextMenuHandler);
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/mouse-move-listener.html b/Tools/TestWebKitAPI/Tests/WebKit2/mouse-move-listener.html
new file mode 100644
index 000000000..afca7ed86
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/mouse-move-listener.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<script>
+ var mouseMoved = false;
+
+ function mouseMoveHandler()
+ {
+ mouseMoved = true;
+ }
+
+ function didMoveMouse()
+ {
+ return mouseMoved;
+ }
+
+ addEventListener("mousemove", mouseMoveHandler);
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/no-autoplay-with-controls.html b/Tools/TestWebKitAPI/Tests/WebKit2/no-autoplay-with-controls.html
new file mode 100644
index 000000000..676bac205
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/no-autoplay-with-controls.html
@@ -0,0 +1,25 @@
+<html>
+ <head>
+ <script>
+ function pageLoaded() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("loaded");
+ } catch(e) { }
+ }
+
+ function beganPlaying() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("played");
+ } catch(e) { }
+ }
+
+ function play() {
+ document.getElementById("video").play();
+ }
+ </script>
+ </head>
+ <body onload="pageLoaded()">
+ <button onclick="play()">Play</button>
+ <video id="video" onplaying=beganPlaying() src="test.mp4" />
+ </body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/open-and-close-window.html b/Tools/TestWebKitAPI/Tests/WebKit2/open-and-close-window.html
new file mode 100644
index 000000000..6ac778a9e
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/open-and-close-window.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+if (document.location.search === "?close-window")
+ window.close();
+else
+ window.open("open-and-close-window.html?close-window");
+</script>
+</head>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/push-state.html b/Tools/TestWebKitAPI/Tests/WebKit2/push-state.html
new file mode 100644
index 000000000..f3a04a6bb
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/push-state.html
@@ -0,0 +1,3 @@
+<script type="text/javascript">
+history.pushState('newState', 0, '?newState');
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/set-long-title.html b/Tools/TestWebKitAPI/Tests/WebKit2/set-long-title.html
new file mode 100644
index 000000000..c31765a9e
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/set-long-title.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+<title>Original Short Title</title>
+</head>
+<body>
+<script>
+document.title = Array(8096).join(String.fromCharCode(0x8181));
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/should-open-external-schemes.html b/Tools/TestWebKitAPI/Tests/WebKit2/should-open-external-schemes.html
new file mode 100644
index 000000000..299e4d66a
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/should-open-external-schemes.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function navigateToTelURL()
+{
+ window.location.href = "tel:+1 (408) 996-1010";
+}
+
+function navigateToTelURLInZeroTimer()
+{
+ window.setTimeout(navigateToTelURL, 0);
+}
+
+function navigateToTelURLInNestedZeroTimer()
+{
+ window.setTimeout(navigateToTelURLInZeroTimer, 0);
+}
+</script>
+</head>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/simple-accelerated-compositing.html b/Tools/TestWebKitAPI/Tests/WebKit2/simple-accelerated-compositing.html
new file mode 100644
index 000000000..bea62721b
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/simple-accelerated-compositing.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+ <div style="-webkit-transform: translateZ(0);">Simple HTML file with accelerated compositing</div>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/simple-form.html b/Tools/TestWebKitAPI/Tests/WebKit2/simple-form.html
new file mode 100644
index 000000000..3bf185293
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/simple-form.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<script>
+function submitForm()
+{
+ document.forms[0].submit();
+}
+</script>
+<form method=post>
+<input name=foo value="Some unimportant data">
+<input type=submit>
+</form>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/simple-iframe.html b/Tools/TestWebKitAPI/Tests/WebKit2/simple-iframe.html
new file mode 100644
index 000000000..429521c7f
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/simple-iframe.html
@@ -0,0 +1,6 @@
+<html>
+<body>
+ Simple HTML file.
+ <iframe src="simple.html"></iframe>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/simple-tall.html b/Tools/TestWebKitAPI/Tests/WebKit2/simple-tall.html
new file mode 100644
index 000000000..a220e9b2d
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/simple-tall.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+<body>
+ Simple and tall HTML file.
+ <div style="height: 3000px;"></div>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/simple.html b/Tools/TestWebKitAPI/Tests/WebKit2/simple.html
new file mode 100644
index 000000000..12cf87364
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/simple.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+ Simple HTML file.
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/simple2.html b/Tools/TestWebKitAPI/Tests/WebKit2/simple2.html
new file mode 100644
index 000000000..1dcbfddd2
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/simple2.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+ Second simple HTML file.
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/simple3.html b/Tools/TestWebKitAPI/Tests/WebKit2/simple3.html
new file mode 100644
index 000000000..786516e89
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/simple3.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+ Third simple HTML file.
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/spacebar-scrolling.html b/Tools/TestWebKitAPI/Tests/WebKit2/spacebar-scrolling.html
new file mode 100644
index 000000000..8da08b3f9
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/spacebar-scrolling.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<script>
+ function textFieldContainsSpace()
+ {
+ return document.querySelector("input").value === " ";
+ }
+
+ function blurTextField()
+ {
+ document.querySelector("input").blur();
+ }
+
+ function isDocumentScrolled()
+ {
+ return scrollY !== 0;
+ }
+
+ function loaded()
+ {
+ document.querySelector("input").focus();
+ }
+
+ addEventListener("load", loaded);
+</script>
+<input>
+<div style="height: 3000px;"></div>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/test-mse.mp4 b/Tools/TestWebKitAPI/Tests/WebKit2/test-mse.mp4
new file mode 100644
index 000000000..901c907e0
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/test-mse.mp4
Binary files differ
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/test-without-audio-track.mp4 b/Tools/TestWebKitAPI/Tests/WebKit2/test-without-audio-track.mp4
new file mode 100644
index 000000000..8ad09c03c
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/test-without-audio-track.mp4
Binary files differ
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/test.mp4 b/Tools/TestWebKitAPI/Tests/WebKit2/test.mp4
new file mode 100644
index 000000000..d278c8ad8
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/test.mp4
Binary files differ
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/webfont.html b/Tools/TestWebKitAPI/Tests/WebKit2/webfont.html
new file mode 100644
index 000000000..008edd098
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/webfont.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+@font-face {
+ font-family: "WebFont";
+ src: url("Ahem.ttf") format("truetype");
+}
+</style>
+</head>
+<body>
+<div style="font: 100px 'WebFont';">Hello</div>
+This tests passes if there is no Web Process crash.
+</body>
+</html> \ No newline at end of file
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/AllAhem.svg b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/AllAhem.svg
new file mode 100644
index 000000000..135d00999
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/AllAhem.svg
@@ -0,0 +1,111 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata></metadata>
+<defs>
+<font id="Litherum" horiz-adv-x="1024">
+<font-face units-per-em="1024" ascent="1024" descent="-1"/>
+<glyph unicode="1" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="2" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="3" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x0021;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x0024;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x0025;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x003a;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x003b;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x003f;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x00a2;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x00a3;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x00a5;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x00b0;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x2010;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x2013;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x2025;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x2026;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x2030;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x2032;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x2033;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x203c;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x2047;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x2048;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x2049;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x20ac;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x2103;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x2116;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x3005;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x301c;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x303b;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x3041;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x3043;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x3045;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x3047;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x3049;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x3063;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x3083;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x3085;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x3087;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x308e;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x3095;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x3096;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x309d;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x309e;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x30a0;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x30a1;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x30a3;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x30a5;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x30a7;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x30a9;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x30c3;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x30e3;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x30e5;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x30e7;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x30ee;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x30f5;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x30f6;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x30fb;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x30fc;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x30fd;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x30fe;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x31f0;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x31f1;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x31f2;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x31f3;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x31f4;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x31f5;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x31f6;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x31f7;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x31f8;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x31f9;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x31fa;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x31fb;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x31fc;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x31fd;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x31fe;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x31ff;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x4e00;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x4e09;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x4e8c;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#x56db;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#xff01;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#xff04;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#xff05;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#xff1a;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#xff1b;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#xff1f;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#xff65;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#xff67;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#xff68;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#xff69;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#xff6a;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#xff6b;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#xff6c;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#xff6d;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#xff6e;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#xff6f;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#xff70;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#xffe0;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#xffe1;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+<glyph unicode="&#xffe5;" horiz-adv-x="1024" d="M0 0V1024H1024V0z"/>
+</font>
+</defs>
+</svg>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ApplicationCache.db b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ApplicationCache.db
new file mode 100644
index 000000000..e7cbb3d7d
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ApplicationCache.db
Binary files differ
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ApplicationCache.db-shm b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ApplicationCache.db-shm
new file mode 100644
index 000000000..f5a2be9ff
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ApplicationCache.db-shm
Binary files differ
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ApplicationCache.db-wal b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ApplicationCache.db-wal
new file mode 100644
index 000000000..dfd74404b
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ApplicationCache.db-wal
Binary files differ
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/BundleEditingDelegateProtocol.h b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/BundleEditingDelegateProtocol.h
new file mode 100644
index 000000000..528afa0e9
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/BundleEditingDelegateProtocol.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <WebKit/WKFoundation.h>
+
+#if WK_API_ENABLED
+
+#import <WebKit/WKWebProcessPlugInEditingDelegate.h>
+
+@protocol BundleEditingDelegateProtocol <NSObject>
+
+- (void)shouldInsertText:(NSString *)text replacingRange:(NSString *)rangeAsString givenAction:(WKEditorInsertAction)action;
+- (void)willWriteToPasteboard:(NSString *)rangeAsString;
+- (void)didWriteToPasteboard;
+
+@end
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/BundleRangeHandleProtocol.h b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/BundleRangeHandleProtocol.h
new file mode 100644
index 000000000..2edab241f
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/BundleRangeHandleProtocol.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <WebKit/WKFoundation.h>
+
+#if WK_API_ENABLED
+
+@protocol BundleRangeHandleProtocol <NSObject>
+- (void)textFromBodyRange:(NSString *)text;
+- (void)bodyInnerHTMLAfterDetectingData:(NSString *)text;
+@end
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.h b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.h
new file mode 100644
index 000000000..9d5b5d433
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+@protocol ContentFilteringProtocol <NSObject>
+- (void)checkIfPlatformFrameworksAreLoaded:(void (^)(BOOL parentalControlsLoaded, BOOL networkExtensionLoaded))completionHandler;
+@end
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.html
new file mode 100644
index 000000000..a48eabb65
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+<body>
+PASS
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/CookieMessage.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/CookieMessage.html
new file mode 100644
index 000000000..78553d43d
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/CookieMessage.html
@@ -0,0 +1,4 @@
+<script>
+document.cookie = "key=value";
+window.webkit.messageHandlers.testHandler.postMessage("COOKIE:" + document.cookie);
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DownloadRequestBlobURL.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DownloadRequestBlobURL.html
new file mode 100644
index 000000000..55ff0c066
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DownloadRequestBlobURL.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<body>
+<a id="href" href="simple.html">download</a>
+<script>
+ var element = document.getElementById("href");
+ var data = { x: 42, s: "hello, world" };
+ var json = JSON.stringify(data);
+ var blob = new Blob([json], {type: "octet/stream"});
+ var url = window.URL.createObjectURL(blob);
+
+ element.href = url;
+ element.click();
+</script>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DownloadRequestOriginalURL.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DownloadRequestOriginalURL.html
new file mode 100644
index 000000000..61447c2fd
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DownloadRequestOriginalURL.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<body>
+<a id="href" href="simple.html">download</a>
+<script>
+ var element = document.getElementById("href");
+ element.click();
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DownloadRequestOriginalURL2.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DownloadRequestOriginalURL2.html
new file mode 100644
index 000000000..01f6a7773
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DownloadRequestOriginalURL2.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+<body>
+<iframe src="DownloadRequestOriginalURLFrame.html"></iframe>
+</body>
+</html> \ No newline at end of file
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DownloadRequestOriginalURLFrame.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DownloadRequestOriginalURLFrame.html
new file mode 100644
index 000000000..61447c2fd
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DownloadRequestOriginalURLFrame.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<body>
+<a id="href" href="simple.html">download</a>
+<script>
+ var element = document.getElementById("href");
+ element.click();
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/FullscreenDelegate.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/FullscreenDelegate.html
new file mode 100644
index 000000000..9a9006203
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/FullscreenDelegate.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script>
+ function load() {
+ window.webkit.messageHandlers.fullscreenChangeHandler.postMessage('load');
+ }
+ document.addEventListener('webkitfullscreenchange', function(event) {
+ window.webkit.messageHandlers.fullscreenChangeHandler.postMessage('fullscreenchange');
+ });
+ document.addEventListener('mousedown', function(event) {
+ // Toggle fullscreen
+ var target = document.getElementById('target');
+ if (document.webkitFullscreenElement == target)
+ document.webkitExitFullscreen();
+ else
+ target.webkitRequestFullScreen();
+ });
+ </script>
+ <style>
+ #target {
+ background-color: red;
+ width: 150px;
+ height: 150px;
+ }
+ </style>
+</head>
+<body onload="load()">
+ <div id="target"></div>
+</body>
+</html> \ No newline at end of file
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/FullscreenLayoutConstraints.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/FullscreenLayoutConstraints.html
new file mode 100644
index 000000000..063d901da
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/FullscreenLayoutConstraints.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script>
+ function load() {
+ window.webkit.messageHandlers.fullscreenStateChangeHandler.postMessage('load');
+ }
+ document.addEventListener('webkitfullscreenchange', function(event) {
+ window.webkit.messageHandlers.fullscreenStateChangeHandler.postMessage('fullscreenchange');
+ });
+ document.addEventListener('mousedown', function(event) {
+ // Toggle fullscreen
+ var target = document.getElementById('target');
+ if (document.webkitFullscreenElement == target)
+ document.webkitExitFullscreen();
+ else
+ target.webkitRequestFullScreen();
+ });
+ </script>
+ <style>
+ #target {
+ background-color: red;
+ width: 150px;
+ height: 150px;
+ }
+ </style>
+</head>
+<body onload="load()">
+ <div id="target"></div>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/FullscreenTopContentInset.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/FullscreenTopContentInset.html
new file mode 100644
index 000000000..9a9006203
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/FullscreenTopContentInset.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script>
+ function load() {
+ window.webkit.messageHandlers.fullscreenChangeHandler.postMessage('load');
+ }
+ document.addEventListener('webkitfullscreenchange', function(event) {
+ window.webkit.messageHandlers.fullscreenChangeHandler.postMessage('fullscreenchange');
+ });
+ document.addEventListener('mousedown', function(event) {
+ // Toggle fullscreen
+ var target = document.getElementById('target');
+ if (document.webkitFullscreenElement == target)
+ document.webkitExitFullscreen();
+ else
+ target.webkitRequestFullScreen();
+ });
+ </script>
+ <style>
+ #target {
+ background-color: red;
+ width: 150px;
+ height: 150px;
+ }
+ </style>
+</head>
+<body onload="load()">
+ <div id="target"></div>
+</body>
+</html> \ No newline at end of file
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBDeleteRecovery.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBDeleteRecovery.html
new file mode 100644
index 000000000..c2bc464ab
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBDeleteRecovery.html
@@ -0,0 +1,14 @@
+<script>
+
+var request = window.indexedDB.deleteDatabase("IDBDeleteRecovery");
+
+request.onsuccess = function(e)
+{
+ window.webkit.messageHandlers.testHandler.postMessage('Deleted database');
+}
+request.onerror = function(e)
+{
+ // Unexpected error
+ window.webkit.messageHandlers.testHandler.postMessage('Error deleting database');
+}
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBDeleteRecovery.sqlite3 b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBDeleteRecovery.sqlite3
new file mode 100644
index 000000000..25ef255ee
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBDeleteRecovery.sqlite3
Binary files differ
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBDeleteRecovery.sqlite3-shm b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBDeleteRecovery.sqlite3-shm
new file mode 100644
index 000000000..285d37720
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBDeleteRecovery.sqlite3-shm
Binary files differ
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBDeleteRecovery.sqlite3-wal b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBDeleteRecovery.sqlite3-wal
new file mode 100644
index 000000000..51fe61926
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBDeleteRecovery.sqlite3-wal
Binary files differ
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBIndexUpgradeToV2.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBIndexUpgradeToV2.html
new file mode 100644
index 000000000..813bbd852
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBIndexUpgradeToV2.html
@@ -0,0 +1,21 @@
+<script>
+
+var databaseName = "index-upgrade-test";
+var openRequest = indexedDB.open(databaseName);
+var db;
+openRequest.onupgradeneeded = function(event) {
+ window.webkit.messageHandlers.testHandler.postMessage('Unexpected upgrade needed');
+}
+
+openRequest.onsuccess = function(event) {
+ var req = event.target.result.transaction('store').objectStore('store').index('index').get("indexkey!");
+
+ req.onsuccess = function (event) {
+ window.webkit.messageHandlers.testHandler.postMessage("Object expected to be a blob: " + event.target.result.test);
+ }
+ req.onerror = function (event) {
+ window.webkit.messageHandlers.testHandler.postMessage("Unexpected get error");
+ }
+}
+
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexUpgrade.blob b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexUpgrade.blob
new file mode 100644
index 000000000..6c51fb115
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexUpgrade.blob
@@ -0,0 +1 @@
+fun times all around! \ No newline at end of file
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexUpgrade.sqlite3 b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexUpgrade.sqlite3
new file mode 100644
index 000000000..bc3b63888
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexUpgrade.sqlite3
Binary files differ
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBDatabaseProcessKill-1.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBDatabaseProcessKill-1.html
new file mode 100644
index 000000000..ab4299bd8
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBDatabaseProcessKill-1.html
@@ -0,0 +1,33 @@
+<script>
+
+var database;
+
+for (var i = 0; i < 100; ++i) {
+ var request = window.indexedDB.deleteDatabase("IndexedDBDatabaseProcessKill");
+ request.onsuccess = function() {
+ window.webkit.messageHandlers.testHandler.postMessage('DeleteRequestDone');
+ }
+ request.onerror = function() {
+ window.webkit.messageHandlers.testHandler.postMessage('DeleteRequestError');
+ }
+
+ request = window.indexedDB.open("IndexedDBDatabaseProcessKill");
+ request.onsuccess = function() {
+ window.webkit.messageHandlers.testHandler.postMessage('OpenRequestDone');
+ }
+ request.onerror = function() {
+ window.webkit.messageHandlers.testHandler.postMessage('OpenRequestError');
+ }
+ request.onupgradeneeded = function(e) {
+ database = e.target.result;
+ database.onerror = function() {
+ notifyDatabaseErrorReceived = function() {
+ window.webkit.messageHandlers.testHandler.postMessage('DatabaseErrorReceived');
+ }
+ setTimeout("setTimeout(notifyDatabaseErrorReceived, 0)", 0);
+ }
+ window.webkit.messageHandlers.testHandler.postMessage('OpenRequestUpgradeNeeded');
+ }
+}
+
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBMultiProcess-1.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBMultiProcess-1.html
new file mode 100644
index 000000000..51223a1cb
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBMultiProcess-1.html
@@ -0,0 +1,46 @@
+<script>
+
+var request = window.indexedDB.deleteDatabase("IndexedDBMultiProcess");
+request.onsuccess = function(e)
+{
+ continueTest();
+}
+request.onerror = function(e)
+{
+ // Unexpected error
+ window.webkit.messageHandlers.testHandler.postMessage('Error deleting database');
+}
+
+function continueTest()
+{
+ var request = window.indexedDB.open("IndexedDBMultiProcess", 2);
+
+ request.onsuccess = function()
+ {
+ window.webkit.messageHandlers.testHandler.postMessage('Open success');
+ }
+
+ request.onerror = function()
+ {
+ // Unexpected error
+ window.webkit.messageHandlers.testHandler.postMessage('Unexpected error opening database');
+ }
+
+ request.onupgradeneeded = function(event)
+ {
+ window.webkit.messageHandlers.testHandler.postMessage('UpgradeNeeded');
+
+ var store = event.target.result.createObjectStore("TestObjectStore");
+
+ event.target.transaction.oncomplete = function() {
+ window.webkit.messageHandlers.testHandler.postMessage('Transaction complete');
+ }
+
+ event.target.transaction.onerror = function() {
+ window.webkit.messageHandlers.testHandler.postMessage('Transaction errored!');
+ }
+
+ store.put("bar", "foo");
+ }
+}
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBMultiProcess-2.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBMultiProcess-2.html
new file mode 100644
index 000000000..31035c993
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBMultiProcess-2.html
@@ -0,0 +1,92 @@
+<script>
+
+var request = window.indexedDB.open("IndexedDBMultiProcess", 2);
+
+request.onsuccess = function(event)
+{
+ var req = event.target.result.transaction("TestObjectStore").objectStore("TestObjectStore").get("foo");
+
+ req.onsuccess = function(event)
+ {
+ window.webkit.messageHandlers.testHandler.postMessage('Value of foo: ' + req.result);
+ continueTest1();
+ }
+
+ req.onerror = function(event)
+ {
+ // Unexpected error
+ window.webkit.messageHandlers.testHandler.postMessage('Unexpected error getting value');
+ }
+}
+
+request.onerror = function()
+{
+ // Unexpected error
+ window.webkit.messageHandlers.testHandler.postMessage('Unexpected error opening database');
+}
+
+request.onupgradeneeded = function(event)
+{
+ // Unexpected upgrade needed
+ window.webkit.messageHandlers.testHandler.postMessage('Unexpected UpgradeNeeded');
+}
+
+function continueTest1()
+{
+ var request = window.indexedDB.deleteDatabase("ProcessCloseIDBCleanup");
+ request.onsuccess = function(e)
+ {
+ continueTest2();
+ }
+ request.onerror = function(e)
+ {
+ // Unexpected error
+ window.webkit.messageHandlers.testHandler.postMessage('Error deleting ProcessCloseIDBCleanup database');
+ }
+}
+
+function startGetLoop()
+{
+ var request = window.indexedDB.open("ProcessCloseIDBCleanup");
+ request.onsuccess = function(e)
+ {
+ var req = e.target.result.transaction(["TestObjectStore"]).objectStore("TestObjectStore").get("foo");
+ req.onsuccess = startGetLoop;
+ req.onerror = function(e)
+ {
+ // Unexpected error
+ window.webkit.messageHandlers.testHandler.postMessage('Error with a get loop');
+ }
+ }
+
+ request.onerror = function(e)
+ {
+ // Unexpected error
+ window.webkit.messageHandlers.testHandler.postMessage('Error with a get loop');
+ }
+}
+
+function continueTest2()
+{
+ var request = window.indexedDB.open("ProcessCloseIDBCleanup");
+ request.onsuccess = function(e)
+ {
+ for (var i = 0; i < 75; ++i)
+ startGetLoop();
+
+ setTimeout("window.webkit.messageHandlers.testHandler.postMessage('Get loops started');", 0);
+ }
+
+ request.onerror = function(e)
+ {
+ // Unexpected error
+ window.webkit.messageHandlers.testHandler.postMessage('Error opening ProcessCloseIDBCleanup database');
+ }
+
+ request.onupgradeneeded = function(e)
+ {
+ e.target.result.createObjectStore("TestObjectStore").put("bar", "foo");
+ }
+}
+
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBMultiProcess-3.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBMultiProcess-3.html
new file mode 100644
index 000000000..872885b75
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBMultiProcess-3.html
@@ -0,0 +1,21 @@
+<script>
+
+var request = window.indexedDB.deleteDatabase("ProcessCloseIDBCleanup");
+
+request.onsuccess = function(event)
+{
+ window.webkit.messageHandlers.testHandler.postMessage('Deleted!');
+}
+
+request.onerror = function()
+{
+ // Unexpected error
+ window.webkit.messageHandlers.testHandler.postMessage('Unexpected error opening database');
+}
+
+request.onblocked = function(event)
+{
+ window.webkit.messageHandlers.testHandler.postMessage('Blocked!');
+}
+
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence-1.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence-1.html
new file mode 100644
index 000000000..62a1baf6f
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence-1.html
@@ -0,0 +1,35 @@
+<script>
+
+var request = window.indexedDB.deleteDatabase("IndexedDBPersistence");
+request.onsuccess = function(e)
+{
+ continueTest();
+}
+request.onerror = function(e)
+{
+ // Unexpected error
+ window.webkit.messageHandlers.testHandler.postMessage('Error');
+}
+
+function continueTest()
+{
+ var request = window.indexedDB.open("IndexedDBPersistence", 2);
+
+ request.onsuccess = function()
+ {
+ window.webkit.messageHandlers.testHandler.postMessage('Success');
+
+ }
+ request.onerror = function()
+ {
+ // Unexpected error
+ window.webkit.messageHandlers.testHandler.postMessage('Error');
+ }
+ request.onupgradeneeded = function(event)
+ {
+ window.webkit.messageHandlers.testHandler.postMessage('UpgradeNeeded');
+
+ event.target.result.createObjectStore("TestObjectStore");
+ }
+}
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence-2.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence-2.html
new file mode 100644
index 000000000..d8ab125f2
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence-2.html
@@ -0,0 +1,22 @@
+<script>
+
+var request = window.indexedDB.open("IndexedDBPersistence");
+
+request.onsuccess = function(event)
+{
+ window.webkit.messageHandlers.testHandler.postMessage(event.target.result.version + " " + event.target.result.objectStoreNames[0]);
+}
+
+request.onerror = function()
+{
+ // Unexpected error
+ window.webkit.messageHandlers.testHandler.postMessage('Unexpected Error');
+}
+
+request.onupgradeneeded = function()
+{
+ // Unexpected error
+ window.webkit.messageHandlers.testHandler.postMessage('Unexpected UpgradeNeeded');
+}
+
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LineBreaking.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LineBreaking.html
new file mode 100644
index 000000000..48da6e69a
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LineBreaking.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<style>
+@font-face {
+ font-family: "AllAhem";
+ src: url("AllAhem.svg") format("svg");
+}
+
+#test {
+ font: 20px "AllAhem";
+}
+</style>
+<script>
+function runTest(testContent, localeString, lineBreakValue) {
+ var container = document.getElementById("container");
+ var test = document.getElementById("test");
+
+ test.textContent = testContent;
+ container.lang = localeString;
+ container.style.webkitLineBreak = lineBreakValue;
+
+ var current = 0;
+ var breakpoints = [];
+ var clientRectsLength = 2;
+ for (var i = 1; clientRectsLength > 1; i += 5) {
+ container.style.width = "" + i + "px";
+ var width = test.getClientRects()[0].width;
+ if (current != width) {
+ current = width;
+ breakpoints.push(width / 20);
+ }
+ clientRectsLength = test.getClientRects().length;
+ }
+ return breakpoints;
+}
+</script>
+</head>
+<body>
+<div id="container" style="width: 99999999px;">
+ <span id="test">Hello World</span>
+</div>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageClear.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageClear.html
new file mode 100644
index 000000000..11bdd6c14
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageClear.html
@@ -0,0 +1,6 @@
+<script>
+
+window.localStorage.foo = "bar";
+window.webkit.messageHandlers.testHandler.postMessage('Go ahead and clear it');
+
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageNullEntries.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageNullEntries.html
new file mode 100644
index 000000000..9878f36ac
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageNullEntries.html
@@ -0,0 +1,6 @@
+<script>
+
+window.localStorage.key(0);
+window.webkit.messageHandlers.testHandler.postMessage('DONE');
+
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageNullEntries.localstorage b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageNullEntries.localstorage
new file mode 100644
index 000000000..0b41b25c7
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageNullEntries.localstorage
Binary files differ
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageNullEntries.localstorage-shm b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageNullEntries.localstorage-shm
new file mode 100644
index 000000000..fe9ac2845
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageNullEntries.localstorage-shm
Binary files differ
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageQuirkEnabled.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageQuirkEnabled.html
new file mode 100644
index 000000000..c53f1deb4
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageQuirkEnabled.html
@@ -0,0 +1,10 @@
+<script>
+
+try {
+ if (window.localStorage)
+ window.webkit.messageHandlers.testHandler.postMessage('PASS');
+} catch(e) {
+ window.webkit.messageHandlers.testHandler.postMessage('FAIL');
+}
+
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/RemoteObjectRegistry.h b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/RemoteObjectRegistry.h
new file mode 100644
index 000000000..3d2654b98
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/RemoteObjectRegistry.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <WebKit/WKFoundation.h>
+
+#if WK_API_ENABLED
+
+#import <WebKit/_WKRemoteObjectInterface.h>
+
+@protocol RemoteObjectProtocol <NSObject>
+
+- (void)sayHello:(NSString *)hello;
+- (void)sayHello:(NSString *)hello completionHandler:(void (^)(NSString *))completionHandler;
+- (void)selectionAndClickInformationForClickAtPoint:(NSValue *)pointValue completionHandler:(void (^)(NSDictionary *))completionHandler;
+- (void)takeRange:(NSRange)range completionHandler:(void (^)(NSUInteger location, NSUInteger length))completionHandler;
+- (void)takeSize:(CGSize)size completionHandler:(void (^)(CGFloat width, CGFloat height))completionHandler;
+- (void)doNotCallCompletionHandler:(void (^)())completionHandler;
+
+@end
+
+static inline _WKRemoteObjectInterface *remoteObjectInterface()
+{
+ _WKRemoteObjectInterface *interface = [_WKRemoteObjectInterface remoteObjectInterfaceWithProtocol:@protocol(RemoteObjectProtocol)];
+
+ [interface setClasses:[NSSet setWithObjects:[NSDictionary class], [NSString class], [NSURL class], nil] forSelector:@selector(selectionAndClickInformationForClickAtPoint:completionHandler:) argumentIndex:0 ofReply:YES];
+
+ return interface;
+}
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/StoreBlobToBeDeleted.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/StoreBlobToBeDeleted.html
new file mode 100644
index 000000000..bcaf972ad
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/StoreBlobToBeDeleted.html
@@ -0,0 +1,41 @@
+<script>
+
+var dbName = "StoreBlobToBeDeleted";
+var request = window.indexedDB.deleteDatabase(dbName);
+request.onsuccess = function(e)
+{
+ continueTest();
+}
+request.onerror = function(e)
+{
+ window.webkit.messageHandlers.testHandler.postMessage('Error deleting database');
+}
+
+var db;
+
+function continueTest(event)
+{
+ var request = window.indexedDB.open(dbName);
+
+ request.onupgradeneeded = function(e) {
+ db = e.target.result;
+ var objectStore = db.createObjectStore("TestStore");
+
+ const blobData = ["fun ", "times ", "all ", "around!"];
+ let blob = new Blob(blobData, { type: "text/plain" });
+
+ var addRequest = objectStore.add(blob, "BlobKey");
+ addRequest.onerror = function() {
+ window.webkit.messageHandlers.testHandler.postMessage('Error storing blob in database');
+ }
+ }
+
+ request.onsuccess = function() {
+ db.close();
+ window.webkit.messageHandlers.testHandler.postMessage('Success');
+ }
+ request.onerror = function() {
+ window.webkit.messageHandlers.testHandler.postMessage('Error storing blob in database');
+ }
+}
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/UserContentWorldProtocol.h b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/UserContentWorldProtocol.h
new file mode 100644
index 000000000..0b335792e
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/UserContentWorldProtocol.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <WebKit/WKFoundation.h>
+
+#if WK_API_ENABLED
+
+@protocol UserContentWorldProtocol <NSObject>
+
+- (void)didObserveNormalWorld;
+- (void)didObserveWorldWithName:(NSString *)name;
+
+@end
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WebProcessKillIDBCleanup-1.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WebProcessKillIDBCleanup-1.html
new file mode 100644
index 000000000..a9a121e49
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WebProcessKillIDBCleanup-1.html
@@ -0,0 +1,67 @@
+<script>
+
+var request = window.indexedDB.deleteDatabase("WebProcessKillIDBCleanup");
+request.onsuccess = function(e)
+{
+ continueTest();
+}
+request.onerror = function(e)
+{
+ // Unexpected error
+ window.webkit.messageHandlers.testHandler.postMessage('Error deleting database');
+}
+
+var database;
+
+function continueTest()
+{
+ var request = window.indexedDB.open("WebProcessKillIDBCleanup");
+
+ request.onsuccess = function()
+ {
+ window.webkit.messageHandlers.testHandler.postMessage('Open success');
+ setTimeout(continueTest2, 0);
+ }
+
+ request.onerror = function()
+ {
+ // Unexpected error
+ window.webkit.messageHandlers.testHandler.postMessage('Unexpected error opening database');
+ }
+
+ request.onupgradeneeded = function(event)
+ {
+ window.webkit.messageHandlers.testHandler.postMessage('UpgradeNeeded');
+
+ database = event.target.result;
+ var store = database.createObjectStore("TestObjectStore");
+
+ event.target.transaction.oncomplete = function() {
+ window.webkit.messageHandlers.testHandler.postMessage('Transaction complete');
+ }
+
+ event.target.transaction.onerror = function() {
+ window.webkit.messageHandlers.testHandler.postMessage('Transaction errored!');
+ }
+
+ store.put("bar", "foo");
+ }
+}
+
+function continueTest2()
+{
+ var objectStore = database.transaction("TestObjectStore", "readonly").objectStore("TestObjectStore");
+
+ // Start a get-loop to keep this transaction active.
+ var shouldMessageClose = true;
+ function success() {
+ objectStore.get("foo").onsuccess = success;
+ if (shouldMessageClose) {
+ window.webkit.messageHandlers.testHandler.postMessage('Infinite Transaction Started');
+ shouldMessageClose = false;
+ }
+ }
+
+ objectStore.get("foo").onsuccess = success;
+}
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WebProcessKillIDBCleanup-2.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WebProcessKillIDBCleanup-2.html
new file mode 100644
index 000000000..3b3047aca
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WebProcessKillIDBCleanup-2.html
@@ -0,0 +1,25 @@
+<script>
+
+var request = window.indexedDB.open("WebProcessKillIDBCleanup");
+
+request.onsuccess = function(event)
+{
+ window.webkit.messageHandlers.testHandler.postMessage('Second open success');
+
+ event.target.result.transaction("TestObjectStore", "readonly").objectStore("TestObjectStore").get("foo").onsuccess = function() {
+ window.webkit.messageHandlers.testHandler.postMessage('Second WebView Transaction Started');
+ }
+}
+
+request.onerror = function()
+{
+ // Unexpected error
+ window.webkit.messageHandlers.testHandler.postMessage('Unexpected error opening database');
+}
+
+request.onupgradeneeded = function(event)
+{
+ // Unexpected error
+ window.webkit.messageHandlers.testHandler.postMessage('Unexpected UpgradeNeeded opening database');
+}
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/autofocused-text-input.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/autofocused-text-input.html
new file mode 100644
index 000000000..c429b188a
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/autofocused-text-input.html
@@ -0,0 +1,3 @@
+<body>
+<input id="input" type="text" autofocus/>
+</body>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/autoplaying-video-with-audio.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/autoplaying-video-with-audio.html
new file mode 100644
index 000000000..53b456388
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/autoplaying-video-with-audio.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script>
+ var timeout;
+
+ function pauseVideo() {
+ document.getElementsByTagName("video")[0].pause();
+ }
+
+ function handlePaused() {
+ // Wait until the next runloop to allow media controls to update.
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("paused");
+ } catch(e) { }
+ }, 0);
+ }
+
+ function beganAutoplaying() {
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("autoplayed");
+ } catch(e) {
+ }
+ }, 0)
+ }
+
+ </script>
+</head>
+<body onmousedown=pauseVideo()>
+ <video autoplay controls onplaying=beganAutoplaying() src="video-with-audio.mp4" webkit-playsinline onpause=handlePaused()></video>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/blinking-div.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/blinking-div.html
new file mode 100644
index 000000000..e0f27aab7
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/blinking-div.html
@@ -0,0 +1,23 @@
+<html>
+ <script>
+window.onload = function () {
+ setInterval(blink, 0);
+}
+
+var a = 0;
+
+function blink() {
+ document.getElementById("blink").style.backgroundColor = a ? "blue" : "green";
+ a = !a;
+}
+ </script>
+ <style>
+#blink {
+ width: 200px; height: 200px;
+ display: inline-block;
+}
+ </style>
+ <body>
+ <div id="blink"></div>
+ </body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-click.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-click.html
new file mode 100644
index 000000000..560e6850a
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-click.html
@@ -0,0 +1,33 @@
+<head>
+ <style>
+ video {
+ width: 800px;
+ height: 600px;
+ }
+ </style>
+ <script type="text/javascript">
+ function changeSource() {
+ var video = document.querySelector("video");
+ video.src = "large-video-with-audio.mp4";
+ video.play();
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("changed");
+ } catch(e) {
+ }
+ });
+ }
+
+ function handlePlaying() {
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("autoplayed");
+ } catch(e) {
+ }
+ }, 0);
+ }
+ </script>
+</head>
+<body>
+ <video autoplay onplaying=handlePlaying() onmousedown=changeSource() src="large-video-with-audio.mp4"></video>
+</body>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-end.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-end.html
new file mode 100644
index 000000000..f84f7f7ac
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-end.html
@@ -0,0 +1,35 @@
+<head>
+ <style>
+ video {
+ width: 800px;
+ height: 600px;
+ }
+ </style>
+ <script type="text/javascript">
+ var hasBegunPlayingBefore = false;
+
+ function changeSource() {
+ var video = document.querySelector("video");
+ video.src = "large-video-with-audio.mp4";
+ video.play();
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("changed");
+ } catch(e) {
+ }
+ });
+ }
+
+ function handlePlaying() {
+ if (hasBegunPlayingBefore)
+ return;
+
+ hasBegunPlayingBefore = true;
+ var video = document.querySelector("video");
+ video.currentTime = video.duration - 0.5;
+ }
+ </script>
+</head>
+<body>
+ <video autoplay onplaying=handlePlaying() src="large-video-with-audio.mp4" onended=changeSource()></video>
+</body>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/duplicate-completion-handler-calls.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/duplicate-completion-handler-calls.html
new file mode 100644
index 000000000..1e7492bed
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/duplicate-completion-handler-calls.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<form action="about:blank"></form>
+<script>
+ alert("alert");
+ confirm("confirm");
+ prompt("prompt");
+ openDatabase("testDatabase", "1", "test database", 1024);
+ document.forms[0].submit();
+</script>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/editable-body.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/editable-body.html
new file mode 100644
index 000000000..0c7baced7
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/editable-body.html
@@ -0,0 +1,7 @@
+<html>
+ <body contenteditable>Lorem Ipsum Et Cetera
+ <script>
+ document.body.focus();
+ </script>
+ </body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/enormous-video-with-sound.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/enormous-video-with-sound.html
new file mode 100644
index 000000000..0934f5ed8
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/enormous-video-with-sound.html
@@ -0,0 +1,15 @@
+<html>
+<head>
+<script>
+ function handlePlaying() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("playing");
+ } catch(e) {
+ }
+ }
+</script>
+</head>
+<body>
+ <video autoplay src="large-video-with-audio.mp4" width=65536 height=65536 onplaying=handlePlaying()></video>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/focus-inputs.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/focus-inputs.html
new file mode 100644
index 000000000..9f292c79d
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/focus-inputs.html
@@ -0,0 +1,15 @@
+<html>
+<head>
+<script>
+function focusPasswordField() {
+ var password = document.getElementById("password");
+ password.focus();
+}
+</script>
+</head>
+
+<body>
+<input type="text" autofocus/>
+<input id="password" type="password" />
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/full-size-autoplaying-video-with-audio.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/full-size-autoplaying-video-with-audio.html
new file mode 100644
index 000000000..48301e630
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/full-size-autoplaying-video-with-audio.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <style>
+ video {
+ width: 100vw;
+ height: 100vh;
+ }
+ </style>
+ <script>
+ function finishTest() {
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("playing");
+ } catch(e) { }
+ }, 0);
+ }
+ </script>
+</head>
+<body>
+ <video autoplay src="video-with-audio.mp4" webkit-playsinline onplaying=finishTest()></video>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/input-field-in-scrollable-document.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/input-field-in-scrollable-document.html
new file mode 100644
index 000000000..6eedf375c
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/input-field-in-scrollable-document.html
@@ -0,0 +1,36 @@
+<html>
+
+<head>
+ <style>
+ body {
+ margin: 0;
+ }
+
+ input {
+ width: 100%;
+ height: 400px;
+ margin-bottom: 5000px;
+ }
+ </style>
+ <script type="text/javascript">
+ function loaded() {
+ var input = document.querySelector("input");
+ input.setSelectionRange(0, 0);
+ input.focus();
+ }
+
+ function focused() {
+ setTimeout(() => window.webkit.messageHandlers.testHandler.postMessage("focused"), 0);
+ }
+
+ function input() {
+ setTimeout(() => window.webkit.messageHandlers.testHandler.postMessage("input"), 0);
+ }
+ </script>
+</head>
+
+<body onload=loaded()>
+ <input onfocus=focused() oninput=input()></input>
+</body>
+
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-input-field-focus-onload.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-input-field-focus-onload.html
new file mode 100644
index 000000000..0671a12f5
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-input-field-focus-onload.html
@@ -0,0 +1,38 @@
+<html>
+
+<head>
+ <style>
+ body {
+ margin: 0;
+ }
+
+ input {
+ width: 100vw;
+ height: 100vh;
+ font-size: 50vh;
+ }
+ </style>
+ <script type="text/javascript">
+ function loaded() {
+ document.querySelector("input").focus();
+ }
+
+ function focused() {
+ setTimeout(() => window.webkit.messageHandlers.testHandler.postMessage("focused"), 0);
+ }
+
+ function input() {
+ setTimeout(() => window.webkit.messageHandlers.testHandler.postMessage("input"), 0);
+ }
+
+ function mousedown() {
+ setTimeout(() => window.webkit.messageHandlers.testHandler.postMessage("mousedown"), 0);
+ }
+ </script>
+</head>
+
+<body onload=loaded()>
+ <input onfocus=focused() oninput=input() onmousedown=mousedown()></input>
+</body>
+
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-hides-controls-after-seek-to-end.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-hides-controls-after-seek-to-end.html
new file mode 100644
index 000000000..0102e9629
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-hides-controls-after-seek-to-end.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script>
+
+ function handleEnded() {
+ // The media controls should be updated on the next runloop.
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("ended");
+ } catch(e) { }
+ }, 0);
+ }
+
+ function seekToEnd() {
+ var video = document.getElementsByTagName("video")[0];
+ video.currentTime = video.duration;
+ }
+
+ function beginTest() {
+ try {
+ window.webkit.messageHandlers.onloadHandler.postMessage("loaded");
+ } catch(e) { }
+ }
+
+ function beganAutoplaying() {
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("autoplayed");
+ } catch(e) {
+ }
+ }, 0)
+ }
+
+ </script>
+</head>
+<body onmousedown=seekToEnd() onload=beginTest()>
+ <video autoplay onplaying=beganAutoplaying() onended=handleEnded() src="large-video-with-audio.mp4" webkit-playsinline style="width: 800px; height: 600px;"></video>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-mutes-onplaying.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-mutes-onplaying.html
new file mode 100644
index 000000000..38fb32552
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-mutes-onplaying.html
@@ -0,0 +1,16 @@
+<html>
+<head>
+<script>
+ function handlePlaying() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("playing");
+ } catch(e) {
+ }
+ document.querySelector("video").muted = true;
+ }
+</script>
+</head>
+<body>
+ <video autoplay src="large-video-with-audio.mp4" width=640 height=480 onplaying=handlePlaying()></video>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-offscreen.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-offscreen.html
new file mode 100644
index 000000000..39cf476ab
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-offscreen.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <style>
+ video {
+ width: 480px;
+ height: 320px;
+ position: absolute;
+ }
+ .offscreen {
+ top: -320px;
+ }
+ </style>
+ <script>
+ function moveVideoOffscreen() {
+ document.querySelector("video").classList.add("offscreen");
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("moved");
+ } catch(e) {
+ }
+ }, 0);
+ }
+ </script>
+</head>
+<body>
+ <video autoplay onplaying=moveVideoOffscreen()><source src="large-video-with-audio.mp4"></video>
+</body>
+<html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-playing-scroll-away.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-playing-scroll-away.html
new file mode 100644
index 000000000..0b7e09a32
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-playing-scroll-away.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <style>
+ video {
+ width: 480px;
+ height: 320px;
+ }
+ div {
+ margin-top: 5000px;
+ }
+ </style>
+ <script>
+ function scrollVideoOutOfView() {
+ document.querySelector("div").scrollIntoView();
+ setTimeout(function() {
+ window.webkit.messageHandlers.testHandler.postMessage("scrolled");
+ }, 0);
+ }
+
+ function beganAutoplaying() {
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("autoplayed");
+ } catch(e) {
+ }
+ }, 0)
+ }
+ </script>
+ </head>
+ <body>
+ <video autoplay onplaying=beganAutoplaying() loop id="first" src="large-video-with-audio.mp4"></video>
+ <br>
+ <div>hello world!</div>
+ </body>
+<html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-after-ending.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-after-ending.html
new file mode 100644
index 000000000..0386540a3
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-after-ending.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script>
+ function seekToBeginningAndFinishTest() {
+ document.querySelector("#test-video").currentTime = 0;
+ // The media controls should be updated on the next runloop.
+ setTimeout(function() {
+ window.webkit.messageHandlers.testHandler.postMessage("ended");
+ }, 0);
+ }
+
+ function seekToEnd() {
+ document.querySelector("#test-video").currentTime = document.querySelector("#test-video").duration - 0.1;
+ }
+ </script>
+</head>
+<body>
+ <video id="test-video" autoplay onended=seekToBeginningAndFinishTest() onplaying=seekToEnd() style="width: 800px; height: 600px;" src="large-video-with-audio.mp4"></video>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-to-beginning-and-play-after-ending.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-to-beginning-and-play-after-ending.html
new file mode 100644
index 000000000..ada9a2d12
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-to-beginning-and-play-after-ending.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script>
+ function seekToBeginningAndFinishTest() {
+ var video = document.querySelector("#test-video");
+ video.currentTime = 0;
+ video.play();
+ // The media controls should be updated on the next runloop.
+ setTimeout(function() {
+ window.webkit.messageHandlers.testHandler.postMessage("replaying");
+ }, 0);
+ }
+
+ function seekToEnd() {
+ document.querySelector("#test-video").currentTime = document.querySelector("#test-video").duration - 0.1;
+ }
+ </script>
+</head>
+<body>
+ <video id="test-video" autoplay onended=seekToBeginningAndFinishTest() onplaying=seekToEnd() style="width: 800px; height: 600px;" src="large-video-with-audio.mp4"></video>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-test-now-playing.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-test-now-playing.html
new file mode 100644
index 000000000..657dbd739
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-test-now-playing.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <style>
+ video {
+ width: 480px;
+ height: 320px;
+ position: absolute;
+ }
+
+ body {
+ margin: 0;
+ }
+ </style>
+ <script>
+ function playing() {
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("playing");
+ } catch(e) {
+ }
+ }, 0);
+ }
+
+ function mousedown() {
+ document.querySelector("video").muted = true;
+ }
+ </script>
+</head>
+<body>
+ <video autoplay title="foo" onmousedown=mousedown() onplaying=playing()><source src="large-video-with-audio.mp4"></video>
+</body>
+<html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-with-audio.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-with-audio.html
new file mode 100644
index 000000000..8c982ae5c
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-with-audio.html
@@ -0,0 +1,12 @@
+<html>
+<head>
+<script>
+ function play() {
+ document.getElementsByTagName('video')[0].play();
+ }
+</script>
+</head>
+<body onload="play()">
+ <video src="large-video-with-audio.mp4" width=640 height=480></video>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-with-audio.mp4 b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-with-audio.mp4
new file mode 100644
index 000000000..4b4bcff48
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-with-audio.mp4
Binary files differ
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-without-audio.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-without-audio.html
new file mode 100644
index 000000000..27838eb25
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-without-audio.html
@@ -0,0 +1,29 @@
+<html>
+<head>
+<script>
+ var timeout;
+
+ function go() {
+ var video = document.getElementsByTagName('video')[0];
+ video.play().then(playing).catch(notPlaying);
+ }
+
+ function playing() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage('playing');
+ } catch(e) {
+ window.location = 'callback:playing';
+ }
+ }
+
+ function notPlaying() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage('not playing');
+ } catch(e) { }
+ }
+</script>
+</head>
+<body onload="go()">
+ <video id="test-video" src="video-without-audio.mp4" controls width=640 height=480></video>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-click-to-pause.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-click-to-pause.html
new file mode 100644
index 000000000..22dbebf12
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-click-to-pause.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <style>
+ video {
+ width: 480px;
+ height: 320px;
+ }
+ </style>
+ <script>
+ var isFirstClick = true;
+ function handleMouseDown() {
+ document.querySelector(isFirstClick ? "#first" : "#second").pause();
+ isFirstClick = false;
+ }
+
+ function handleFirstPause() {
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("paused");
+ } catch(e) { }
+ }, 0);
+ }
+
+ function handleSecondPause() {
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("paused");
+ } catch(e) { }
+ }, 0);
+ }
+
+ function beganAutoplaying() {
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("autoplayed");
+ } catch(e) {
+ }
+ }, 0)
+ }
+ </script>
+ </head>
+ <body onmousedown=handleMouseDown()>
+ <video autoplay onplaying=beganAutoplaying() loop id="first" src="large-video-with-audio.mp4" onpause=handleFirstPause()></video>
+ <video autoplay onplaying=beganAutoplaying() loop id="second" src="large-video-with-audio.mp4" onpause=handleSecondPause()></video>
+ </body>
+<html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-scroll-to-video.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-scroll-to-video.html
new file mode 100644
index 000000000..d1c1aaea9
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-scroll-to-video.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <style>
+ video {
+ width: 480px;
+ height: 320px;
+ }
+ #second {
+ margin-top: 5000px;
+ }
+ </style>
+ <script>
+ function scrollToSecondView() {
+ document.querySelector("#second").scrollIntoView();
+ setTimeout(function() {
+ window.webkit.messageHandlers.testHandler.postMessage("scrolled");
+ }, 0);
+ }
+ function beganAutoplaying() {
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("autoplayed");
+ } catch(e) {
+ }
+ }, 0)
+ }
+ </script>
+ </head>
+ <body>
+ <video autoplay onplaying=beganAutoplaying() loop id="first" src="large-video-with-audio.mp4"></video>
+ <br>
+ <video autoplay onplaying=beganAutoplaying() loop id="second" src="large-video-with-audio.mp4"></video>
+ </body>
+<html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-paused-video-hides-controls.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-paused-video-hides-controls.html
new file mode 100644
index 000000000..31f86cbc9
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-paused-video-hides-controls.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<style>
+ video {
+ width: 480px;
+ height: 320px;
+ }
+ #bar {
+ margin-top: 5000px;
+ }
+</style>
+<script>
+ function pauseFirstVideoAndScrollToSecondVideo() {
+ document.querySelector("#bar").scrollIntoView();
+ document.querySelector("#foo").pause();
+ }
+ function handlePaused() {
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("paused");
+ } catch(e) { }
+ }, 0);
+ }
+ function beganAutoplaying() {
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("autoplayed");
+ } catch(e) {
+ }
+ }, 0)
+ }
+</script>
+<body>
+ <video autoplay onplaying=beganAutoplaying() loop id="foo" onpause=handlePaused()><source src="large-video-with-audio.mp4"></video>
+ <br>
+ <video id="bar"><source src="large-video-with-audio.mp4"></video>
+</body>
+<html> \ No newline at end of file
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-muted-video-hides-controls.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-muted-video-hides-controls.html
new file mode 100644
index 000000000..34486e2e3
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-muted-video-hides-controls.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<style>
+ video {
+ width: 480px;
+ height: 320px;
+ }
+ #bar {
+ margin-top: 5000px;
+ }
+</style>
+<script>
+ function muteFirstVideoAndScrollToSecondVideo() {
+ document.querySelector("#foo").muted = true;
+ document.querySelector("#bar").scrollIntoView();
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("playing");
+ } catch(e) { }
+ }, 0);
+ }
+ function beganAutoplaying() {
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("autoplayed");
+ } catch(e) {
+ }
+ }, 0)
+ }
+</script>
+<body>
+ <video autoplay onplaying=beganAutoplaying() loop id="foo"><source src="large-video-with-audio.mp4"></video>
+ <br>
+ <video id="bar"><source src="large-video-with-audio.mp4"></video>
+</body>
+<html> \ No newline at end of file
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-video-keeps-controls.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-video-keeps-controls.html
new file mode 100644
index 000000000..b6fcf7a05
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-video-keeps-controls.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+<style>
+ video {
+ width: 480px;
+ height: 320px;
+ }
+ #bar {
+ margin-top: 5000px;
+ }
+</style>
+<script>
+ function scrollToSecondVideo() {
+ document.querySelector("#bar").scrollIntoView();
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("scrolled");
+ } catch(e) { }
+ }, 0);
+ }
+ function beganAutoplaying() {
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("autoplayed");
+ } catch(e) {
+ }
+ }, 0)
+ }
+</script>
+<body>
+ <video autoplay onplaying=beganAutoplaying() loop id="foo"><source src="large-video-with-audio.mp4"></video>
+ <br>
+ <video id="bar"><source src="large-video-with-audio.mp4"></video>
+</body>
+<html> \ No newline at end of file
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-with-audio-autoplay.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-with-audio-autoplay.html
new file mode 100644
index 000000000..3e170ced5
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-with-audio-autoplay.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<script>
+ function beganAutoplaying() {
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("autoplayed");
+ } catch(e) {
+ }
+ }, 0)
+ }
+</script>
+<body>
+ <video id="foo" style="width: 480px; height: 320px;"><source src="large-video-with-audio.mp4"></video>
+ <video autoplay onplaying=beganAutoplaying() id="bar" style="width: 480px; height: 320px;"><source src="large-video-with-audio.mp4"></video>
+ <video id="baz" style="width: 480px; height: 320px;"><source src="large-video-with-audio.mp4"></video>
+</body>
+<html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-with-audio.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-with-audio.html
new file mode 100644
index 000000000..0fdde2f2a
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-with-audio.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<script>
+ function handleLoaded() {
+ // The media controls should be updated on the next runloop.
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.onloadHandler.postMessage("loaded");
+ } catch(e) { }
+ }, 0);
+ }
+</script>
+<body onload=handleLoaded()>
+ <video id="foo" style="width: 480px; height: 320px;"><source src="large-video-with-audio.mp4"></video>
+ <video id="bar" style="width: 480px; height: 320px;"><source src="large-video-with-audio.mp4"></video>
+ <video id="baz" style="width: 480px; height: 320px;"><source src="large-video-with-audio.mp4"></video>
+</body>
+<html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/open-multiple-external-url.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/open-multiple-external-url.html
new file mode 100644
index 000000000..9c3df85e2
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/open-multiple-external-url.html
@@ -0,0 +1,66 @@
+<style>
+ iframe { width: 0; height: 0; visibility: hidden; }
+</style>
+
+<body>
+
+<script>
+window.addEventListener("click", function() {
+ let hash = window.location.hash;
+ switch (hash) {
+ case "#normalLoop":
+ normalLoop();
+ break;
+ case "#loopAfterTimer":
+ loopAfterTimer();
+ break;
+ case "#loopAfterPostMessage":
+ loopAfterPostMessage();
+ break;
+ case "#loopAfterLongTimer":
+ loopAfterLongTimer();
+ break;
+ }
+}, false);
+
+function normalLoop() {
+ for (var i = 0; i < 3; ++i) {
+ var iframe = document.createElement('iframe');
+ document.body.appendChild(iframe);
+ iframe.contentWindow.location = "mailto:someone@example.com?Subject=Hello%20again";
+ }
+}
+
+function loopAfterTimer() {
+ setTimeout(function() {
+ for (var i = 0; i < 3; ++i) {
+ var iframe = document.createElement('iframe');
+ document.body.appendChild(iframe);
+ iframe.contentWindow.location = "mailto:someone@example.com?Subject=Hello%20again";
+ }
+ }, 500);
+}
+
+function loopAfterPostMessage() {
+ window.onmessage = function() {
+ for (var i = 0; i < 3; ++i) {
+ var iframe = document.createElement('iframe');
+ document.body.appendChild(iframe);
+ iframe.contentWindow.location = "mailto:someone@example.com?Subject=Hello%20again";
+ }
+ }
+ window.postMessage("foo", "*");
+}
+
+function loopAfterLongTimer() {
+ setTimeout(function() {
+ for (var i = 0; i < 3; ++i) {
+ var iframe = document.createElement('iframe');
+ document.body.appendChild(iframe);
+ iframe.contentWindow.location = "mailto:someone@example.com?Subject=Hello%20again";
+ }
+ }, 2000);
+}
+
+</script>
+</body>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/page-with-csp-iframe.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/page-with-csp-iframe.html
new file mode 100644
index 000000000..4c2a9dbb6
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/page-with-csp-iframe.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Security-Policy" content="script-src 'none'">
+</head>
+<body>
+<script nonce="a">
+window.webkit.messageHandlers.testHandler.postMessage("Subframe: A");
+</script>
+<script nonce="b">
+window.webkit.messageHandlers.testHandler.postMessage("Subframe: B");
+</script>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/page-with-csp.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/page-with-csp.html
new file mode 100644
index 000000000..3fb76fe84
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/page-with-csp.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Security-Policy" content="script-src 'none'">
+</head>
+<body>
+<script nonce="a">
+window.webkit.messageHandlers.testHandler.postMessage("MainFrame: A");
+</script>
+<script nonce="b">
+window.webkit.messageHandlers.testHandler.postMessage("MainFrame: B");
+</script>
+<iframe id="iframe" src="page-with-csp-iframe.html"></iframe>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/page-without-csp-iframe.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/page-without-csp-iframe.html
new file mode 100644
index 000000000..84a23d5f0
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/page-without-csp-iframe.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script nonce="a">
+window.webkit.messageHandlers.testHandler.postMessage("Subframe: A");
+</script>
+<script nonce="b">
+window.webkit.messageHandlers.testHandler.postMessage("Subframe: B");
+</script>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/page-without-csp.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/page-without-csp.html
new file mode 100644
index 000000000..74cecafe8
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/page-without-csp.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script nonce="a">
+window.webkit.messageHandlers.testHandler.postMessage("MainFrame: A");
+</script>
+<script nonce="b">
+window.webkit.messageHandlers.testHandler.postMessage("MainFrame: B");
+</script>
+<iframe id="iframe" src="page-without-csp-iframe.html"></iframe>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/play-audio-on-click.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/play-audio-on-click.html
new file mode 100644
index 000000000..d7768a64e
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/play-audio-on-click.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <style>
+ div {
+ width: 400px;
+ height: 400px;
+ background-color: red;
+ }
+ body {
+ margin: 0;
+ }
+ </style>
+ <script>
+ var audio;
+
+ function playFirstTrack()
+ {
+ audio = document.createElement("audio");
+ audio.src = "video-with-audio.mp4";
+ audio.id = "first";
+ audio.onplaying = audioPlayingHandler("first");
+ audio.onended = playSecondTrack;
+ audio.play();
+ }
+
+ function playSecondTrack()
+ {
+ audio = document.createElement("audio");
+ audio.src = "large-video-with-audio.mp4";
+ audio.id = "second";
+ audio.onplaying = audioPlayingHandler("second");
+ audio.play();
+ }
+
+ function seekToEnd()
+ {
+ audio.currentTime = audio.duration - 0.5;
+ }
+
+ function audioPlayingHandler(id)
+ {
+ return function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("playing-" + id);
+ } catch(e) {}
+ }
+ }
+ </script>
+</head>
+<body>
+ <div onmousedown=playFirstTrack()>Click me to start playing!</div>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/skinny-autoplaying-video-with-audio.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/skinny-autoplaying-video-with-audio.html
new file mode 100644
index 000000000..26ef53dc2
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/skinny-autoplaying-video-with-audio.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <style>
+ video {
+ width: 300vw;
+ height: 40vh;
+ }
+ </style>
+ <script>
+ function finishTest() {
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("playing");
+ } catch(e) { }
+ }, 0);
+ }
+ </script>
+</head>
+<body>
+ <video autoplay src="video-with-audio.mp4" webkit-playsinline onplaying=finishTest()></video>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/text-and-password-inputs.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/text-and-password-inputs.html
new file mode 100644
index 000000000..e7e11db24
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/text-and-password-inputs.html
@@ -0,0 +1,39 @@
+<html>
+<head>
+ <script>
+ function loaded() {
+ setTimeout(() => window.webkit.messageHandlers.testHandler.postMessage("loaded"), 0);
+ }
+
+ function textFocused() {
+ setTimeout(() => window.webkit.messageHandlers.testHandler.postMessage("text-focused"), 0);
+ }
+
+ function textInput() {
+ setTimeout(() => window.webkit.messageHandlers.testHandler.postMessage("text-input"), 0);
+ }
+
+ function passwordFocused() {
+ setTimeout(() => window.webkit.messageHandlers.testHandler.postMessage("password-focused"), 0);
+ }
+
+ function passwordInput() {
+ setTimeout(() => window.webkit.messageHandlers.testHandler.postMessage("password-input"), 0);
+ }
+ </script>
+
+ <style>
+ input {
+ width: 100%;
+ height: 50%;
+ font-size: 100px;
+ }
+ body { margin: 0; }
+ </style>
+</head>
+
+<body onload=loaded() onmousedown=mousedown(event)>
+ <input id="text" type="text" onfocus=textFocused() oninput=textInput()></input>
+ <input id="password" type="password" onfocus=passwordFocused() oninput=passwordInput()></input>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/wide-autoplaying-video-with-audio.html b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/wide-autoplaying-video-with-audio.html
new file mode 100644
index 000000000..ea2cb5063
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/wide-autoplaying-video-with-audio.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <style>
+ video {
+ width: 800px;
+ height: 400px;
+ }
+ </style>
+ <script>
+ function finishTest() {
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("playing");
+ } catch(e) { }
+ }, 0);
+ }
+ </script>
+</head>
+<body>
+ <video autoplay src="video-with-audio.mp4" webkit-playsinline onplaying=finishTest()></video>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/AutocleanupsTest.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/AutocleanupsTest.cpp
new file mode 100644
index 000000000..a20cbfd73
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/AutocleanupsTest.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2013 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include "WebProcessTest.h"
+#include <webkit2/webkit-web-extension.h>
+
+#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
+
+class AutocleanupsTest : public WebProcessTest {
+public:
+ static std::unique_ptr<WebProcessTest> create() { return std::unique_ptr<WebProcessTest>(new AutocleanupsTest()); }
+
+private:
+ bool testWebProcessAutocleanups(WebKitWebPage* webPage)
+ {
+ // Transfer none
+ g_autoptr(WebKitWebPage) page = WEBKIT_WEB_PAGE(g_object_ref(G_OBJECT(webPage)));
+ g_assert(WEBKIT_IS_WEB_PAGE(page));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(page));
+
+ // Transfer none
+ g_autoptr(WebKitDOMDocument) document = WEBKIT_DOM_DOCUMENT(g_object_ref(G_OBJECT(webkit_web_page_get_dom_document(page))));
+ g_assert(WEBKIT_DOM_IS_DOCUMENT(document));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(document));
+
+ // Transfer full
+ g_autoptr(WebKitDOMDOMWindow) window = webkit_dom_document_get_default_view(document);
+ g_assert(WEBKIT_DOM_IS_DOM_WINDOW(window));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(window));
+
+ // Transfer full
+ g_autoptr(WebKitDOMRange) range = webkit_dom_document_create_range(document);
+ g_assert(WEBKIT_DOM_IS_RANGE(range));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(range));
+
+ return true;
+ }
+
+ bool runTest(const char* testName, WebKitWebPage* page) override
+ {
+ if (!strcmp(testName, "web-process-autocleanups"))
+ return testWebProcessAutocleanups(page);
+
+ g_assert_not_reached();
+ return false;
+ }
+};
+
+static void __attribute__((constructor)) registerTests()
+{
+ REGISTER_TEST(AutocleanupsTest, "Autocleanups/web-process-autocleanups");
+}
+
+#endif // G_DEFINE_AUTOPTR_CLEANUP_FUNC
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/CMakeLists.txt b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/CMakeLists.txt
new file mode 100644
index 000000000..64640f51c
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/CMakeLists.txt
@@ -0,0 +1,135 @@
+set(TEST_LIBRARY_DIR ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/WebKit2GtkAPITests)
+set(TEST_BINARY_DIR ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/TestWebKitAPI/WebKit2Gtk)
+set(TEST_RESOURCES_DIR ${TEST_BINARY_DIR}/resources)
+file(MAKE_DIRECTORY ${TEST_RESOURCES_DIR})
+
+add_definitions(
+ -DWEBKIT_TEST_PLUGIN_DIR="${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/plugins"
+ -DWEBKIT_EXEC_PATH="${CMAKE_RUNTIME_OUTPUT_DIRECTORY}"
+ -DWEBKIT_SRC_DIR="${CMAKE_SOURCE_DIR}"
+ -DWEBKIT_TEST_WEB_EXTENSIONS_DIR="${TEST_LIBRARY_DIR}"
+ -DWEBKIT_INJECTED_BUNDLE_PATH="${CMAKE_LIBRARY_OUTPUT_DIRECTORY}"
+)
+
+include_directories(
+ ${CMAKE_SOURCE_DIR}/Source
+ ${CMAKE_SOURCE_DIR}/Source/WTF
+ ${DERIVED_SOURCES_WEBKIT2GTK_DIR}
+ ${FORWARDING_HEADERS_DIR}
+ ${FORWARDING_HEADERS_WEBKIT2GTK_DIR}
+ ${FORWARDING_HEADERS_WEBKIT2GTK_EXTENSION_DIR}
+ ${TOOLS_DIR}/TestWebKitAPI/gtk/WebKit2Gtk
+)
+
+include_directories(SYSTEM
+ ${ATSPI_INCLUDE_DIRS}
+ ${GLIB_INCLUDE_DIRS}
+ ${GSTREAMER_INCLUDE_DIRS}
+ ${GTK3_INCLUDE_DIRS}
+ ${GTK_UNIX_PRINT_INCLUDE_DIRS}
+ ${LIBSOUP_INCLUDE_DIRS}
+)
+
+add_library(WebKit2APITestCore STATIC
+ ${TOOLS_DIR}/TestWebKitAPI/gtk/WebKit2Gtk/LoadTrackingTest.cpp
+ ${TOOLS_DIR}/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestBus.cpp
+ ${TOOLS_DIR}/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestServer.cpp
+ ${TOOLS_DIR}/TestWebKitAPI/gtk/WebKit2Gtk/TestMain.cpp
+ ${TOOLS_DIR}/TestWebKitAPI/gtk/WebKit2Gtk/WebViewTest.cpp
+)
+target_link_libraries(WebKit2APITestCore WebKit2)
+
+add_custom_command(
+ OUTPUT ${TEST_RESOURCES_DIR}/webkit2gtk-tests-resources.gresource
+ DEPENDS resources/webkit2gtk-tests.gresource.xml
+ resources/link-title.js
+ COMMAND glib-compile-resources
+ --target=${TEST_RESOURCES_DIR}/webkit2gtk-tests-resources.gresource
+ --sourcedir=${CMAKE_SOURCE_DIR}
+ ${CMAKE_CURRENT_LIST_DIR}/resources/webkit2gtk-tests.gresource.xml
+)
+
+add_custom_target(test-gresource-bundle
+ DEPENDS ${TEST_RESOURCES_DIR}/webkit2gtk-tests-resources.gresource
+)
+
+macro(ADD_WK2_TEST_WEB_EXTENSION extension_name)
+ add_library(${extension_name} MODULE ${ARGN})
+ add_dependencies(${extension_name} WebKit2)
+ set_property(
+ TARGET ${extension_name}
+ APPEND
+ PROPERTY COMPILE_DEFINITIONS WEBKIT2_COMPILATION
+ )
+ set_target_properties(${extension_name} PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY ${TEST_LIBRARY_DIR}
+ )
+ target_link_libraries(${extension_name}
+ JavaScriptCore
+ WebKit2
+ ${GLIB_LIBRARIES}
+ )
+endmacro()
+
+macro(ADD_WK2_TEST test_name)
+ add_executable(${test_name} ${ARGN})
+ add_dependencies(${test_name}
+ test-gresource-bundle
+ WebExtensionTest
+ )
+ target_link_libraries(${test_name}
+ JavaScriptCore
+ WebKit2
+ WebKit2APITestCore
+ ${ATSPI_LIBRARIES}
+ ${GLIB_LIBRARIES}
+ ${GTK3_LIBRARIES}
+ ${GTK_UNIX_PRINT_LIBRARIES}
+ ${LIBSOUP_LIBRARIES}
+ )
+ set_target_properties(${test_name} PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY ${TEST_BINARY_DIR}
+ )
+endmacro()
+
+ADD_WK2_TEST_WEB_EXTENSION(WebExtensionTest WebExtensionTest.cpp)
+ADD_WK2_TEST_WEB_EXTENSION(WebProcessTest AutocleanupsTest.cpp DOMNodeTest.cpp DOMNodeFilterTest.cpp DOMXPathNSResolverTest.cpp FrameTest.cpp WebProcessTest.cpp EditorTest.cpp)
+
+ADD_WK2_TEST(InspectorTestServer InspectorTestServer.cpp)
+ADD_WK2_TEST(TestAuthentication TestAuthentication.cpp)
+ADD_WK2_TEST(TestAutocleanups TestAutocleanups.cpp)
+ADD_WK2_TEST(TestBackForwardList TestBackForwardList.cpp)
+ADD_WK2_TEST(TestContextMenu TestContextMenu.cpp)
+ADD_WK2_TEST(TestCookieManager TestCookieManager.cpp)
+ADD_WK2_TEST(TestDOMNode TestDOMNode.cpp)
+ADD_WK2_TEST(TestDOMNodeFilter TestDOMNodeFilter.cpp)
+ADD_WK2_TEST(TestDOMXPathNSResolver TestDOMXPathNSResolver.cpp)
+ADD_WK2_TEST(TestDownloads TestDownloads.cpp)
+ADD_WK2_TEST(TestWebKitFaviconDatabase TestWebKitFaviconDatabase.cpp)
+ADD_WK2_TEST(TestWebKitFindController TestWebKitFindController.cpp)
+ADD_WK2_TEST(TestFrame TestFrame.cpp)
+ADD_WK2_TEST(TestInspector TestInspector.cpp)
+ADD_WK2_TEST(TestInspectorServer TestInspectorServer.cpp)
+ADD_WK2_TEST(TestLoaderClient TestLoaderClient.cpp)
+ADD_WK2_TEST(TestMultiprocess TestMultiprocess.cpp)
+ADD_WK2_TEST(TestPrinting TestPrinting.cpp)
+ADD_WK2_TEST(TestResources TestResources.cpp)
+ADD_WK2_TEST(TestSSL TestSSL.cpp)
+ADD_WK2_TEST(TestUIClient TestUIClient.cpp)
+ADD_WK2_TEST(TestWebExtensions TestWebExtensions.cpp)
+ADD_WK2_TEST(TestWebKitPolicyClient TestWebKitPolicyClient.cpp)
+ADD_WK2_TEST(TestWebKitSecurityOrigin TestWebKitSecurityOrigin.cpp)
+ADD_WK2_TEST(TestWebKitSettings TestWebKitSettings.cpp)
+ADD_WK2_TEST(TestWebKitVersion TestWebKitVersion.cpp)
+ADD_WK2_TEST(TestWebViewEditor TestWebViewEditor.cpp)
+ADD_WK2_TEST(TestWebKitWebContext TestWebKitWebContext.cpp)
+ADD_WK2_TEST(TestWebKitWebView TestWebKitWebView.cpp)
+ADD_WK2_TEST(TestWebKitUserContentManager TestWebKitUserContentManager.cpp)
+ADD_WK2_TEST(TestWebsiteData TestWebsiteData.cpp)
+ADD_WK2_TEST(TestEditor TestEditor.cpp)
+ADD_WK2_TEST(TestConsoleMessage TestConsoleMessage.cpp)
+
+if (ATSPI_FOUND)
+ ADD_WK2_TEST(AccessibilityTestServer AccessibilityTestServer.cpp)
+ ADD_WK2_TEST(TestWebKitAccessibility TestWebKitAccessibility.cpp)
+endif ()
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/DOMDOMWindowTest.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/DOMDOMWindowTest.cpp
new file mode 100644
index 000000000..fc8cefb52
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/DOMDOMWindowTest.cpp
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2013 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include "WebProcessTest.h"
+#include <gio/gio.h>
+#include <webkit2/webkit-web-extension.h>
+#include <wtf/RunLoop.h>
+
+class WebKitDOMDOMWindowTest;
+static gboolean loadedCallback(WebKitDOMDOMWindow*, WebKitDOMEvent*, WebKitDOMDOMWindowTest*);
+static gboolean clickedCallback(WebKitDOMDOMWindow*, WebKitDOMEvent*, WebKitDOMDOMWindowTest*);
+
+class WebKitDOMDOMWindowTest : public WebProcessTest {
+public:
+ static std::unique_ptr<WebProcessTest> create() { return std::make_unique<WebKitDOMDOMWindowTest>(); }
+
+private:
+ guint64 webPageFromArgs(GVariant* args)
+ {
+ GVariantIter iter;
+ g_variant_iter_init(&iter, args);
+
+ const char* key;
+ GVariant* value;
+ while (g_variant_iter_loop(&iter, "{&sv}", &key, &value)) {
+ if (!strcmp(key, "pageID") && g_variant_classify(value) == G_VARIANT_CLASS_UINT64)
+ return g_variant_get_uint64(value);
+ }
+
+ g_assert_not_reached();
+ return 0;
+ }
+
+ bool testSignals(WebKitWebExtension* extension, GVariant* args)
+ {
+ notify("ready", "");
+
+ WebKitWebPage* page = webkit_web_extension_get_page(extension, webPageFromArgs(args));
+ g_assert(WEBKIT_IS_WEB_PAGE(page));
+ WebKitDOMDocument* document = webkit_web_page_get_dom_document(page);
+ g_assert(WEBKIT_DOM_IS_DOCUMENT(document));
+
+ WebKitDOMDOMWindow* domWindow = webkit_dom_document_get_default_view(document);
+ g_assert(domWindow);
+
+ // The "load" WebKitDOMDOMWindow signal is issued before this test is
+ // called. There's no way to capture it here. We simply assume that
+ // the document is loaded and notify the uiprocess accordingly
+ // notify("loaded", "");
+
+ webkit_dom_event_target_add_event_listener(
+ WEBKIT_DOM_EVENT_TARGET(domWindow),
+ "load",
+ G_CALLBACK(loadedCallback),
+ false,
+ this);
+
+ // loadedCallback() will stop this loop
+ RunLoop::run();
+
+ document = webkit_web_page_get_dom_document(page);
+ g_assert(WEBKIT_DOM_IS_DOCUMENT(document));
+
+ WebKitDOMElement* element = webkit_dom_document_get_element_by_id(document, "test");
+ g_assert(element);
+
+ webkit_dom_event_target_add_event_listener(
+ WEBKIT_DOM_EVENT_TARGET(element),
+ "click",
+ G_CALLBACK(clickedCallback),
+ false,
+ this);
+
+ // The "click" action will be issued in the uiprocess and that will
+ // trigger the dom event here.
+ // clickedCallback() will stop this loop
+ RunLoop::run();
+
+ return true;
+ }
+
+ bool testDispatchEvent(WebKitWebExtension* extension, GVariant* args)
+ {
+ notify("ready", "");
+
+ WebKitWebPage* page = webkit_web_extension_get_page(extension, webPageFromArgs(args));
+ g_assert(WEBKIT_IS_WEB_PAGE(page));
+ WebKitDOMDocument* document = webkit_web_page_get_dom_document(page);
+ g_assert(WEBKIT_DOM_IS_DOCUMENT(document));
+
+ WebKitDOMDOMWindow* domWindow = webkit_dom_document_get_default_view(document);
+ g_assert(domWindow);
+
+ // The "load" WebKitDOMDOMWindow signal is issued before this test is
+ // called. There's no way to capture it here. We simply assume that
+ // the document is loaded and notify the uiprocess accordingly
+ // notify("loaded", "");
+
+ webkit_dom_event_target_add_event_listener(
+ WEBKIT_DOM_EVENT_TARGET(domWindow),
+ "load",
+ G_CALLBACK(loadedCallback),
+ false,
+ this);
+
+ // loadedCallback() will stop this loop
+ RunLoop::run();
+
+ document = webkit_web_page_get_dom_document(page);
+ g_assert(WEBKIT_DOM_IS_DOCUMENT(document));
+
+ WebKitDOMElement* element = webkit_dom_document_get_element_by_id(document, "test");
+ g_assert(element);
+
+ WebKitDOMEvent* event = webkit_dom_document_create_event(document, "MouseEvent", 0);
+ g_assert(event);
+ g_assert(WEBKIT_DOM_IS_EVENT(event));
+ g_assert(WEBKIT_DOM_IS_MOUSE_EVENT(event));
+
+ glong clientX, clientY;
+ clientX = webkit_dom_element_get_client_left(element);
+ clientY = webkit_dom_element_get_client_top(element);
+
+ webkit_dom_event_target_add_event_listener(
+ WEBKIT_DOM_EVENT_TARGET(element),
+ "click",
+ G_CALLBACK(clickedCallback),
+ false,
+ this);
+
+ webkit_dom_mouse_event_init_mouse_event(WEBKIT_DOM_MOUSE_EVENT(event),
+ "click", TRUE, TRUE,
+ domWindow, 0, 0, 0, clientX, clientY,
+ FALSE, FALSE, FALSE, FALSE,
+ 1, WEBKIT_DOM_EVENT_TARGET(element));
+
+ webkit_dom_event_target_dispatch_event(WEBKIT_DOM_EVENT_TARGET(element), event, 0);
+
+ // clickedCallback() will stop this loop
+ RunLoop::run();
+
+ return true;
+ }
+
+ bool testGetComputedStyle(WebKitWebExtension* extension, GVariant* args)
+ {
+ WebKitWebPage* page = webkit_web_extension_get_page(extension, webPageFromArgs(args));
+ g_assert(WEBKIT_IS_WEB_PAGE(page));
+ WebKitDOMDocument* document = webkit_web_page_get_dom_document(page);
+ g_assert(WEBKIT_DOM_IS_DOCUMENT(document));
+ WebKitDOMDOMWindow* domWindow = webkit_dom_document_get_default_view(document);
+ g_assert(domWindow);
+ WebKitDOMElement* element = webkit_dom_document_get_element_by_id(document, "test");
+ g_assert(element);
+ g_assert(WEBKIT_DOM_IS_ELEMENT(element));
+ WebKitDOMCSSStyleDeclaration* cssStyle = webkit_dom_dom_window_get_computed_style(domWindow, element, 0);
+ gchar* fontSize = webkit_dom_css_style_declaration_get_property_value(cssStyle, "font-size");
+ g_assert_cmpstr(fontSize, ==, "16px");
+
+ return true;
+ }
+
+ virtual bool runTest(const char* testName, WebKitWebExtension* extension, GVariant* args)
+ {
+ if (!strcmp(testName, "signals"))
+ return testSignals(extension, args);
+ if (!strcmp(testName, "dispatch-event"))
+ return testDispatchEvent(extension, args);
+ if (!strcmp(testName, "get-computed-style"))
+ return testGetComputedStyle(extension, args);
+
+ g_assert_not_reached();
+ return false;
+ }
+};
+
+static void __attribute__((constructor)) registerTests()
+{
+ REGISTER_TEST(WebKitDOMDOMWindowTest, "WebKitDOMDOMWindow/signals");
+ REGISTER_TEST(WebKitDOMDOMWindowTest, "WebKitDOMDOMWindow/dispatch-event");
+ REGISTER_TEST(WebKitDOMDOMWindowTest, "WebKitDOMDOMWindow/get-computed-style");
+}
+
+static gboolean loadedCallback(WebKitDOMDOMWindow* view, WebKitDOMEvent* event, WebKitDOMDOMWindowTest* test)
+{
+ test->notify("loaded", "");
+
+ // Stop the loop and let testSignals() or testDispatchEvent() continue its course
+ RunLoop::current().stop();
+
+ return FALSE;
+}
+
+static gboolean clickedCallback(WebKitDOMDOMWindow* view, WebKitDOMEvent* event, WebKitDOMDOMWindowTest* test)
+{
+ test->notify("clicked", "");
+ test->notify("finish", "");
+
+ // Stop the loop and let testSignals() or testDispatchEvent() continue its course
+ RunLoop::current().stop();
+
+ return FALSE;
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/DOMNodeFilterTest.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/DOMNodeFilterTest.cpp
new file mode 100644
index 000000000..0f18d1f31
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/DOMNodeFilterTest.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2013 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include "WebProcessTest.h"
+#include <gio/gio.h>
+#include <webkit2/webkit-web-extension.h>
+#include <wtf/glib/GUniquePtr.h>
+
+typedef struct _WebKitNodeFilter {
+ GObject parent;
+} WebKitNodeFilter;
+
+typedef struct _WebKitNodeFilterClass {
+ GObjectClass parentClass;
+} WebKitNodeFilterClass;
+
+static short webkitNodeFilterAcceptNode(WebKitDOMNodeFilter*, WebKitDOMNode* node)
+{
+ // Filter out input elements.
+ return WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(node) ? WEBKIT_DOM_NODE_FILTER_REJECT : WEBKIT_DOM_NODE_FILTER_ACCEPT;
+}
+
+static void webkitNodeFilterDOMNodeFilterIfaceInit(WebKitDOMNodeFilterIface* iface)
+{
+ iface->accept_node = webkitNodeFilterAcceptNode;
+}
+
+G_DEFINE_TYPE_WITH_CODE(WebKitNodeFilter, webkit_node_filter, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE(WEBKIT_DOM_TYPE_NODE_FILTER, webkitNodeFilterDOMNodeFilterIfaceInit))
+
+static void webkit_node_filter_init(WebKitNodeFilter*)
+{
+}
+
+static void webkit_node_filter_class_init(WebKitNodeFilterClass*)
+{
+}
+
+static const char* expectedNodesAll[] = { "HTML", "HEAD", "TITLE", "#text", "BODY", "INPUT", "INPUT", "BR" };
+static const char* expectedNodesNoInput[] = { "HTML", "HEAD", "TITLE", "#text", "BODY", "BR" };
+static const char* expectedElementsNoInput[] = { "HTML", "HEAD", "TITLE", "BODY", "BR" };
+
+class WebKitDOMNodeFilterTest : public WebProcessTest {
+public:
+ static std::unique_ptr<WebProcessTest> create() { return std::unique_ptr<WebProcessTest>(new WebKitDOMNodeFilterTest()); }
+
+private:
+ bool testTreeWalker(WebKitWebPage* page)
+ {
+ WebKitDOMDocument* document = webkit_web_page_get_dom_document(page);
+ g_assert(WEBKIT_DOM_IS_DOCUMENT(document));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(document));
+
+ WebKitDOMElement* root = webkit_dom_document_get_element_by_id(document, "root");
+ g_assert(WEBKIT_DOM_IS_NODE(root));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(root));
+
+ // No filter.
+ GRefPtr<WebKitDOMTreeWalker> walker = adoptGRef(webkit_dom_document_create_tree_walker(document, WEBKIT_DOM_NODE(root), WEBKIT_DOM_NODE_FILTER_SHOW_ALL, nullptr, FALSE, nullptr));
+ g_assert(WEBKIT_DOM_IS_TREE_WALKER(walker.get()));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(walker.get()));
+ g_assert(!webkit_dom_tree_walker_get_filter(walker.get()));
+
+ unsigned i = 0;
+ for (WebKitDOMNode* node = WEBKIT_DOM_NODE(root); node; node = webkit_dom_tree_walker_next_node(walker.get()), ++i) {
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(node));
+ g_assert_cmpuint(i, <, G_N_ELEMENTS(expectedNodesAll));
+ GUniquePtr<char> nodeName(webkit_dom_node_get_node_name(node));
+ g_assert_cmpstr(nodeName.get(), ==, expectedNodesAll[i]);
+ }
+ g_assert_cmpuint(i, ==, G_N_ELEMENTS(expectedNodesAll));
+
+ // Input elements filter.
+ GRefPtr<WebKitDOMNodeFilter> filter = adoptGRef(static_cast<WebKitDOMNodeFilter*>(g_object_new(webkit_node_filter_get_type(), nullptr)));
+ walker = adoptGRef(webkit_dom_document_create_tree_walker(document, WEBKIT_DOM_NODE(root), WEBKIT_DOM_NODE_FILTER_SHOW_ALL, filter.get(), FALSE, nullptr));
+ g_assert(WEBKIT_DOM_IS_TREE_WALKER(walker.get()));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(filter.get()));
+ g_assert(webkit_dom_tree_walker_get_filter(walker.get()) == filter.get());
+
+ i = 0;
+ for (WebKitDOMNode* node = WEBKIT_DOM_NODE(root); node; node = webkit_dom_tree_walker_next_node(walker.get()), ++i) {
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(node));
+ g_assert_cmpuint(i, <, G_N_ELEMENTS(expectedNodesNoInput));
+ GUniquePtr<char> nodeName(webkit_dom_node_get_node_name(node));
+ g_assert_cmpstr(nodeName.get(), ==, expectedNodesNoInput[i]);
+ }
+ g_assert_cmpuint(i, ==, G_N_ELEMENTS(expectedNodesNoInput));
+
+ // Show only elements, reusing the input filter.
+ walker = adoptGRef(webkit_dom_document_create_tree_walker(document, WEBKIT_DOM_NODE(root), WEBKIT_DOM_NODE_FILTER_SHOW_ELEMENT, filter.get(), FALSE, nullptr));
+ g_assert(WEBKIT_DOM_IS_TREE_WALKER(walker.get()));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(walker.get()));
+ g_assert(webkit_dom_tree_walker_get_filter(walker.get()) == filter.get());
+
+ i = 0;
+ for (WebKitDOMNode* node = WEBKIT_DOM_NODE(root); node; node = webkit_dom_tree_walker_next_node(walker.get()), ++i) {
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(node));
+ g_assert_cmpuint(i, <, G_N_ELEMENTS(expectedElementsNoInput));
+ GUniquePtr<char> nodeName(webkit_dom_node_get_node_name(node));
+ g_assert_cmpstr(nodeName.get(), ==, expectedElementsNoInput[i]);
+ }
+ g_assert_cmpuint(i, ==, G_N_ELEMENTS(expectedElementsNoInput));
+
+ return true;
+ }
+
+ bool testNodeIterator(WebKitWebPage* page)
+ {
+ WebKitDOMDocument* document = webkit_web_page_get_dom_document(page);
+ g_assert(WEBKIT_DOM_IS_DOCUMENT(document));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(document));
+
+ WebKitDOMElement* root = webkit_dom_document_get_element_by_id(document, "root");
+ g_assert(WEBKIT_DOM_IS_NODE(root));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(root));
+
+ // No filter.
+ GRefPtr<WebKitDOMNodeIterator> iter = adoptGRef(webkit_dom_document_create_node_iterator(document, WEBKIT_DOM_NODE(root), WEBKIT_DOM_NODE_FILTER_SHOW_ALL, nullptr, FALSE, nullptr));
+ g_assert(WEBKIT_DOM_IS_NODE_ITERATOR(iter.get()));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(iter.get()));
+ g_assert(!webkit_dom_node_iterator_get_filter(iter.get()));
+
+ unsigned i = 0;
+ while (WebKitDOMNode* node = webkit_dom_node_iterator_next_node(iter.get(), nullptr)) {
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(node));
+ g_assert_cmpuint(i, <, G_N_ELEMENTS(expectedNodesAll));
+ GUniquePtr<char> nodeName(webkit_dom_node_get_node_name(node));
+ g_assert_cmpstr(nodeName.get(), ==, expectedNodesAll[i]);
+ i++;
+ }
+ g_assert_cmpuint(i, ==, G_N_ELEMENTS(expectedNodesAll));
+
+ // Input elements filter.
+ GRefPtr<WebKitDOMNodeFilter> filter = adoptGRef(static_cast<WebKitDOMNodeFilter*>(g_object_new(webkit_node_filter_get_type(), nullptr)));
+ iter = adoptGRef(webkit_dom_document_create_node_iterator(document, WEBKIT_DOM_NODE(root), WEBKIT_DOM_NODE_FILTER_SHOW_ALL, filter.get(), FALSE, nullptr));
+ g_assert(WEBKIT_DOM_IS_NODE_ITERATOR(iter.get()));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(iter.get()));
+ g_assert(webkit_dom_node_iterator_get_filter(iter.get()) == filter.get());
+
+ i = 0;
+ while (WebKitDOMNode* node = webkit_dom_node_iterator_next_node(iter.get(), nullptr)) {
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(node));
+ g_assert_cmpuint(i, <, G_N_ELEMENTS(expectedNodesNoInput));
+ GUniquePtr<char> nodeName(webkit_dom_node_get_node_name(node));
+ g_assert_cmpstr(nodeName.get(), ==, expectedNodesNoInput[i]);
+ i++;
+ }
+ g_assert_cmpuint(i, ==, G_N_ELEMENTS(expectedNodesNoInput));
+
+ // Show only elements, reusing the input filter.
+ iter = adoptGRef(webkit_dom_document_create_node_iterator(document, WEBKIT_DOM_NODE(root), WEBKIT_DOM_NODE_FILTER_SHOW_ELEMENT, filter.get(), FALSE, nullptr));
+ g_assert(WEBKIT_DOM_IS_NODE_ITERATOR(iter.get()));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(iter.get()));
+ g_assert(webkit_dom_node_iterator_get_filter(iter.get()) == filter.get());
+
+ i = 0;
+ while (WebKitDOMNode* node = webkit_dom_node_iterator_next_node(iter.get(), nullptr)) {
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(node));
+ g_assert_cmpuint(i, <, G_N_ELEMENTS(expectedElementsNoInput));
+ GUniquePtr<char> nodeName(webkit_dom_node_get_node_name(node));
+ g_assert_cmpstr(nodeName.get(), ==, expectedElementsNoInput[i]);
+ i++;
+ }
+ g_assert_cmpuint(i, ==, G_N_ELEMENTS(expectedElementsNoInput));
+
+ return true;
+ }
+
+ bool runTest(const char* testName, WebKitWebPage* page) override
+ {
+ if (!strcmp(testName, "tree-walker"))
+ return testTreeWalker(page);
+ if (!strcmp(testName, "node-iterator"))
+ return testNodeIterator(page);
+
+ g_assert_not_reached();
+ return false;
+ }
+};
+
+static void __attribute__((constructor)) registerTests()
+{
+ REGISTER_TEST(WebKitDOMNodeFilterTest, "WebKitDOMNodeFilter/tree-walker");
+ REGISTER_TEST(WebKitDOMNodeFilterTest, "WebKitDOMNodeFilter/node-iterator");
+}
+
+
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/DOMNodeTest.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/DOMNodeTest.cpp
index 5f62e5493..9d57b42d2 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/DOMNodeTest.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/DOMNodeTest.cpp
@@ -22,7 +22,7 @@
#include "WebProcessTest.h"
#include <gio/gio.h>
#include <webkit2/webkit-web-extension.h>
-#include <wtf/gobject/GUniquePtr.h>
+#include <wtf/glib/GUniquePtr.h>
class WebKitDOMNodeTest : public WebProcessTest {
public:
@@ -33,21 +33,26 @@ private:
{
WebKitDOMDocument* document = webkit_web_page_get_dom_document(page);
g_assert(WEBKIT_DOM_IS_DOCUMENT(document));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(document));
WebKitDOMHTMLHeadElement* head = webkit_dom_document_get_head(document);
g_assert(WEBKIT_DOM_IS_HTML_HEAD_ELEMENT(head));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(head));
// Title, head's child.
g_assert(webkit_dom_node_has_child_nodes(WEBKIT_DOM_NODE(head)));
GRefPtr<WebKitDOMNodeList> list = adoptGRef(webkit_dom_node_get_child_nodes(WEBKIT_DOM_NODE(head)));
g_assert(WEBKIT_DOM_IS_NODE_LIST(list.get()));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(list.get()));
g_assert_cmpint(webkit_dom_node_list_get_length(list.get()), ==, 1);
WebKitDOMNode* node = webkit_dom_node_list_item(list.get(), 0);
g_assert(WEBKIT_DOM_IS_HTML_TITLE_ELEMENT(node));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(node));
// Body, Head sibling.
node = webkit_dom_node_get_next_sibling(WEBKIT_DOM_NODE(head));
g_assert(WEBKIT_DOM_IS_HTML_BODY_ELEMENT(node));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(node));
WebKitDOMHTMLBodyElement* body = WEBKIT_DOM_HTML_BODY_ELEMENT(node);
// There is no third sibling
@@ -56,10 +61,13 @@ private:
// Body's previous sibling is Head.
node = webkit_dom_node_get_previous_sibling(WEBKIT_DOM_NODE(body));
g_assert(WEBKIT_DOM_IS_HTML_HEAD_ELEMENT(node));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(node));
// Body has 3 children.
g_assert(webkit_dom_node_has_child_nodes(WEBKIT_DOM_NODE(body)));
list = adoptGRef(webkit_dom_node_get_child_nodes(WEBKIT_DOM_NODE(body)));
+ g_assert(WEBKIT_DOM_IS_NODE_LIST(list.get()));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(list.get()));
unsigned long length = webkit_dom_node_list_get_length(list.get());
g_assert_cmpint(length, ==, 3);
@@ -67,6 +75,7 @@ private:
for (unsigned long i = 0; i < length; i++) {
node = webkit_dom_node_list_item(list.get(), i);
g_assert(WEBKIT_DOM_IS_HTML_PARAGRAPH_ELEMENT(node));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(node));
}
// Go backwards
@@ -81,88 +90,135 @@ private:
{
WebKitDOMDocument* document = webkit_web_page_get_dom_document(page);
g_assert(WEBKIT_DOM_IS_DOCUMENT(document));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(document));
WebKitDOMHTMLElement* body = webkit_dom_document_get_body(document);
g_assert(WEBKIT_DOM_IS_HTML_ELEMENT(body));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(body));
// Body shouldn't have any children at this point.
g_assert(!webkit_dom_node_has_child_nodes(WEBKIT_DOM_NODE(body)));
+ // The value of a non-existent attribute should be null, not an empty string
+ g_assert(!webkit_dom_html_body_element_get_background(WEBKIT_DOM_HTML_BODY_ELEMENT(body)));
+
// Insert one P element.
WebKitDOMElement* p = webkit_dom_document_create_element(document, "P", 0);
g_assert(WEBKIT_DOM_IS_HTML_ELEMENT(p));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(p));
webkit_dom_node_append_child(WEBKIT_DOM_NODE(body), WEBKIT_DOM_NODE(p), 0);
// Now it should have one, the same that we inserted.
g_assert(webkit_dom_node_has_child_nodes(WEBKIT_DOM_NODE(body)));
GRefPtr<WebKitDOMNodeList> list = adoptGRef(webkit_dom_node_get_child_nodes(WEBKIT_DOM_NODE(body)));
g_assert(WEBKIT_DOM_IS_NODE_LIST(list.get()));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(list.get()));
g_assert_cmpint(webkit_dom_node_list_get_length(list.get()), ==, 1);
WebKitDOMNode* node = webkit_dom_node_list_item(list.get(), 0);
g_assert(WEBKIT_DOM_IS_HTML_ELEMENT(node));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(node));
g_assert(webkit_dom_node_is_same_node(WEBKIT_DOM_NODE(p), node));
// Replace the P tag with a DIV tag.
WebKitDOMElement* div = webkit_dom_document_create_element(document, "DIV", 0);
g_assert(WEBKIT_DOM_IS_HTML_ELEMENT(div));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(div));
webkit_dom_node_replace_child(WEBKIT_DOM_NODE(body), WEBKIT_DOM_NODE(div), WEBKIT_DOM_NODE(p), 0);
g_assert(webkit_dom_node_has_child_nodes(WEBKIT_DOM_NODE(body)));
list = adoptGRef(webkit_dom_node_get_child_nodes(WEBKIT_DOM_NODE(body)));
g_assert(WEBKIT_DOM_IS_NODE_LIST(list.get()));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(list.get()));
g_assert_cmpint(webkit_dom_node_list_get_length(list.get()), ==, 1);
node = webkit_dom_node_list_item(list.get(), 0);
g_assert(WEBKIT_DOM_IS_HTML_ELEMENT(node));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(node));
g_assert(webkit_dom_node_is_same_node(WEBKIT_DOM_NODE(div), node));
// Now remove the tag.
webkit_dom_node_remove_child(WEBKIT_DOM_NODE(body), node, 0);
list = adoptGRef(webkit_dom_node_get_child_nodes(WEBKIT_DOM_NODE(body)));
g_assert(WEBKIT_DOM_IS_NODE_LIST(list.get()));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(list.get()));
g_assert_cmpint(webkit_dom_node_list_get_length(list.get()), ==, 0);
// Test insert before. If refChild is null, insert newChild as last element of parent.
div = webkit_dom_document_create_element(document, "DIV", 0);
g_assert(WEBKIT_DOM_IS_HTML_ELEMENT(div));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(div));
webkit_dom_node_insert_before(WEBKIT_DOM_NODE(body), WEBKIT_DOM_NODE(div), 0, 0);
g_assert(webkit_dom_node_has_child_nodes(WEBKIT_DOM_NODE(body)));
list = adoptGRef(webkit_dom_node_get_child_nodes(WEBKIT_DOM_NODE(body)));
g_assert(WEBKIT_DOM_IS_NODE_LIST(list.get()));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(list.get()));
g_assert_cmpint(webkit_dom_node_list_get_length(list.get()), ==, 1);
node = webkit_dom_node_list_item(list.get(), 0);
g_assert(WEBKIT_DOM_IS_HTML_ELEMENT(node));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(node));
g_assert(webkit_dom_node_is_same_node(WEBKIT_DOM_NODE(div), node));
// Now insert a 'p' before 'div'.
p = webkit_dom_document_create_element(document, "P", 0);
g_assert(WEBKIT_DOM_IS_HTML_ELEMENT(p));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(p));
webkit_dom_node_insert_before(WEBKIT_DOM_NODE(body), WEBKIT_DOM_NODE(p), WEBKIT_DOM_NODE(div), 0);
g_assert(webkit_dom_node_has_child_nodes(WEBKIT_DOM_NODE(body)));
list = adoptGRef(webkit_dom_node_get_child_nodes(WEBKIT_DOM_NODE(body)));
g_assert(WEBKIT_DOM_IS_NODE_LIST(list.get()));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(list.get()));
g_assert_cmpint(webkit_dom_node_list_get_length(list.get()), ==, 2);
node = webkit_dom_node_list_item(list.get(), 0);
g_assert(WEBKIT_DOM_IS_HTML_ELEMENT(node));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(node));
g_assert(webkit_dom_node_is_same_node(WEBKIT_DOM_NODE(p), node));
node = webkit_dom_node_list_item(list.get(), 1);
g_assert(WEBKIT_DOM_IS_HTML_ELEMENT(node));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(node));
g_assert(webkit_dom_node_is_same_node(WEBKIT_DOM_NODE(div), node));
return true;
}
- bool testTagNames(WebKitWebPage* page)
+ bool testTagNamesNodeList(WebKitWebPage* page)
+ {
+ static const char* expectedTagNames[] = { "HTML", "HEAD", "BODY", "VIDEO", "SOURCE", "VIDEO", "SOURCE", "INPUT" };
+
+ WebKitDOMDocument* document = webkit_web_page_get_dom_document(page);
+ g_assert(WEBKIT_DOM_IS_DOCUMENT(document));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(document));
+
+ GRefPtr<WebKitDOMNodeList> list = adoptGRef(webkit_dom_document_query_selector_all(document, "*", nullptr));
+ g_assert(WEBKIT_DOM_IS_NODE_LIST(list.get()));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(list.get()));
+ gulong nodeCount = webkit_dom_node_list_get_length(list.get());
+ g_assert_cmpuint(nodeCount, ==, G_N_ELEMENTS(expectedTagNames));
+ for (unsigned i = 0; i < nodeCount; i++) {
+ WebKitDOMNode* node = webkit_dom_node_list_item(list.get(), i);
+ g_assert(WEBKIT_DOM_IS_NODE(node));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(node));
+ GUniquePtr<char> tagName(webkit_dom_node_get_node_name(node));
+ g_assert_cmpstr(tagName.get(), ==, expectedTagNames[i]);
+ }
+
+ return true;
+ }
+
+ bool testTagNamesHTMLCollection(WebKitWebPage* page)
{
static const char* expectedTagNames[] = { "HTML", "HEAD", "BODY", "VIDEO", "SOURCE", "VIDEO", "SOURCE", "INPUT" };
WebKitDOMDocument* document = webkit_web_page_get_dom_document(page);
g_assert(WEBKIT_DOM_IS_DOCUMENT(document));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(document));
- WebKitDOMNodeList* list = webkit_dom_document_get_elements_by_tag_name(document, "*");
- gulong nodeCount = webkit_dom_node_list_get_length(list);
+ GRefPtr<WebKitDOMHTMLCollection> collection = adoptGRef(webkit_dom_document_get_elements_by_tag_name_as_html_collection(document, "*"));
+ g_assert(WEBKIT_DOM_IS_HTML_COLLECTION(collection.get()));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(collection.get()));
+ gulong nodeCount = webkit_dom_html_collection_get_length(collection.get());
g_assert_cmpuint(nodeCount, ==, G_N_ELEMENTS(expectedTagNames));
for (unsigned i = 0; i < nodeCount; i++) {
- WebKitDOMNode* node = webkit_dom_node_list_item(list, i);
+ WebKitDOMNode* node = webkit_dom_html_collection_item(collection.get(), i);
g_assert(WEBKIT_DOM_IS_NODE(node));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(node));
GUniquePtr<char> tagName(webkit_dom_node_get_node_name(node));
g_assert_cmpstr(tagName.get(), ==, expectedTagNames[i]);
}
@@ -170,14 +226,62 @@ private:
return true;
}
+ bool testDOMCache(WebKitWebPage* page)
+ {
+ WebKitDOMDocument* document = webkit_web_page_get_dom_document(page);
+ g_assert(WEBKIT_DOM_IS_DOCUMENT(document));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(document));
+
+ // DOM objects already in the document should be automatically handled by the cache.
+ WebKitDOMElement* div = webkit_dom_document_get_element_by_id(document, "container");
+ g_assert(WEBKIT_DOM_IS_HTML_ELEMENT(div));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(div));
+
+ // Get the same elment twice should return the same pointer.
+ g_assert(div == webkit_dom_document_get_element_by_id(document, "container"));
+
+ // A new DOM object created that is derived from Node should be automatically handled by the cache.
+ WebKitDOMElement* p = webkit_dom_document_create_element(document, "P", nullptr);
+ g_assert(WEBKIT_DOM_IS_HTML_PARAGRAPH_ELEMENT(p));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(p));
+
+ // A new DOM object created that isn't derived from Node should be manually handled.
+ GRefPtr<WebKitDOMNodeIterator> iter = adoptGRef(webkit_dom_document_create_node_iterator(document, WEBKIT_DOM_NODE(div), WEBKIT_DOM_NODE_FILTER_SHOW_ALL, nullptr, FALSE, nullptr));
+ g_assert(WEBKIT_DOM_IS_NODE_ITERATOR(iter.get()));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(iter.get()));
+
+ // We can also manually handle a DOM object handled by the cache.
+ GRefPtr<WebKitDOMElement> p2 = adoptGRef(webkit_dom_document_create_element(document, "P", nullptr));
+ g_assert(WEBKIT_DOM_IS_HTML_PARAGRAPH_ELEMENT(p2.get()));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(p2.get()));
+
+ // Manually handling a DOM object owned by the cache shouldn't crash when the cache has more than one reference.
+ GRefPtr<WebKitDOMElement> p3 = adoptGRef(webkit_dom_document_create_element(document, "P", nullptr));
+ g_assert(WEBKIT_DOM_IS_HTML_PARAGRAPH_ELEMENT(p3.get()));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(p3.get()));
+ webkit_dom_node_append_child(WEBKIT_DOM_NODE(div), WEBKIT_DOM_NODE(p3.get()), nullptr);
+
+ // DOM objects removed from the document are also correctly handled by the cache.
+ WebKitDOMElement* a = webkit_dom_document_create_element(document, "A", nullptr);
+ g_assert(WEBKIT_DOM_IS_ELEMENT(a));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(a));
+ webkit_dom_node_remove_child(WEBKIT_DOM_NODE(div), WEBKIT_DOM_NODE(a), nullptr);
+
+ return true;
+ }
+
bool runTest(const char* testName, WebKitWebPage* page) override
{
if (!strcmp(testName, "hierarchy-navigation"))
return testHierarchyNavigation(page);
if (!strcmp(testName, "insertion"))
return testInsertion(page);
- if (!strcmp(testName, "tag-names"))
- return testTagNames(page);
+ if (!strcmp(testName, "tag-names-node-list"))
+ return testTagNamesNodeList(page);
+ if (!strcmp(testName, "tag-names-html-collection"))
+ return testTagNamesHTMLCollection(page);
+ if (!strcmp(testName, "dom-cache"))
+ return testDOMCache(page);
g_assert_not_reached();
return false;
@@ -188,7 +292,9 @@ static void __attribute__((constructor)) registerTests()
{
REGISTER_TEST(WebKitDOMNodeTest, "WebKitDOMNode/hierarchy-navigation");
REGISTER_TEST(WebKitDOMNodeTest, "WebKitDOMNode/insertion");
- REGISTER_TEST(WebKitDOMNodeTest, "WebKitDOMNode/tag-names");
+ REGISTER_TEST(WebKitDOMNodeTest, "WebKitDOMNode/tag-names-node-list");
+ REGISTER_TEST(WebKitDOMNodeTest, "WebKitDOMNode/tag-names-html-collection");
+ REGISTER_TEST(WebKitDOMNodeTest, "WebKitDOMNode/dom-cache");
}
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/DOMXPathNSResolverTest.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/DOMXPathNSResolverTest.cpp
new file mode 100644
index 000000000..110677e41
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/DOMXPathNSResolverTest.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include "WebProcessTest.h"
+#include <gio/gio.h>
+#include <webkit2/webkit-web-extension.h>
+#include <wtf/glib/GUniquePtr.h>
+
+typedef struct _WebKitXPathNSResolver {
+ GObject parent;
+} WebKitXPathNSResolver;
+
+typedef struct _WebKitXPathNSResolverClass {
+ GObjectClass parentClass;
+} WebKitXPathNSResolverClass;
+
+static char* webkitXPathNSResolverLookupNamespaceURI(WebKitDOMXPathNSResolver* resolver, const char* prefix)
+{
+ if (!g_strcmp0(prefix, "foo"))
+ return g_strdup("http://www.example.com");
+
+ return nullptr;
+}
+
+static void webkitXPathNSResolverDOMXPathNSResolverIfaceInit(WebKitDOMXPathNSResolverIface* iface)
+{
+ iface->lookup_namespace_uri = webkitXPathNSResolverLookupNamespaceURI;
+}
+
+G_DEFINE_TYPE_WITH_CODE(WebKitXPathNSResolver, webkit_xpath_ns_resolver, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE(WEBKIT_DOM_TYPE_XPATH_NS_RESOLVER, webkitXPathNSResolverDOMXPathNSResolverIfaceInit))
+
+static void webkit_xpath_ns_resolver_init(WebKitXPathNSResolver*)
+{
+}
+
+static void webkit_xpath_ns_resolver_class_init(WebKitXPathNSResolverClass*)
+{
+}
+
+class WebKitDOMXPathNSResolverTest : public WebProcessTest {
+public:
+ static std::unique_ptr<WebProcessTest> create() { return std::unique_ptr<WebProcessTest>(new WebKitDOMXPathNSResolverTest()); }
+
+private:
+ void evaluateFooChildTextAndCheckResult(WebKitDOMDocument* document, WebKitDOMXPathNSResolver* resolver)
+ {
+ WebKitDOMElement* documentElement = webkit_dom_document_get_document_element(document);
+ g_assert(WEBKIT_DOM_IS_ELEMENT(documentElement));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(documentElement));
+
+ GRefPtr<WebKitDOMXPathResult> result = adoptGRef(webkit_dom_document_evaluate(document, "foo:child/text()", WEBKIT_DOM_NODE(documentElement), resolver, WEBKIT_DOM_XPATH_RESULT_ORDERED_NODE_ITERATOR_TYPE, nullptr, nullptr));
+ g_assert(WEBKIT_DOM_IS_XPATH_RESULT(result.get()));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(result.get()));
+
+ WebKitDOMNode* nodeResult = webkit_dom_xpath_result_iterate_next(result.get(), nullptr);
+ g_assert(WEBKIT_DOM_IS_NODE(nodeResult));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(nodeResult));
+
+ GUniquePtr<char> nodeValue(webkit_dom_node_get_node_value(nodeResult));
+ g_assert_cmpstr(nodeValue.get(), ==, "SUCCESS");
+ }
+
+ bool testXPathNSResolverNative(WebKitWebPage* page)
+ {
+ WebKitDOMDocument* document = webkit_web_page_get_dom_document(page);
+ g_assert(WEBKIT_DOM_IS_DOCUMENT(document));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(document));
+
+ GRefPtr<WebKitDOMXPathNSResolver> resolver = adoptGRef(webkit_dom_document_create_ns_resolver(document, WEBKIT_DOM_NODE(webkit_dom_document_get_document_element(document))));
+ g_assert(WEBKIT_DOM_IS_XPATH_NS_RESOLVER(resolver.get()));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(resolver.get()));
+ evaluateFooChildTextAndCheckResult(document, resolver.get());
+
+ return true;
+ }
+
+ bool testXPathNSResolverCustom(WebKitWebPage* page)
+ {
+ WebKitDOMDocument* document = webkit_web_page_get_dom_document(page);
+ g_assert(WEBKIT_DOM_IS_DOCUMENT(document));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(document));
+
+ GRefPtr<WebKitDOMXPathNSResolver> resolver = adoptGRef(WEBKIT_DOM_XPATH_NS_RESOLVER(g_object_new(webkit_xpath_ns_resolver_get_type(), nullptr)));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(resolver.get()));
+ evaluateFooChildTextAndCheckResult(document, resolver.get());
+
+ return true;
+ }
+
+ bool runTest(const char* testName, WebKitWebPage* page) override
+ {
+ if (!strcmp(testName, "native"))
+ return testXPathNSResolverNative(page);
+ if (!strcmp(testName, "custom"))
+ return testXPathNSResolverCustom(page);
+
+ g_assert_not_reached();
+ return false;
+ }
+};
+
+static void __attribute__((constructor)) registerTests()
+{
+ REGISTER_TEST(WebKitDOMXPathNSResolverTest, "WebKitDOMXPathNSResolver/native");
+ REGISTER_TEST(WebKitDOMXPathNSResolverTest, "WebKitDOMXPathNSResolver/custom");
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/EditorTest.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/EditorTest.cpp
new file mode 100644
index 000000000..873344271
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/EditorTest.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2015 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include "WebProcessTest.h"
+#include <webkit2/webkit-web-extension.h>
+
+#define WEBKIT_DOM_USE_UNSTABLE_API
+#include <webkitdom/WebKitDOMDOMSelection.h>
+#include <webkitdom/WebKitDOMDOMWindowUnstable.h>
+
+class WebKitWebEditorTest : public WebProcessTest {
+public:
+ static std::unique_ptr<WebProcessTest> create() { return std::unique_ptr<WebProcessTest>(new WebKitWebEditorTest()); }
+
+private:
+ static void selectionChangedCallback(bool* selectionChanged)
+ {
+ *selectionChanged = true;
+ }
+
+ void testSelectionSelectAll(WebKitWebPage* page)
+ {
+ WebKitDOMDocument* document = webkit_web_page_get_dom_document(page);
+ g_assert(WEBKIT_DOM_IS_DOCUMENT(document));
+
+ webkit_dom_document_exec_command(document, "SelectAll", false, "");
+ }
+
+ void testSelectionCollapse(WebKitWebPage* page)
+ {
+ WebKitDOMDocument* document = webkit_web_page_get_dom_document(page);
+ g_assert(WEBKIT_DOM_IS_DOCUMENT(document));
+ GRefPtr<WebKitDOMDOMWindow> domWindow = adoptGRef(webkit_dom_document_get_default_view(document));
+ g_assert(WEBKIT_DOM_IS_DOM_WINDOW(domWindow.get()));
+ GRefPtr<WebKitDOMDOMSelection> domSelection = adoptGRef(webkit_dom_dom_window_get_selection(domWindow.get()));
+ g_assert(WEBKIT_DOM_IS_DOM_SELECTION(domSelection.get()));
+
+ webkit_dom_dom_selection_collapse_to_start(domSelection.get(), nullptr);
+ }
+
+ void testSelectionModifyMove(WebKitWebPage* page)
+ {
+ WebKitDOMDocument* document = webkit_web_page_get_dom_document(page);
+ g_assert(WEBKIT_DOM_IS_DOCUMENT(document));
+ GRefPtr<WebKitDOMDOMWindow> domWindow = adoptGRef(webkit_dom_document_get_default_view(document));
+ g_assert(WEBKIT_DOM_IS_DOM_WINDOW(domWindow.get()));
+ GRefPtr<WebKitDOMDOMSelection> domSelection = adoptGRef(webkit_dom_dom_window_get_selection(domWindow.get()));
+ g_assert(WEBKIT_DOM_IS_DOM_SELECTION(domSelection.get()));
+
+ webkit_dom_dom_selection_modify(domSelection.get(), "move", "forward", "character");
+ }
+
+ void testSelectionModifyExtend(WebKitWebPage* page)
+ {
+ WebKitDOMDocument* document = webkit_web_page_get_dom_document(page);
+ g_assert(WEBKIT_DOM_IS_DOCUMENT(document));
+ GRefPtr<WebKitDOMDOMWindow> domWindow = adoptGRef(webkit_dom_document_get_default_view(document));
+ g_assert(WEBKIT_DOM_IS_DOM_WINDOW(domWindow.get()));
+ GRefPtr<WebKitDOMDOMSelection> domSelection = adoptGRef(webkit_dom_dom_window_get_selection(domWindow.get()));
+ g_assert(WEBKIT_DOM_IS_DOM_SELECTION(domSelection.get()));
+
+ webkit_dom_dom_selection_modify(domSelection.get(), "extend", "forward", "word");
+ }
+
+ void testSelectionUnselect(WebKitWebPage* page)
+ {
+ WebKitDOMDocument* document = webkit_web_page_get_dom_document(page);
+ g_assert(WEBKIT_DOM_IS_DOCUMENT(document));
+
+ webkit_dom_document_exec_command(document, "Unselect", false, "");
+ }
+
+ bool runTest(const char* testName, WebKitWebPage* page) override
+ {
+ if (!strcmp(testName, "selection-changed")) {
+ bool selectionChanged = false;
+
+ WebKitWebEditor* editor = webkit_web_page_get_editor(page);
+ g_assert(WEBKIT_IS_WEB_EDITOR(editor));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(editor));
+ g_signal_connect_swapped(editor, "selection-changed", G_CALLBACK(selectionChangedCallback), &selectionChanged);
+
+ testSelectionSelectAll(page);
+ g_assert(selectionChanged);
+
+ selectionChanged = false;
+ testSelectionCollapse(page);
+ g_assert(selectionChanged);
+
+ selectionChanged = false;
+ testSelectionModifyMove(page);
+ g_assert(selectionChanged);
+
+ selectionChanged = false;
+ testSelectionModifyExtend(page);
+ g_assert(selectionChanged);
+
+ selectionChanged = false;
+ testSelectionUnselect(page);
+ g_assert(selectionChanged);
+
+ return true;
+ }
+
+ g_assert_not_reached();
+ return false;
+ }
+};
+
+static void __attribute__((constructor)) registerTests()
+{
+ REGISTER_TEST(WebKitWebEditorTest, "WebKitWebEditor/selection-changed");
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/FrameTest.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/FrameTest.cpp
index b9c86365b..a32d3e52f 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/FrameTest.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/FrameTest.cpp
@@ -32,6 +32,7 @@ private:
{
WebKitFrame* frame = webkit_web_page_get_main_frame(page);
g_assert(WEBKIT_IS_FRAME(frame));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(frame));
g_assert(webkit_frame_is_main_frame(frame));
return true;
@@ -41,6 +42,7 @@ private:
{
WebKitFrame* frame = webkit_web_page_get_main_frame(page);
g_assert(WEBKIT_IS_FRAME(frame));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(frame));
g_assert_cmpstr(webkit_web_page_get_uri(page), ==, webkit_frame_get_uri(frame));
return true;
@@ -50,6 +52,7 @@ private:
{
WebKitFrame* frame = webkit_web_page_get_main_frame(page);
g_assert(WEBKIT_IS_FRAME(frame));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(frame));
g_assert(webkit_frame_get_javascript_global_context(frame));
return true;
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestAuthentication.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestAuthentication.cpp
index ede422556..9cd9f5e7a 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestAuthentication.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestAuthentication.cpp
@@ -20,7 +20,7 @@
#include "config.h"
#include "LoadTrackingTest.h"
#include "WebKitTestServer.h"
-#include <wtf/gobject/GRefPtr.h>
+#include <wtf/glib/GRefPtr.h>
static WebKitTestServer* kServer;
@@ -187,7 +187,9 @@ static void testWebViewAuthenticationNoCredential(AuthenticationTest* test, gcon
static void testWebViewAuthenticationStorage(AuthenticationTest* test, gconstpointer)
{
// Enable private browsing before authentication request to test that credentials can't be saved.
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
webkit_settings_set_enable_private_browsing(webkit_web_view_get_settings(test->m_webView), TRUE);
+ G_GNUC_END_IGNORE_DEPRECATIONS;
test->loadURI(kServer->getURIForPath("/auth-test.html").data());
WebKitAuthenticationRequest* request = test->waitForAuthenticationRequest();
g_assert(!webkit_authentication_request_get_proposed_credential(request));
@@ -195,8 +197,10 @@ static void testWebViewAuthenticationStorage(AuthenticationTest* test, gconstpoi
// If WebKit has been compiled with libsecret, and private browsing is disabled
// then check that credentials can be saved.
-#if ENABLE(CREDENTIAL_STORAGE)
+#if USE(LIBSECRET)
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
webkit_settings_set_enable_private_browsing(webkit_web_view_get_settings(test->m_webView), FALSE);
+ G_GNUC_END_IGNORE_DEPRECATIONS;
test->loadURI(kServer->getURIForPath("/auth-test.html").data());
request = test->waitForAuthenticationRequest();
g_assert(!webkit_authentication_request_get_proposed_credential(request));
@@ -232,6 +236,22 @@ static void testWebViewAuthenticationSuccess(AuthenticationTest* test, gconstpoi
g_assert_cmpstr(webkit_web_view_get_title(test->m_webView), ==, authExpectedSuccessTitle);
}
+static void testWebViewAuthenticationEmptyRealm(AuthenticationTest* test, gconstpointer)
+{
+ test->loadURI(kServer->getURIForPath("/empty-realm.html").data());
+ WebKitAuthenticationRequest* request = test->waitForAuthenticationRequest();
+ WebKitCredential* credential = webkit_credential_new(authTestUsername, authTestPassword, WEBKIT_CREDENTIAL_PERSISTENCE_FOR_SESSION);
+ webkit_authentication_request_authenticate(request, credential);
+ webkit_credential_free(credential);
+ test->waitUntilLoadFinished();
+
+ g_assert_cmpint(test->m_loadEvents.size(), ==, 3);
+ g_assert_cmpint(test->m_loadEvents[0], ==, LoadTrackingTest::ProvisionalLoadStarted);
+ g_assert_cmpint(test->m_loadEvents[1], ==, LoadTrackingTest::LoadCommitted);
+ g_assert_cmpint(test->m_loadEvents[2], ==, LoadTrackingTest::LoadFinished);
+ g_assert_cmpstr(webkit_web_view_get_title(test->m_webView), ==, authExpectedSuccessTitle);
+}
+
static void serverCallback(SoupServer*, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, void*)
{
if (message->method != SOUP_METHOD_GET) {
@@ -239,7 +259,7 @@ static void serverCallback(SoupServer*, SoupMessage* message, const char* path,
return;
}
- if (!strcmp(path, "/auth-test.html")) {
+ if (!strcmp(path, "/auth-test.html") || !strcmp(path, "/empty-realm.html")) {
const char* authorization = soup_message_headers_get_one(message->request_headers, "Authorization");
// Require authentication.
if (!g_strcmp0(authorization, authExpectedAuthorization)) {
@@ -250,7 +270,10 @@ static void serverCallback(SoupServer*, SoupMessage* message, const char* path,
} else if (++AuthenticationTest::authenticationRetries < 3) {
// No or invalid authorization header provided by the client, request authentication twice then fail.
soup_message_set_status(message, SOUP_STATUS_UNAUTHORIZED);
- soup_message_headers_append(message->response_headers, "WWW-Authenticate", "Basic realm=\"my realm\"");
+ if (!strcmp(path, "/empty-realm.html"))
+ soup_message_headers_append(message->response_headers, "WWW-Authenticate", "Basic");
+ else
+ soup_message_headers_append(message->response_headers, "WWW-Authenticate", "Basic realm=\"my realm\"");
// Include a failure message in case the user attempts to proceed without authentication.
soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, authFailureHTMLString, strlen(authFailureHTMLString));
} else {
@@ -272,12 +295,11 @@ void beforeAll()
AuthenticationTest::add("WebKitWebView", "authentication-request", testWebViewAuthenticationRequest);
AuthenticationTest::add("WebKitWebView", "authentication-cancel", testWebViewAuthenticationCancel);
AuthenticationTest::add("WebKitWebView", "authentication-load-cancelled", testWebViewAuthenticationLoadCancelled);
+ AuthenticationTest::add("WebKitWebView", "authentication-success", testWebViewAuthenticationSuccess);
AuthenticationTest::add("WebKitWebView", "authentication-failure", testWebViewAuthenticationFailure);
AuthenticationTest::add("WebKitWebView", "authentication-no-credential", testWebViewAuthenticationNoCredential);
AuthenticationTest::add("WebKitWebView", "authentication-storage", testWebViewAuthenticationStorage);
- // Testing authentication success must be done last because libsoup will never fire
- // the authenticate signal again once authentication is successful.
- AuthenticationTest::add("WebKitWebView", "authentication-success", testWebViewAuthenticationSuccess);
+ AuthenticationTest::add("WebKitWebView", "authentication-empty-realm", testWebViewAuthenticationEmptyRealm);
}
void afterAll()
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestAutocleanups.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestAutocleanups.cpp
new file mode 100644
index 000000000..975688ced
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestAutocleanups.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2015 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include "WebViewTest.h"
+#include <webkit2/webkit2.h>
+
+#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
+
+static void testUIProcessAutocleanups(WebViewTest* test, gconstpointer)
+{
+ // Sanity-check a couple UI process API autocleanups that are easy to test....
+ g_autoptr(WebKitWebContext) context = webkit_web_context_new();
+ g_assert(WEBKIT_IS_WEB_CONTEXT(context));
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(context));
+
+ g_autoptr(WebKitWebsiteDataManager) manager = webkit_website_data_manager_new(nullptr);
+ g_assert(WEBKIT_IS_WEBSITE_DATA_MANAGER(manager));
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(context));
+
+ g_autoptr(WebKitUserScript) userScript = webkit_user_script_new("",
+ WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES, WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START,
+ nullptr, nullptr);
+ g_assert(userScript);
+ // Not a GObject, so just checking that this doesn't crash....
+}
+
+static void testWebProcessAutocleanups(WebViewTest* test, gconstpointer)
+{
+ static const char* testHTML = "<html><body></body></html>";
+ test->loadHtml(testHTML, nullptr);
+ test->waitUntilLoadFinished();
+
+ g_assert(test->runWebProcessTest("Autocleanups", "web-process-autocleanups"));
+}
+
+void beforeAll()
+{
+ WebViewTest::add("Autocleanups", "ui-process-autocleanups", testUIProcessAutocleanups);
+ WebViewTest::add("Autocleanups", "web-process-autocleanups", testWebProcessAutocleanups);
+}
+
+#else
+
+void beforeAll()
+{
+}
+
+#endif // G_DEFINE_AUTOPTR_CLEANUP_FUNC
+
+void afterAll()
+{
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestBackForwardList.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestBackForwardList.cpp
index 65c3d2d7c..fd2fbf5f2 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestBackForwardList.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestBackForwardList.cpp
@@ -264,6 +264,140 @@ static void testBackForwardListLimitAndCache(BackForwardListTest* test, gconstpo
g_assert_cmpuint(webkit_back_forward_list_get_length(test->m_list), ==, kBackForwardListLimit);
}
+static void testWebKitWebViewSessionState(BackForwardListTest* test, gconstpointer)
+{
+ WebKitWebViewSessionState* state = webkit_web_view_get_session_state(test->m_webView);
+ g_assert(state);
+ GRefPtr<WebKitWebView> view = WEBKIT_WEB_VIEW(webkit_web_view_new());
+ WebKitBackForwardList* bfList = webkit_web_view_get_back_forward_list(view.get());
+ g_assert_cmpuint(webkit_back_forward_list_get_length(bfList), ==, 0);
+ webkit_web_view_restore_session_state(view.get(), state);
+ g_assert_cmpuint(webkit_back_forward_list_get_length(bfList), ==, 0);
+ GRefPtr<GBytes> data = adoptGRef(webkit_web_view_session_state_serialize(state));
+ g_assert(data);
+ state = webkit_web_view_session_state_new(data.get());
+ g_assert(state);
+ view = WEBKIT_WEB_VIEW(webkit_web_view_new());
+ bfList = webkit_web_view_get_back_forward_list(view.get());
+ g_assert_cmpuint(webkit_back_forward_list_get_length(bfList), ==, 0);
+ webkit_web_view_restore_session_state(view.get(), state);
+ g_assert_cmpuint(webkit_back_forward_list_get_length(bfList), ==, 0);
+ webkit_web_view_session_state_unref(state);
+
+ CString uriPage1 = kServer->getURIForPath("/Page1");
+ test->m_changedFlags = BackForwardListTest::CurrentItem | BackForwardListTest::AddedItem;
+ test->loadURI(uriPage1.data());
+ test->waitUntilLoadFinished();
+
+ CString uriPage2 = kServer->getURIForPath("/Page2");
+ test->m_changedFlags = BackForwardListTest::CurrentItem | BackForwardListTest::AddedItem;
+ test->loadURI(uriPage2.data());
+ test->waitUntilLoadFinished();
+
+ CString uriPage3 = kServer->getURIForPath("/Page3");
+ test->m_changedFlags = BackForwardListTest::CurrentItem | BackForwardListTest::AddedItem;
+ test->loadURI(uriPage3.data());
+ test->waitUntilLoadFinished();
+
+ test->m_changedFlags = BackForwardListTest::CurrentItem;
+ test->goBack();
+ test->waitUntilLoadFinished();
+
+ state = webkit_web_view_get_session_state(test->m_webView);
+ g_assert(state);
+
+ g_assert_cmpuint(webkit_back_forward_list_get_length(bfList), ==, 0);
+ webkit_web_view_restore_session_state(view.get(), state);
+ g_assert_cmpuint(webkit_back_forward_list_get_length(bfList), ==, 3);
+
+ BackForwardListTest::checkItem(webkit_back_forward_list_get_nth_item(bfList, -1), "Page1", uriPage1.data(), uriPage1.data());
+ BackForwardListTest::checkItem(webkit_back_forward_list_get_current_item(bfList), "Page2", uriPage2.data(), uriPage2.data());
+ BackForwardListTest::checkItem(webkit_back_forward_list_get_nth_item(bfList, 1), "Page3", uriPage3.data(), uriPage3.data());
+
+ data = adoptGRef(webkit_web_view_session_state_serialize(state));
+ g_assert(data);
+ webkit_web_view_session_state_unref(state);
+ state = webkit_web_view_session_state_new(data.get());
+ g_assert(state);
+
+ view = WEBKIT_WEB_VIEW(webkit_web_view_new());
+ bfList = webkit_web_view_get_back_forward_list(view.get());
+ g_assert_cmpuint(webkit_back_forward_list_get_length(bfList), ==, 0);
+ webkit_web_view_restore_session_state(view.get(), state);
+ g_assert_cmpuint(webkit_back_forward_list_get_length(bfList), ==, 3);
+ webkit_web_view_session_state_unref(state);
+
+ BackForwardListTest::checkItem(webkit_back_forward_list_get_nth_item(bfList, -1), "Page1", uriPage1.data(), uriPage1.data());
+ BackForwardListTest::checkItem(webkit_back_forward_list_get_current_item(bfList), "Page2", uriPage2.data(), uriPage2.data());
+ BackForwardListTest::checkItem(webkit_back_forward_list_get_nth_item(bfList, 1), "Page3", uriPage3.data(), uriPage3.data());
+
+ static const char* invalidSessionData = "invalid session data";
+ data = adoptGRef(g_bytes_new_static(invalidSessionData, strlen(invalidSessionData)));
+ g_assert(!webkit_web_view_session_state_new(data.get()));
+}
+
+static void testWebKitWebViewSessionStateWithFormData(BackForwardListTest* test, gconstpointer)
+{
+ GUniquePtr<char> htmlPath(g_build_filename(Test::getResourcesDir(Test::WebKit2Resources).data(), "simple-form.html", nullptr));
+ GUniquePtr<char> htmlURL(g_filename_to_uri(htmlPath.get(), nullptr, nullptr));
+ test->m_changedFlags = BackForwardListTest::CurrentItem | BackForwardListTest::AddedItem;
+ test->loadURI(htmlURL.get());
+ test->waitUntilLoadFinished();
+
+ webkit_web_view_run_javascript(test->m_webView, "submitForm();", nullptr, nullptr, nullptr);
+ test->waitUntilLoadFinished();
+
+ WebKitWebViewSessionState* state = webkit_web_view_get_session_state(test->m_webView);
+ g_assert(state);
+ GRefPtr<WebKitWebView> view = WEBKIT_WEB_VIEW(webkit_web_view_new());
+ WebKitBackForwardList* bfList = webkit_web_view_get_back_forward_list(view.get());
+ g_assert_cmpuint(webkit_back_forward_list_get_length(bfList), ==, 0);
+ webkit_web_view_restore_session_state(view.get(), state);
+ g_assert_cmpuint(webkit_back_forward_list_get_length(bfList), ==, 2);
+ GRefPtr<GBytes> data = adoptGRef(webkit_web_view_session_state_serialize(state));
+ g_assert(data);
+ state = webkit_web_view_session_state_new(data.get());
+ g_assert(state);
+ view = WEBKIT_WEB_VIEW(webkit_web_view_new());
+ bfList = webkit_web_view_get_back_forward_list(view.get());
+ g_assert_cmpuint(webkit_back_forward_list_get_length(bfList), ==, 0);
+ webkit_web_view_restore_session_state(view.get(), state);
+ g_assert_cmpuint(webkit_back_forward_list_get_length(bfList), ==, 2);
+ webkit_web_view_session_state_unref(state);
+}
+
+static void viewLoadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent, GMainLoop* mainLoop)
+{
+ if (loadEvent == WEBKIT_LOAD_FINISHED)
+ g_main_loop_quit(mainLoop);
+}
+
+static void testWebKitWebViewNavigationAfterSessionRestore(BackForwardListTest* test, gconstpointer)
+{
+ // This test checks that a normal load after a session restore with a BackForard list having
+ // forward items doesn't produce any runtime critical warning. See https://bugs.webkit.org/show_bug.cgi?id=153233.
+ GRefPtr<WebKitWebView> view = WEBKIT_WEB_VIEW(webkit_web_view_new());
+ g_signal_connect(view.get(), "load-changed", G_CALLBACK(viewLoadChanged), test->m_mainLoop);
+
+ webkit_web_view_load_uri(view.get(), kServer->getURIForPath("/Page1").data());
+ g_main_loop_run(test->m_mainLoop);
+ webkit_web_view_load_uri(view.get(), kServer->getURIForPath("/Page2").data());
+ g_main_loop_run(test->m_mainLoop);
+ webkit_web_view_load_uri(view.get(), kServer->getURIForPath("/Page3").data());
+ g_main_loop_run(test->m_mainLoop);
+ webkit_web_view_go_back(view.get());
+ g_main_loop_run(test->m_mainLoop);
+
+ WebKitWebViewSessionState* state = webkit_web_view_get_session_state(view.get());
+ webkit_web_view_restore_session_state(test->m_webView, state);
+ webkit_web_view_session_state_unref(state);
+
+ // A normal load after a session restore should remove the forward list, add the new item and update the current one.
+ test->m_changedFlags = BackForwardListTest::CurrentItem | BackForwardListTest::AddedItem | BackForwardListTest::RemovedItems;
+ test->loadURI(kServer->getURIForPath("/Page4").data());
+ test->waitUntilLoadFinished();
+}
+
void beforeAll()
{
kServer = new WebKitTestServer();
@@ -271,6 +405,9 @@ void beforeAll()
BackForwardListTest::add("BackForwardList", "navigation", testBackForwardListNavigation);
BackForwardListTest::add("BackForwardList", "list-limit-and-cache", testBackForwardListLimitAndCache);
+ BackForwardListTest::add("WebKitWebView", "session-state", testWebKitWebViewSessionState);
+ BackForwardListTest::add("WebKitWebView", "session-state-with-form-data", testWebKitWebViewSessionStateWithFormData);
+ BackForwardListTest::add("WebKitWebView", "navigation-after-session-restore", testWebKitWebViewNavigationAfterSessionRestore);
}
void afterAll()
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestConsoleMessage.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestConsoleMessage.cpp
new file mode 100644
index 000000000..2595a8a42
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestConsoleMessage.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2015 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2,1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include "WebViewTest.h"
+#include <gtk/gtk.h>
+#include <webkit2/webkit2.h>
+
+class ConsoleMessageTest : public WebViewTest {
+public:
+ MAKE_GLIB_TEST_FIXTURE(ConsoleMessageTest);
+
+ // This should be keep in sync with the public enums in WebKitConsoleMessage.h.
+ enum class MessageSource { JavaScript, Network, ConsoleAPI, Security, Other };
+ enum class MessageLevel { Info, Log, Warning, Error, Debug };
+ struct ConsoleMessage {
+ bool operator==(const ConsoleMessage& other)
+ {
+ return source == other.source
+ && level == other.level
+ && message == other.message
+ && lineNumber == other.lineNumber
+ && sourceID == other.sourceID;
+ }
+
+ MessageSource source;
+ MessageLevel level;
+ CString message;
+ unsigned lineNumber;
+ CString sourceID;
+ };
+
+ static void consoleMessageReceivedCallback(WebKitUserContentManager*, WebKitJavascriptResult* message, ConsoleMessageTest* test)
+ {
+ g_assert(message);
+ GUniquePtr<char> messageString(WebViewTest::javascriptResultToCString(message));
+ GRefPtr<GVariant> variant = g_variant_parse(G_VARIANT_TYPE("(uusus)"), messageString.get(), nullptr, nullptr, nullptr);
+ g_assert(variant.get());
+
+ unsigned source, level, lineNumber;
+ const char* messageText;
+ const char* sourceID;
+ g_variant_get(variant.get(), "(uu&su&s)", &source, &level, &messageText, &lineNumber, &sourceID);
+ test->m_consoleMessage = { static_cast<ConsoleMessageTest::MessageSource>(source), static_cast<ConsoleMessageTest::MessageLevel>(level), messageText, lineNumber, sourceID };
+
+ g_main_loop_quit(test->m_mainLoop);
+ }
+
+ ConsoleMessageTest()
+ {
+ webkit_user_content_manager_register_script_message_handler(m_userContentManager.get(), "console");
+ g_signal_connect(m_userContentManager.get(), "script-message-received::console", G_CALLBACK(consoleMessageReceivedCallback), this);
+ }
+
+ ~ConsoleMessageTest()
+ {
+ g_signal_handlers_disconnect_matched(m_userContentManager.get(), G_SIGNAL_MATCH_DATA, 0, 0, nullptr, nullptr, this);
+ webkit_user_content_manager_unregister_script_message_handler(m_userContentManager.get(), "console");
+ }
+
+ void waitUntilConsoleMessageReceived()
+ {
+ g_main_loop_run(m_mainLoop);
+ }
+
+ ConsoleMessage m_consoleMessage;
+};
+
+static void testWebKitConsoleMessageConsoleAPI(ConsoleMessageTest* test, gconstpointer)
+{
+ ConsoleMessageTest::ConsoleMessage referenceMessage = { ConsoleMessageTest::MessageSource::ConsoleAPI, ConsoleMessageTest::MessageLevel::Log, "Log Console Message", 1, "http://foo.com/bar" };
+ test->loadHtml("<html><body onload='console.log(\"Log Console Message\");'></body></html>", "http://foo.com/bar");
+ test->waitUntilConsoleMessageReceived();
+ g_assert(test->m_consoleMessage == referenceMessage);
+
+ referenceMessage.level = ConsoleMessageTest::MessageLevel::Info;
+ referenceMessage.message = "Info Console Message";
+ test->loadHtml("<html><body onload='console.info(\"Info Console Message\");'></body></html>", "http://foo.com/bar");
+ test->waitUntilConsoleMessageReceived();
+ g_assert(test->m_consoleMessage == referenceMessage);
+
+ referenceMessage.level = ConsoleMessageTest::MessageLevel::Warning;
+ referenceMessage.message = "Warning Console Message";
+ test->loadHtml("<html><body onload='console.warn(\"Warning Console Message\");'></body></html>", "http://foo.com/bar");
+ test->waitUntilConsoleMessageReceived();
+ g_assert(test->m_consoleMessage == referenceMessage);
+
+ referenceMessage.level = ConsoleMessageTest::MessageLevel::Error;
+ referenceMessage.message = "Error Console Message";
+ test->loadHtml("<html><body onload='console.error(\"Error Console Message\");'></body></html>", "http://foo.com/bar");
+ test->waitUntilConsoleMessageReceived();
+ g_assert(test->m_consoleMessage == referenceMessage);
+
+ referenceMessage.level = ConsoleMessageTest::MessageLevel::Debug;
+ referenceMessage.message = "Debug Console Message";
+ test->loadHtml("<html><body onload='console.debug(\"Debug Console Message\");'></body></html>", "http://foo.com/bar");
+ test->waitUntilConsoleMessageReceived();
+ g_assert(test->m_consoleMessage == referenceMessage);
+}
+
+static void testWebKitConsoleMessageJavaScriptException(ConsoleMessageTest* test, gconstpointer)
+{
+ ConsoleMessageTest::ConsoleMessage referenceMessage = { ConsoleMessageTest::MessageSource::JavaScript, ConsoleMessageTest::MessageLevel::Error,
+ "ReferenceError: Can't find variable: foo", 1, "http://foo.com/bar" };
+ test->loadHtml("<html><body onload='foo()'></body></html>", "http://foo.com/bar");
+ test->waitUntilConsoleMessageReceived();
+ g_assert(test->m_consoleMessage == referenceMessage);
+}
+
+static void testWebKitConsoleMessageNetworkError(ConsoleMessageTest* test, gconstpointer)
+{
+ ConsoleMessageTest::ConsoleMessage referenceMessage = { ConsoleMessageTest::MessageSource::Network, ConsoleMessageTest::MessageLevel::Error,
+ "Failed to load resource: The resource at '/org/webkit/webkit2gtk/tests/not-found.css' does not exist", 0, "resource:///org/webkit/webkit2gtk/tests/not-found.css" };
+ test->loadHtml("<html><head><link rel='stylesheet' href='not-found.css' type='text/css'></head><body></body></html>", "resource:///org/webkit/webkit2gtk/tests/");
+ test->waitUntilConsoleMessageReceived();
+ g_assert(test->m_consoleMessage == referenceMessage);
+}
+
+static void testWebKitConsoleMessageSecurityError(ConsoleMessageTest* test, gconstpointer)
+{
+ ConsoleMessageTest::ConsoleMessage referenceMessage = { ConsoleMessageTest::MessageSource::Security, ConsoleMessageTest::MessageLevel::Error,
+ "Not allowed to load local resource: file:///foo/bar/source.png", 1, "http://foo.com/bar" };
+ test->loadHtml("<html><body><img src=\"file:///foo/bar/source.png\"/></body></html>", "http://foo.com/bar");
+ test->waitUntilConsoleMessageReceived();
+ g_assert(test->m_consoleMessage == referenceMessage);
+}
+
+void beforeAll()
+{
+ ConsoleMessageTest::add("WebKitConsoleMessage", "console-api", testWebKitConsoleMessageConsoleAPI);
+ ConsoleMessageTest::add("WebKitConsoleMessage", "js-exception", testWebKitConsoleMessageJavaScriptException);
+ ConsoleMessageTest::add("WebKitConsoleMessage", "network-error", testWebKitConsoleMessageNetworkError);
+ ConsoleMessageTest::add("WebKitConsoleMessage", "security-error", testWebKitConsoleMessageSecurityError);
+}
+
+void afterAll()
+{
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestContextMenu.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestContextMenu.cpp
index a91e78741..3d7ab00cc 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestContextMenu.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestContextMenu.cpp
@@ -19,7 +19,8 @@
#include "config.h"
#include "WebViewTest.h"
-#include <wtf/gobject/GRefPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/glib/GRefPtr.h>
class ContextMenuTest: public WebViewTest {
public:
@@ -32,10 +33,24 @@ public:
void checkContextMenuEvent(GdkEvent* event)
{
g_assert(event);
- g_assert_cmpint(event->type, ==, GDK_BUTTON_PRESS);
- g_assert_cmpint(event->button.button, ==, 3);
- g_assert_cmpint(event->button.x, ==, m_menuPositionX);
- g_assert_cmpint(event->button.y, ==, m_menuPositionY);
+ g_assert_cmpint(event->type, ==, m_expectedEventType);
+
+ switch (m_expectedEventType) {
+ case GDK_BUTTON_PRESS:
+ g_assert_cmpint(event->button.button, ==, 3);
+ g_assert_cmpint(event->button.x, ==, m_menuPositionX);
+ g_assert_cmpint(event->button.y, ==, m_menuPositionY);
+ break;
+ case GDK_KEY_PRESS:
+ g_assert_cmpint(event->key.keyval, ==, GDK_KEY_Menu);
+ break;
+ case GDK_NOTHING:
+ // GDK_NOTHING means that the context menu was triggered by the
+ // popup-menu signal. We don't have anything to check here.
+ break;
+ default:
+ g_assert_not_reached();
+ }
}
static gboolean contextMenuCallback(WebKitWebView* webView, WebKitContextMenu* contextMenu, GdkEvent* event, WebKitHitTestResult* hitTestResult, ContextMenuTest* test)
@@ -57,6 +72,7 @@ public:
ContextMenuTest()
: m_menuPositionX(0)
, m_menuPositionY(0)
+ , m_expectedEventType(GDK_BUTTON_PRESS)
{
g_signal_connect(m_webView, "context-menu", G_CALLBACK(contextMenuCallback), this);
g_signal_connect(m_webView, "context-menu-dismissed", G_CALLBACK(contextMenuDismissedCallback), this);
@@ -92,17 +108,6 @@ public:
return 0;
}
- bool shouldShowInputMethodsMenu()
- {
- GtkSettings* settings = gtk_widget_get_settings(GTK_WIDGET(m_webView));
- if (!settings)
- return true;
-
- gboolean showInputMethodMenu;
- g_object_get(settings, "gtk-show-input-method-menu", &showInputMethodMenu, NULL);
- return showInputMethodMenu;
- }
-
void checkActionState(GtkAction* action, unsigned state)
{
if (state & Visible)
@@ -209,6 +214,7 @@ public:
void showContextMenuAndWaitUntilFinished()
{
+ m_expectedEventType = GDK_BUTTON_PRESS;
showContextMenuAtPositionAndWaitUntilFinished(0, 0);
}
@@ -224,8 +230,35 @@ public:
g_main_loop_run(m_mainLoop);
}
+ static gboolean emitPopupMenuSignalIdleCallback(ContextMenuTest* test)
+ {
+ test->emitPopupMenuSignal();
+ return FALSE;
+ }
+
+ void showContextMenuTriggeredByPopupEventAndWaitUntilFinished()
+ {
+ m_expectedEventType = GDK_NOTHING;
+ g_idle_add(reinterpret_cast<GSourceFunc>(emitPopupMenuSignalIdleCallback), this);
+ g_main_loop_run(m_mainLoop);
+ }
+
+ static gboolean simulateMenuKeyIdleCallback(ContextMenuTest* test)
+ {
+ test->keyStroke(GDK_KEY_Menu);
+ return FALSE;
+ }
+
+ void showContextMenuTriggeredByContextMenuKeyAndWaitUntilFinished()
+ {
+ m_expectedEventType = GDK_KEY_PRESS;
+ g_idle_add(reinterpret_cast<GSourceFunc>(simulateMenuKeyIdleCallback), this);
+ g_main_loop_run(m_mainLoop);
+ }
+
double m_menuPositionX;
double m_menuPositionY;
+ GdkEventType m_expectedEventType;
};
class ContextMenuDefaultTest: public ContextMenuTest {
@@ -239,7 +272,8 @@ public:
LinkImage,
Video,
Audio,
- Editable
+ Editable,
+ Selection
};
ContextMenuDefaultTest()
@@ -257,6 +291,7 @@ public:
g_assert(!webkit_hit_test_result_context_is_image(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_media(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult));
+ g_assert(!webkit_hit_test_result_context_is_selection(hitTestResult));
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_GO_BACK, Visible);
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_GO_FORWARD, Visible);
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_STOP, Visible);
@@ -267,6 +302,7 @@ public:
g_assert(!webkit_hit_test_result_context_is_image(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_media(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult));
+ g_assert(!webkit_hit_test_result_context_is_selection(hitTestResult));
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK, Visible | Enabled);
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK_IN_NEW_WINDOW, Visible | Enabled);
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_LINK_TO_DISK, Visible | Enabled);
@@ -277,6 +313,7 @@ public:
g_assert(webkit_hit_test_result_context_is_image(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_media(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult));
+ g_assert(!webkit_hit_test_result_context_is_selection(hitTestResult));
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_OPEN_IMAGE_IN_NEW_WINDOW, Visible | Enabled);
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_IMAGE_TO_DISK, Visible | Enabled);
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_TO_CLIPBOARD, Visible | Enabled);
@@ -287,6 +324,7 @@ public:
g_assert(webkit_hit_test_result_context_is_image(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_media(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult));
+ g_assert(!webkit_hit_test_result_context_is_selection(hitTestResult));
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK, Visible | Enabled);
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK_IN_NEW_WINDOW, Visible | Enabled);
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_LINK_TO_DISK, Visible | Enabled);
@@ -302,6 +340,7 @@ public:
g_assert(!webkit_hit_test_result_context_is_image(hitTestResult));
g_assert(webkit_hit_test_result_context_is_media(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult));
+ g_assert(!webkit_hit_test_result_context_is_selection(hitTestResult));
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_MEDIA_PLAY, Visible | Enabled);
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_MEDIA_MUTE, Visible);
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_TOGGLE_MEDIA_CONTROLS, Visible | Enabled | Checked);
@@ -317,6 +356,7 @@ public:
g_assert(!webkit_hit_test_result_context_is_image(hitTestResult));
g_assert(webkit_hit_test_result_context_is_media(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult));
+ g_assert(!webkit_hit_test_result_context_is_selection(hitTestResult));
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_MEDIA_PLAY, Visible | Enabled);
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_MEDIA_MUTE, Visible);
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_TOGGLE_MEDIA_CONTROLS, Visible | Enabled | Checked);
@@ -332,6 +372,7 @@ public:
g_assert(!webkit_hit_test_result_context_is_image(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_media(hitTestResult));
g_assert(webkit_hit_test_result_context_is_editable(hitTestResult));
+ g_assert(!webkit_hit_test_result_context_is_selection(hitTestResult));
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_CUT, Visible);
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY, Visible);
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_PASTE, Visible | Enabled);
@@ -339,10 +380,16 @@ public:
iter = checkCurrentItemIsSeparatorAndGetNext(iter);
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_SELECT_ALL, Visible | Enabled);
iter = checkCurrentItemIsSeparatorAndGetNext(iter);
- if (shouldShowInputMethodsMenu())
- iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_INPUT_METHODS, Visible | Enabled);
iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_UNICODE, Visible | Enabled);
break;
+ case Selection:
+ g_assert(!webkit_hit_test_result_context_is_link(hitTestResult));
+ g_assert(!webkit_hit_test_result_context_is_image(hitTestResult));
+ g_assert(!webkit_hit_test_result_context_is_media(hitTestResult));
+ g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult));
+ g_assert(webkit_hit_test_result_context_is_selection(hitTestResult));
+ iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY, Visible | Enabled);
+ break;
default:
g_assert_not_reached();
}
@@ -361,21 +408,39 @@ public:
DefaultMenuType m_expectedMenuType;
};
-static void testContextMenuDefaultMenu(ContextMenuDefaultTest* test, gconstpointer)
+static void prepareContextMenuTestView(ContextMenuDefaultTest* test)
{
- test->showInWindowAndWaitUntilMapped();
-
+ GUniquePtr<char> baseDir(g_strdup_printf("file://%s/", Test::getResourcesDir().data()));
const char* linksHTML =
"<html><body>"
" <a style='position:absolute; left:1; top:1' href='http://www.webkitgtk.org' title='WebKitGTK+ Title'>WebKitGTK+ Website</a>"
- " <img style='position:absolute; left:1; top:10' src='0xdeadbeef' width=5 height=5></img>"
- " <a style='position:absolute; left:1; top:20' href='http://www.webkitgtk.org/logo' title='WebKitGTK+ Logo'><img src='0xdeadbeef' width=5 height=5></img></a>"
+ " <img style='position:absolute; left:1; top:10' src='blank.ico' width=5 height=5></img>"
+ " <a style='position:absolute; left:1; top:20' href='http://www.webkitgtk.org/logo' title='WebKitGTK+ Logo'><img src='blank.ico' width=5 height=5></img></a>"
" <input style='position:absolute; left:1; top:30' size='10'></input>"
- " <video style='position:absolute; left:1; top:50' width='300' height='300' controls='controls' preload='none'><source src='movie.ogg' type='video/ogg' /></video>"
- " <audio style='position:absolute; left:1; top:60' width='50' height='20' controls='controls' preload='none'><source src='track.mp3' type='audio/mp3' /></audio>"
+ " <video style='position:absolute; left:1; top:50' width='300' height='300' controls='controls' preload='none'><source src='silence.mpg' type='video/mpeg' /></video>"
+ " <audio style='position:absolute; left:1; top:60' width='50' height='20' controls='controls' preload='none'><source src='track.ogg' type='audio/ogg' /></audio>"
+ " <p style='position:absolute; left:1; top:90' id='text_to_select'>Lorem ipsum.</p>"
+ " <script>"
+ " window.getSelection().removeAllRanges();"
+ " var select_range = document.createRange();"
+ " select_range.selectNodeContents(document.getElementById('text_to_select'));"
+ " window.getSelection().addRange(select_range);"
+ " </script>"
"</body></html>";
- test->loadHtml(linksHTML, "file:///");
+ test->loadHtml(linksHTML, baseDir.get());
test->waitUntilLoadFinished();
+}
+
+static void testContextMenuDefaultMenu(ContextMenuDefaultTest* test, gconstpointer)
+{
+ test->showInWindowAndWaitUntilMapped();
+
+ prepareContextMenuTestView(test);
+
+ // Context menu for selection.
+ // This test should always be the first because any other click removes the selection.
+ test->m_expectedMenuType = ContextMenuDefaultTest::Selection;
+ test->showContextMenuAtPositionAndWaitUntilFinished(2, 115);
// Context menu for document.
test->m_expectedMenuType = ContextMenuDefaultTest::Navigation;
@@ -410,6 +475,26 @@ static void testContextMenuDefaultMenu(ContextMenuDefaultTest* test, gconstpoint
test->showContextMenuAtPositionAndWaitUntilFinished(5, 35);
}
+static void testPopupEventSignal(ContextMenuDefaultTest* test, gconstpointer)
+{
+ test->showInWindowAndWaitUntilMapped();
+
+ prepareContextMenuTestView(test);
+
+ test->m_expectedMenuType = ContextMenuDefaultTest::Selection;
+ test->showContextMenuTriggeredByPopupEventAndWaitUntilFinished();
+}
+
+static void testContextMenuKey(ContextMenuDefaultTest* test, gconstpointer)
+{
+ test->showInWindowAndWaitUntilMapped();
+
+ prepareContextMenuTestView(test);
+
+ test->m_expectedMenuType = ContextMenuDefaultTest::Selection;
+ test->showContextMenuTriggeredByContextMenuKeyAndWaitUntilFinished();
+}
+
class ContextMenuCustomTest: public ContextMenuTest {
public:
MAKE_GLIB_TEST_FIXTURE(ContextMenuCustomTest);
@@ -742,124 +827,173 @@ static void testContextMenuDismissed(ContextMenuDismissedTest* test, gconstpoint
g_assert(test->m_dismissed);
}
-class ContextMenuSmartSeparatorsTest: public ContextMenuTest {
+class ContextMenuWebExtensionTest: public ContextMenuTest {
public:
- MAKE_GLIB_TEST_FIXTURE(ContextMenuSmartSeparatorsTest);
+ MAKE_GLIB_TEST_FIXTURE(ContextMenuWebExtensionTest);
- bool contextMenu(WebKitContextMenu* contextMenu, GdkEvent*, WebKitHitTestResult*)
+ void deserializeContextMenuFromUserData(GVariant* userData)
{
- webkit_context_menu_remove_all(contextMenu);
+ m_actions.clear();
+ if (!userData)
+ return;
- webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_separator());
- webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_separator());
- webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_from_stock_action(WEBKIT_CONTEXT_MENU_ACTION_GO_BACK));
- webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_from_stock_action(WEBKIT_CONTEXT_MENU_ACTION_GO_FORWARD));
- webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_separator());
- webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_separator());
- webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_from_stock_action(WEBKIT_CONTEXT_MENU_ACTION_COPY));
- webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_separator());
- webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_from_stock_action(WEBKIT_CONTEXT_MENU_ACTION_INSPECT_ELEMENT));
- webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_separator());
- webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_separator());
+ GVariantIter iter;
+ g_variant_iter_init(&iter, userData);
+ m_actions.reserveInitialCapacity(g_variant_iter_n_children(&iter));
+
+ uint32_t item;
+ while (g_variant_iter_next(&iter, "u", &item))
+ m_actions.uncheckedAppend(static_cast<WebKitContextMenuAction>(item));
+ }
+
+ bool contextMenu(WebKitContextMenu* menu, GdkEvent*, WebKitHitTestResult*)
+ {
+ deserializeContextMenuFromUserData(webkit_context_menu_get_user_data(menu));
+ GList* items = webkit_context_menu_get_items(menu);
+ g_assert_cmpuint(g_list_length(items), ==, m_actions.size());
+
+ unsigned actionIndex = 0;
+ for (GList* it = items; it; it = g_list_next(it)) {
+ WebKitContextMenuItem* item = WEBKIT_CONTEXT_MENU_ITEM(it->data);
+ g_assert_cmpuint(webkit_context_menu_item_get_stock_action(item), ==, m_actions[actionIndex++]);
+ }
quitMainLoop();
- return false;
+ return true;
+ }
+
+ Vector<WebKitContextMenuAction> m_actions;
+};
+
+static void testContextMenuWebExtensionMenu(ContextMenuWebExtensionTest* test, gconstpointer)
+{
+ test->showInWindowAndWaitUntilMapped();
+ test->loadHtml("<html><body>WebKitGTK+ Context menu tests<br>"
+ "<a style='position:absolute; left:1; top:10' href='http://www.webkitgtk.org'>WebKitGTK+ Website</a></body></html>",
+ "ContextMenuTestDefault");
+ test->waitUntilLoadFinished();
+
+ // Default context menu.
+ test->showContextMenuAtPositionAndWaitUntilFinished(1, 1);
+ g_assert_cmpuint(test->m_actions.size(), ==, 4);
+ g_assert_cmpuint(test->m_actions[0], ==, WEBKIT_CONTEXT_MENU_ACTION_GO_BACK);
+ g_assert_cmpuint(test->m_actions[1], ==, WEBKIT_CONTEXT_MENU_ACTION_GO_FORWARD);
+ g_assert_cmpuint(test->m_actions[2], ==, WEBKIT_CONTEXT_MENU_ACTION_STOP);
+ g_assert_cmpuint(test->m_actions[3], ==, WEBKIT_CONTEXT_MENU_ACTION_RELOAD);
+
+ // Link menu.
+ test->showContextMenuAtPositionAndWaitUntilFinished(1, 11);
+ g_assert_cmpuint(test->m_actions.size(), ==, 4);
+ g_assert_cmpuint(test->m_actions[0], ==, WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK);
+ g_assert_cmpuint(test->m_actions[1], ==, WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK_IN_NEW_WINDOW);
+ g_assert_cmpuint(test->m_actions[2], ==, WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_LINK_TO_DISK);
+ g_assert_cmpuint(test->m_actions[3], ==, WEBKIT_CONTEXT_MENU_ACTION_COPY_LINK_TO_CLIPBOARD);
+
+ // Custom menu.
+ test->loadHtml("<html><body></body></html>", "ContextMenuTestCustom");
+ test->showContextMenuAndWaitUntilFinished();
+ g_assert_cmpuint(test->m_actions.size(), ==, 4);
+ g_assert_cmpuint(test->m_actions[0], ==, WEBKIT_CONTEXT_MENU_ACTION_STOP);
+ g_assert_cmpuint(test->m_actions[1], ==, WEBKIT_CONTEXT_MENU_ACTION_RELOAD);
+ g_assert_cmpuint(test->m_actions[2], ==, WEBKIT_CONTEXT_MENU_ACTION_NO_ACTION);
+ g_assert_cmpuint(test->m_actions[3], ==, WEBKIT_CONTEXT_MENU_ACTION_INSPECT_ELEMENT);
+
+ // Menu cleared by the web process.
+ test->loadHtml("<html><body></body></html>", "ContextMenuTestClear");
+ test->showContextMenuAndWaitUntilFinished();
+ g_assert_cmpuint(test->m_actions.size(), ==, 0);
+}
+
+class ContextMenuWebExtensionNodeTest: public ContextMenuTest {
+public:
+ MAKE_GLIB_TEST_FIXTURE(ContextMenuWebExtensionNodeTest);
+
+ struct Node {
+ enum {
+ NodeUnknown = 0,
+ NodeElement = 1,
+ NodeText = 3
+ };
+ typedef unsigned Type;
+
+ CString name;
+ Type type;
+ CString contents;
+ CString parentName;
+ };
+
+ void deserializeNodeFromUserData(GVariant* userData)
+ {
+ GVariantIter iter;
+ g_variant_iter_init(&iter, userData);
+
+ const char* key;
+ GVariant* value;
+ while (g_variant_iter_next(&iter, "{&sv}", &key, &value)) {
+ if (!strcmp(key, "Name") && g_variant_classify(value) == G_VARIANT_CLASS_STRING)
+ m_node.name = g_variant_get_string(value, nullptr);
+ else if (!strcmp(key, "Type") && g_variant_classify(value) == G_VARIANT_CLASS_UINT32)
+ m_node.type = g_variant_get_uint32(value);
+ else if (!strcmp(key, "Contents") && g_variant_classify(value) == G_VARIANT_CLASS_STRING)
+ m_node.contents = g_variant_get_string(value, nullptr);
+ else if (!strcmp(key, "Parent") && g_variant_classify(value) == G_VARIANT_CLASS_STRING)
+ m_node.parentName = g_variant_get_string(value, nullptr);
+ g_variant_unref(value);
+ }
}
- GtkMenu* showContextMenuAndGetGtkMenu()
+ bool contextMenu(WebKitContextMenu* menu, GdkEvent*, WebKitHitTestResult*)
{
- showContextMenuAndWaitUntilFinished();
- return getPopupMenu();
+ deserializeNodeFromUserData(webkit_context_menu_get_user_data(menu));
+ quitMainLoop();
+
+ return true;
}
+
+ Node m_node;
};
-static void testContextMenuSmartSeparators(ContextMenuSmartSeparatorsTest* test, gconstpointer)
+static void testContextMenuWebExtensionNode(ContextMenuWebExtensionNodeTest* test, gconstpointer)
{
test->showInWindowAndWaitUntilMapped();
-
- test->loadHtml("<html><body>WebKitGTK+ Context menu tests</body></html>", "file:///");
+ test->loadHtml("<html><body><p style='position:absolute; left:1; top:1'>WebKitGTK+ Context menu tests</p><br>"
+ "<a style='position:absolute; left:1; top:100' href='http://www.webkitgtk.org'>WebKitGTK+ Website</a></body></html>",
+ "ContextMenuTestNode");
test->waitUntilLoadFinished();
- GtkMenu* menu = test->showContextMenuAndGetGtkMenu();
- g_assert(menu);
-
- // Leading and trailing separators are not added to the context menu.
- GUniquePtr<GList> menuItems(gtk_container_get_children(GTK_CONTAINER(menu)));
- g_assert_cmpuint(g_list_length(menuItems.get()), ==, 6);
- GtkWidget* item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 0));
- g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item));
- item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 1));
- g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item));
- item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 2));
- g_assert(GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item));
- item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 3));
- g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item));
- item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 4));
- g_assert(GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item));
- item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 5));
- g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item));
-
- // Hiding a menu item between two separators hides the following separator.
- GtkAction* action = gtk_activatable_get_related_action(GTK_ACTIVATABLE(g_list_nth_data(menuItems.get(), 3)));
- gtk_action_set_visible(action, FALSE);
- menuItems.reset(gtk_container_get_children(GTK_CONTAINER(menu)));
- g_assert_cmpuint(g_list_length(menuItems.get()), ==, 6);
- item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 0));
- g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item));
- item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 1));
- g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item));
- item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 2));
- g_assert(GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item));
- item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 3));
- g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && !gtk_widget_get_visible(item));
- item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 4));
- g_assert(GTK_IS_SEPARATOR_MENU_ITEM(item) && !gtk_widget_get_visible(item));
- item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 5));
- g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item));
- gtk_action_set_visible(action, TRUE);
-
- // Showing an action between two separators shows the hidden separator.
- item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 0));
- g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item));
- item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 1));
- g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item));
- item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 2));
- g_assert(GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item));
- item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 3));
- g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item));
- item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 4));
- g_assert(GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item));
- item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 5));
- g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item));
-
- // Trailing separators are hidden too.
- action = gtk_activatable_get_related_action(GTK_ACTIVATABLE(g_list_nth_data(menuItems.get(), 5)));
- gtk_action_set_visible(action, FALSE);
- menuItems.reset(gtk_container_get_children(GTK_CONTAINER(menu)));
- item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 0));
- g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item));
- item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 1));
- g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item));
- item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 2));
- g_assert(GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item));
- item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 3));
- g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item));
- item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 4));
- g_assert(GTK_IS_SEPARATOR_MENU_ITEM(item) && !gtk_widget_get_visible(item));
- item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 5));
- g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && !gtk_widget_get_visible(item));
+ test->showContextMenuAtPositionAndWaitUntilFinished(0, 0);
+ g_assert_cmpstr(test->m_node.name.data(), ==, "HTML");
+ g_assert_cmpuint(test->m_node.type, ==, ContextMenuWebExtensionNodeTest::Node::NodeElement);
+ g_assert_cmpstr(test->m_node.contents.data(), ==, "WebKitGTK+ Context menu testsWebKitGTK+ Website");
+ g_assert_cmpstr(test->m_node.parentName.data(), ==, "#document");
+
+ test->showContextMenuAtPositionAndWaitUntilFinished(1, 20);
+ g_assert_cmpstr(test->m_node.name.data(), ==, "#text");
+ g_assert_cmpuint(test->m_node.type, ==, ContextMenuWebExtensionNodeTest::Node::NodeText);
+ g_assert_cmpstr(test->m_node.contents.data(), ==, "WebKitGTK+ Context menu tests");
+ g_assert_cmpstr(test->m_node.parentName.data(), ==, "P");
+
+ // Link menu.
+ test->showContextMenuAtPositionAndWaitUntilFinished(1, 101);
+ g_assert_cmpstr(test->m_node.name.data(), ==, "#text");
+ g_assert_cmpuint(test->m_node.type, ==, ContextMenuWebExtensionNodeTest::Node::NodeText);
+ g_assert_cmpstr(test->m_node.contents.data(), ==, "WebKitGTK+ Website");
+ g_assert_cmpstr(test->m_node.parentName.data(), ==, "A");
}
void beforeAll()
{
ContextMenuDefaultTest::add("WebKitWebView", "default-menu", testContextMenuDefaultMenu);
+ ContextMenuDefaultTest::add("WebKitWebView", "context-menu-key", testContextMenuKey);
+ ContextMenuDefaultTest::add("WebKitWebView", "popup-event-signal", testPopupEventSignal);
ContextMenuCustomTest::add("WebKitWebView", "populate-menu", testContextMenuPopulateMenu);
ContextMenuCustomFullTest::add("WebKitWebView", "custom-menu", testContextMenuCustomMenu);
ContextMenuDisabledTest::add("WebKitWebView", "disable-menu", testContextMenuDisableMenu);
ContextMenuSubmenuTest::add("WebKitWebView", "submenu", testContextMenuSubMenu);
ContextMenuDismissedTest::add("WebKitWebView", "menu-dismissed", testContextMenuDismissed);
- ContextMenuSmartSeparatorsTest::add("WebKitWebView", "smart-separators", testContextMenuSmartSeparators);
+ ContextMenuWebExtensionTest::add("WebKitWebPage", "context-menu", testContextMenuWebExtensionMenu);
+ ContextMenuWebExtensionNodeTest::add("WebKitWebPage", "context-menu-node", testContextMenuWebExtensionNode);
}
void afterAll()
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestCookieManager.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestCookieManager.cpp
index 2e98645e8..4cd4b5c8c 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestCookieManager.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestCookieManager.cpp
@@ -24,7 +24,6 @@
#include <glib/gstdio.h>
static WebKitTestServer* kServer;
-static char* kTempDirectory;
static const char* kFirstPartyDomain = "127.0.0.1";
static const char* kThirdPartyDomain = "localhost";
@@ -53,6 +52,7 @@ public:
, m_cookiesChanged(false)
, m_finishLoopWhenCookiesChange(false)
{
+ g_assert(webkit_website_data_manager_get_cookie_manager(webkit_web_context_get_website_data_manager(webkit_web_view_get_context(m_webView))) == m_cookieManager);
g_signal_connect(m_cookieManager, "changed", G_CALLBACK(cookiesChangedCallback), this);
}
@@ -72,12 +72,12 @@ public:
switch (storage) {
case WEBKIT_COOKIE_PERSISTENT_STORAGE_TEXT:
if (!m_cookiesTextFile)
- m_cookiesTextFile.reset(g_build_filename(kTempDirectory, "cookies.txt", NULL));
+ m_cookiesTextFile.reset(g_build_filename(Test::dataDirectory(), "cookies.txt", nullptr));
filename = m_cookiesTextFile.get();
break;
case WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE:
if (!m_cookiesSQLiteFile)
- m_cookiesSQLiteFile.reset(g_build_filename(kTempDirectory, "cookies.db", NULL));
+ m_cookiesSQLiteFile.reset(g_build_filename(Test::dataDirectory(), "cookies.db", nullptr));
filename = m_cookiesSQLiteFile.get();
break;
default:
@@ -114,7 +114,9 @@ public:
static void getDomainsReadyCallback(GObject* object, GAsyncResult* result, gpointer userData)
{
GUniqueOutPtr<GError> error;
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
char** domains = webkit_cookie_manager_get_domains_with_cookies_finish(WEBKIT_COOKIE_MANAGER(object), result, &error.outPtr());
+ G_GNUC_END_IGNORE_DEPRECATIONS;
g_assert(!error.get());
CookieManagerTest* test = static_cast<CookieManagerTest*>(userData);
@@ -126,7 +128,9 @@ public:
{
g_strfreev(m_domains);
m_domains = 0;
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
webkit_cookie_manager_get_domains_with_cookies(m_cookieManager, 0, getDomainsReadyCallback, this);
+ G_GNUC_END_IGNORE_DEPRECATIONS;
g_main_loop_run(m_mainLoop);
return m_domains;
@@ -145,12 +149,16 @@ public:
void deleteCookiesForDomain(const char* domain)
{
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
webkit_cookie_manager_delete_cookies_for_domain(m_cookieManager, domain);
+ G_GNUC_END_IGNORE_DEPRECATIONS;
}
void deleteAllCookies()
{
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
webkit_cookie_manager_delete_all_cookies(m_cookieManager);
+ G_GNUC_END_IGNORE_DEPRECATIONS;
}
void waitUntilCookiesChanged()
@@ -291,6 +299,58 @@ static void testCookieManagerPersistentStorage(CookieManagerTest* test, gconstpo
g_assert_cmpint(g_strv_length(test->getDomains()), ==, 0);
}
+static void ephemeralViewloadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent, WebViewTest* test)
+{
+ if (loadEvent != WEBKIT_LOAD_FINISHED)
+ return;
+ g_signal_handlers_disconnect_by_func(webView, reinterpret_cast<void*>(ephemeralViewloadChanged), test);
+ test->quitMainLoop();
+}
+
+static void testCookieManagerEphemeral(CookieManagerTest* test, gconstpointer)
+{
+ test->setAcceptPolicy(WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS);
+ test->setPersistentStorage(WEBKIT_COOKIE_PERSISTENT_STORAGE_TEXT);
+ char** domains = test->getDomains();
+ g_assert(domains);
+ g_assert_cmpint(g_strv_length(domains), ==, 0);
+
+ GRefPtr<WebKitWebView> webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW,
+ "web-context", webkit_web_view_get_context(test->m_webView),
+ "is-ephemeral", TRUE,
+ nullptr));
+ g_assert(webkit_web_view_is_ephemeral(webView.get()));
+ g_assert(!webkit_web_context_is_ephemeral(webkit_web_view_get_context(webView.get())));
+
+ g_signal_connect(webView.get(), "load-changed", G_CALLBACK(ephemeralViewloadChanged), test);
+ webkit_web_view_load_uri(webView.get(), kServer->getURIForPath("/index.html").data());
+ g_main_loop_run(test->m_mainLoop);
+
+ domains = test->getDomains();
+ g_assert(domains);
+ g_assert_cmpint(g_strv_length(domains), ==, 0);
+
+ auto* viewDataManager = webkit_web_view_get_website_data_manager(webView.get());
+ g_assert(WEBKIT_IS_WEBSITE_DATA_MANAGER(viewDataManager));
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(viewDataManager));
+ g_assert(viewDataManager != webkit_web_context_get_website_data_manager(webkit_web_view_get_context(test->m_webView)));
+ auto* cookieManager = webkit_website_data_manager_get_cookie_manager(viewDataManager);
+ g_assert(WEBKIT_IS_COOKIE_MANAGER(cookieManager));
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(cookieManager));
+ g_assert(cookieManager != test->m_cookieManager);
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+ webkit_cookie_manager_get_domains_with_cookies(cookieManager, nullptr, [](GObject* object, GAsyncResult* result, gpointer userData) {
+ auto* test = static_cast<CookieManagerTest*>(userData);
+ GUniquePtr<char*> domains(webkit_cookie_manager_get_domains_with_cookies_finish(WEBKIT_COOKIE_MANAGER(object), result, nullptr));
+ g_assert(domains);
+ g_assert_cmpint(g_strv_length(domains.get()), ==, 1);
+ g_assert_cmpstr(domains.get()[0], ==, kFirstPartyDomain);
+ test->quitMainLoop();
+ }, test);
+ G_GNUC_END_IGNORE_DEPRECATIONS;
+ g_main_loop_run(test->m_mainLoop);
+}
+
static void serverCallback(SoupServer* server, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, gpointer)
{
if (message->method != SOUP_METHOD_GET) {
@@ -315,17 +375,14 @@ void beforeAll()
kServer = new WebKitTestServer();
kServer->run(serverCallback);
- kTempDirectory = g_dir_make_tmp("WebKit2Tests-XXXXXX", 0);
- g_assert(kTempDirectory);
-
CookieManagerTest::add("WebKitCookieManager", "accept-policy", testCookieManagerAcceptPolicy);
CookieManagerTest::add("WebKitCookieManager", "delete-cookies", testCookieManagerDeleteCookies);
CookieManagerTest::add("WebKitCookieManager", "cookies-changed", testCookieManagerCookiesChanged);
CookieManagerTest::add("WebKitCookieManager", "persistent-storage", testCookieManagerPersistentStorage);
+ CookieManagerTest::add("WebKitCookieManager", "ephemeral", testCookieManagerEphemeral);
}
void afterAll()
{
delete kServer;
- g_rmdir(kTempDirectory);
}
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDOMDOMWindow.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDOMDOMWindow.cpp
new file mode 100644
index 000000000..98c6e1064
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDOMDOMWindow.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2013 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2,1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include "WebProcessTestRunner.h"
+#include "WebViewTest.h"
+#include <gtk/gtk.h>
+#include <webkit2/webkit2.h>
+
+#define HTML_DOCUMENT "<html><head><title></title></head><style type='text/css'>#test { font-size: 16px; }</style><body><p id='test'>test</p></body></html>"
+
+typedef struct {
+ gboolean loaded;
+ gboolean clicked;
+ WebProcessTestRunner* testRunner;
+ WebViewTest* test;
+} DomDomWindowTestStatus;
+
+static DomDomWindowTestStatus status;
+
+static void signalsNotifyCallback(const gchar *key, const gchar *value, gconstpointer)
+{
+ if (g_str_equal(key, "ready")) {
+ // The document was already loaded in the webprocess, and its "load"
+ // signal couldn't be captured on time (was issued before the test
+ // started). We load it again to force a new "load" signal in the
+ // webprocess, which will be captured this time
+ status.test->loadHtml(HTML_DOCUMENT, 0);
+ }
+
+ if (g_str_equal(key, "loaded")) {
+ status.loaded = TRUE;
+ status.test->showInWindowAndWaitUntilMapped();
+
+ // Click in a known location where the text is
+ status.test->clickMouseButton(20, 18, 1, 0);
+ }
+
+ if (g_str_equal(key, "clicked"))
+ status.clicked = TRUE;
+
+ if (g_str_equal(key, "finish")) {
+ status.test = 0;
+ status.testRunner->finishTest(status.loaded && status.clicked);
+ }
+}
+
+static void dispatchEventNotifyCallback(const gchar *key, const gchar *value, gconstpointer)
+{
+ if (g_str_equal(key, "ready")) {
+ // The document was already loaded in the webprocess, and its "load"
+ // signal couldn't be captured on time (was issued before the test
+ // started). We load it again to force a new "load" signal in the
+ // webprocess, which will be captured this time
+ status.test->loadHtml(HTML_DOCUMENT, 0);
+ }
+
+ if (g_str_equal(key, "loaded"))
+ status.loaded = TRUE;
+
+ if (g_str_equal(key, "clicked"))
+ status.clicked = TRUE;
+
+ if (g_str_equal(key, "finish")) {
+ status.test = 0;
+ status.testRunner->finishTest(status.loaded && status.clicked);
+ }
+}
+
+static void testWebKitDOMDOMWindowSignals(WebViewTest* test, gconstpointer)
+{
+ status.loaded = FALSE;
+ status.clicked = FALSE;
+ status.test = test;
+
+ status.testRunner->setNotifyCallback(G_CALLBACK(signalsNotifyCallback), 0);
+
+ // The HTML document will we loaded later, when the test is "ready" because
+ // we want to test the "load" signal
+
+ GVariantBuilder builder;
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
+ g_variant_builder_add(&builder, "{sv}", "pageID", g_variant_new_uint64(webkit_web_view_get_page_id(status.test->m_webView)));
+ status.testRunner->runTestAndWait("WebKitDOMDOMWindow", "signals", g_variant_builder_end(&builder));
+ g_assert(status.testRunner->getTestResult());
+}
+
+static void testWebKitDOMDOMWindowDispatchEvent(WebViewTest* test, gconstpointer)
+{
+ status.loaded = FALSE;
+ status.clicked = FALSE;
+ status.test = test;
+
+ status.testRunner->setNotifyCallback(G_CALLBACK(dispatchEventNotifyCallback), 0);
+
+ // The HTML document will we loaded later, when the test is "ready" because
+ // we want to test the "load" signal
+
+ GVariantBuilder builder;
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
+ g_variant_builder_add(&builder, "{sv}", "pageID", g_variant_new_uint64(webkit_web_view_get_page_id(status.test->m_webView)));
+ status.testRunner->runTestAndWait("WebKitDOMDOMWindow", "dispatch-event", g_variant_builder_end(&builder));
+ g_assert(status.testRunner->getTestResult());
+}
+
+static void testWebKitDOMDOMWindowGetComputedStyle(WebViewTest* test, gconstpointer)
+{
+ status.loaded = FALSE;
+ status.clicked = FALSE;
+ status.test = test;
+
+ static const char* testHTML = HTML_DOCUMENT;
+ status.test->loadHtml(testHTML, 0);
+ status.test->waitUntilLoadFinished();
+
+ GVariantBuilder builder;
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
+ g_variant_builder_add(&builder, "{sv}", "pageID", g_variant_new_uint64(webkit_web_view_get_page_id(status.test->m_webView)));
+ g_assert(status.testRunner->runTest("WebKitDOMDOMWindow", "get-computed-style", g_variant_builder_end(&builder)));
+}
+
+void beforeAll()
+{
+ status.testRunner = new WebProcessTestRunner();
+ webkit_web_context_set_web_extensions_directory(webkit_web_context_get_default(), WEBKIT_TEST_WEB_EXTENSIONS_DIR);
+
+ WebViewTest::add("WebKitDOMDOMWindow", "signals", testWebKitDOMDOMWindowSignals);
+ WebViewTest::add("WebKitDOMDOMWindow", "dispatch-event", testWebKitDOMDOMWindowDispatchEvent);
+ WebViewTest::add("WebKitDOMDOMWindow", "get-computed-style", testWebKitDOMDOMWindowGetComputedStyle);
+}
+
+void afterAll()
+{
+ delete status.testRunner;
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDOMNode.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDOMNode.cpp
index 16db87d98..886356b7e 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDOMNode.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDOMNode.cpp
@@ -41,7 +41,7 @@ static void testWebKitDOMNodeInsertion(WebViewTest* test, gconstpointer)
g_assert(test->runWebProcessTest("WebKitDOMNode", "insertion"));
}
-static void testWebKitDOMNodeTagNames(WebViewTest* test, gconstpointer)
+static void prepareDOMForTagNamesTests(WebViewTest* test)
{
static const char* testHTML = "<html><head></head><body>"
"<video id='video' preload='none'>"
@@ -53,19 +53,44 @@ static void testWebKitDOMNodeTagNames(WebViewTest* test, gconstpointer)
" Your browser does not support the video tag."
"</video>"
"<input type='hidden' id='test' name='finish' value='false'></body></html>";
- test->loadHtml(testHTML, 0);
+ test->loadHtml(testHTML, nullptr);
test->waitUntilLoadFinished();
+}
- g_assert(test->runWebProcessTest("WebKitDOMNode", "tag-names"));
+static void testWebKitDOMNodeTagNamesNodeList(WebViewTest* test, gconstpointer)
+{
+ prepareDOMForTagNamesTests(test);
+ g_assert(test->runWebProcessTest("WebKitDOMNode", "tag-names-node-list"));
}
-void beforeAll()
+static void testWebKitDOMNodeTagNamesHTMLCollection(WebViewTest* test, gconstpointer)
+{
+ prepareDOMForTagNamesTests(test);
+ g_assert(test->runWebProcessTest("WebKitDOMNode", "tag-names-html-collection"));
+}
+
+static void testWebKitDOMObjectCache(WebViewTest* test, gconstpointer)
{
- webkit_web_context_set_web_extensions_directory(webkit_web_context_get_default(), WEBKIT_TEST_WEB_EXTENSIONS_DIR);
+ static const char* testHTML = "<html><body><div id='container'><p>DOM Cache test</p><a id='link href='#'>link</a></div></body></html>";
+ // Run the test 3 times to make sure the DOM objects are correctly released when the
+ // document is detached from the frame for every new document created.
+ for (unsigned i = 0; i < 3; ++i) {
+ test->loadHtml(testHTML, nullptr);
+ test->waitUntilLoadFinished();
+
+ g_assert(test->runWebProcessTest("WebKitDOMNode", "dom-cache"));
+ }
+}
+
+
+void beforeAll()
+{
WebViewTest::add("WebKitDOMNode", "hierarchy-navigation", testWebKitDOMNodeHierarchyNavigation);
WebViewTest::add("WebKitDOMNode", "insertion", testWebKitDOMNodeInsertion);
- WebViewTest::add("WebKitDOMNode", "tag-names", testWebKitDOMNodeTagNames);
+ WebViewTest::add("WebKitDOMNode", "tag-names-node-list", testWebKitDOMNodeTagNamesNodeList);
+ WebViewTest::add("WebKitDOMNode", "tag-names-html-collection", testWebKitDOMNodeTagNamesHTMLCollection);
+ WebViewTest::add("WebKitDOMNode", "dom-cache", testWebKitDOMObjectCache);
}
void afterAll()
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDOMNodeFilter.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDOMNodeFilter.cpp
new file mode 100644
index 000000000..812946153
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDOMNodeFilter.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2,1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include "WebViewTest.h"
+#include <gtk/gtk.h>
+#include <webkit2/webkit2.h>
+
+static const char* testHTML = "<html id='root'><head><title>DOMNodeTreeWalker</title></head>"
+ "<body><input type='button' name='push' value='push'><input type='button' name='clear' value='clear'><br></body></html>";
+
+static void runTest(WebViewTest* test, const char* name)
+{
+ test->loadHtml(testHTML, nullptr);
+ test->waitUntilLoadFinished();
+
+ g_assert(test->runWebProcessTest("WebKitDOMNodeFilter", name));
+}
+
+static void testWebKitDOMNodeFilterTreeWalker(WebViewTest* test, gconstpointer)
+{
+ runTest(test, "tree-walker");
+}
+
+static void testWebKitDOMNodeFilterNodeIterator(WebViewTest* test, gconstpointer)
+{
+ runTest(test, "node-iterator");
+}
+
+void beforeAll()
+{
+ WebViewTest::add("WebKitDOMNodeFilter", "tree-walker", testWebKitDOMNodeFilterTreeWalker);
+ WebViewTest::add("WebKitDOMNodeFilter", "node-iterator", testWebKitDOMNodeFilterNodeIterator);
+}
+
+void afterAll()
+{
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDOMXPathNSResolver.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDOMXPathNSResolver.cpp
new file mode 100644
index 000000000..ff9a77192
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDOMXPathNSResolver.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2,1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include "WebViewTest.h"
+#include <gtk/gtk.h>
+#include <webkit2/webkit2.h>
+
+static void testWebKitDOMXPathNSResolverNative(WebViewTest* test, gconstpointer)
+{
+ static const char* nativeXML = "<root xmlns:foo='http://www.example.org'><foo:child>SUCCESS</foo:child></root>";
+ GRefPtr<GBytes> bytes = adoptGRef(g_bytes_new_static(nativeXML, strlen(nativeXML)));
+ test->loadBytes(bytes.get(), "text/xml", nullptr, nullptr);
+ test->waitUntilLoadFinished();
+ g_assert(test->runWebProcessTest("WebKitDOMXPathNSResolver", "native"));
+}
+
+static void testWebKitDOMXPathNSResolverCustom(WebViewTest* test, gconstpointer)
+{
+ static const char* customXML = "<root xmlns='http://www.example.com'><child>SUCCESS</child></root>";
+ GRefPtr<GBytes> bytes = adoptGRef(g_bytes_new_static(customXML, strlen(customXML)));
+ test->loadBytes(bytes.get(), "text/xml", nullptr, nullptr);
+ test->waitUntilLoadFinished();
+ g_assert(test->runWebProcessTest("WebKitDOMXPathNSResolver", "custom"));
+}
+
+void beforeAll()
+{
+ WebViewTest::add("WebKitDOMXPathNSResolver", "native", testWebKitDOMXPathNSResolverNative);
+ WebViewTest::add("WebKitDOMXPathNSResolver", "custom", testWebKitDOMXPathNSResolverCustom);
+}
+
+void afterAll()
+{
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDownloads.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDownloads.cpp
index a4d27a508..6b95a7fe4 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDownloads.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDownloads.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Igalia S.L.
+ * Copyright (C) 2012, 2014 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -27,12 +27,10 @@
#include <string.h>
#include <webkit2/webkit2.h>
#include <wtf/Vector.h>
-#include <wtf/gobject/GRefPtr.h>
-#include <wtf/gobject/GUniquePtr.h>
+#include <wtf/glib/GRefPtr.h>
+#include <wtf/glib/GUniquePtr.h>
#include <wtf/text/CString.h>
-static char* kTempDirectory;
-
class DownloadTest: public Test {
public:
MAKE_GLIB_TEST_FIXTURE(DownloadTest);
@@ -56,6 +54,8 @@ public:
{
g_assert(webkit_download_get_destination(download));
g_assert_cmpstr(webkit_download_get_destination(download), ==, destination);
+ GRefPtr<GFile> file = adoptGRef(g_file_new_for_uri(destination));
+ g_assert(g_file_query_exists(file.get(), nullptr));
test->createdDestination(download, destination);
}
@@ -72,6 +72,14 @@ public:
static void failedCallback(WebKitDownload* download, GError* error, DownloadTest* test)
{
g_assert(error);
+
+ const char* destinationURI = webkit_download_get_destination(download);
+ if (destinationURI) {
+ GUniquePtr<char> tempFileURI(g_strconcat(destinationURI, ".wkdownload", nullptr));
+ GRefPtr<GFile> tempFile = adoptGRef(g_file_new_for_uri(tempFileURI.get()));
+ g_assert(!g_file_query_exists(tempFile.get(), nullptr));
+ }
+
test->failed(download, error);
}
@@ -95,21 +103,23 @@ public:
}
DownloadTest()
- : m_webContext(webkit_web_context_get_default())
- , m_mainLoop(g_main_loop_new(0, TRUE))
+ : m_mainLoop(g_main_loop_new(nullptr, TRUE))
, m_downloadSize(0)
+ , m_allowOverwrite(false)
{
- g_signal_connect(m_webContext, "download-started", G_CALLBACK(downloadStartedCallback), this);
+ g_signal_connect(m_webContext.get(), "download-started", G_CALLBACK(downloadStartedCallback), this);
}
~DownloadTest()
{
- g_signal_handlers_disconnect_matched(m_webContext, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
+ g_signal_handlers_disconnect_matched(m_webContext.get(), G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
g_main_loop_unref(m_mainLoop);
}
virtual void started(WebKitDownload* download)
{
+ m_downloadSize = 0;
+ m_downloadEvents.clear();
m_downloadEvents.append(Started);
}
@@ -144,17 +154,21 @@ public:
virtual void decideDestination(WebKitDownload* download, const gchar* suggestedFilename)
{
- GUniquePtr<char> destination(g_build_filename(kTempDirectory, suggestedFilename, NULL));
+ GUniquePtr<char> destination(g_build_filename(Test::dataDirectory(), suggestedFilename, nullptr));
GUniquePtr<char> destinationURI(g_filename_to_uri(destination.get(), 0, 0));
webkit_download_set_destination(download, destinationURI.get());
}
- WebKitDownload* downloadURIAndWaitUntilFinishes(const CString& requestURI)
+ GRefPtr<WebKitDownload> downloadURIAndWaitUntilFinishes(const CString& requestURI)
{
- WebKitDownload* download = webkit_web_context_download_uri(m_webContext, requestURI.data());
- assertObjectIsDeletedWhenTestFinishes(G_OBJECT(download));
+ GRefPtr<WebKitDownload> download = adoptGRef(webkit_web_context_download_uri(m_webContext.get(), requestURI.data()));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(download.get()));
- WebKitURIRequest* request = webkit_download_get_request(download);
+ g_assert(!webkit_download_get_allow_overwrite(download.get()));
+ webkit_download_set_allow_overwrite(download.get(), m_allowOverwrite);
+ g_assert(webkit_download_get_allow_overwrite(download.get()) == m_allowOverwrite);
+
+ WebKitURIRequest* request = webkit_download_get_request(download.get());
g_assert(request);
ASSERT_CMP_CSTRING(webkit_uri_request_get_uri(request), ==, requestURI);
@@ -174,19 +188,19 @@ public:
g_file_delete(destFile.get(), 0, 0);
}
- WebKitWebContext* m_webContext;
GMainLoop* m_mainLoop;
Vector<DownloadEvent> m_downloadEvents;
guint64 m_downloadSize;
+ bool m_allowOverwrite;
};
-static void testDownloadLocalFile(DownloadTest* test, gconstpointer)
+static GRefPtr<WebKitDownload> downloadLocalFileSuccessfully(DownloadTest* test, const char* filename)
{
- GUniquePtr<char> sourcePath(g_build_filename(Test::getWebKit1TestResoucesDir().data(), "test.pdf", NULL));
+ GUniquePtr<char> sourcePath(g_build_filename(Test::getResourcesDir().data(), filename, nullptr));
GRefPtr<GFile> source = adoptGRef(g_file_new_for_path(sourcePath.get()));
GRefPtr<GFileInfo> sourceInfo = adoptGRef(g_file_query_info(source.get(), G_FILE_ATTRIBUTE_STANDARD_SIZE, static_cast<GFileQueryInfoFlags>(0), 0, 0));
GUniquePtr<char> sourceURI(g_file_get_uri(source.get()));
- GRefPtr<WebKitDownload> download = adoptGRef(test->downloadURIAndWaitUntilFinishes(sourceURI.get()));
+ GRefPtr<WebKitDownload> download = test->downloadURIAndWaitUntilFinishes(sourceURI.get());
g_assert(!webkit_download_get_web_view(download.get()));
Vector<DownloadTest::DownloadEvent>& events = test->m_downloadEvents;
@@ -204,15 +218,50 @@ static void testDownloadLocalFile(DownloadTest* test, gconstpointer)
g_assert_cmpint(test->m_downloadSize, ==, g_file_info_get_size(sourceInfo.get()));
g_assert(webkit_download_get_destination(download.get()));
g_assert_cmpfloat(webkit_download_get_estimated_progress(download.get()), ==, 1);
- test->checkDestinationAndDeleteFile(download.get(), "test.pdf");
+
+ return download;
+}
+
+static void testDownloadLocalFile(DownloadTest* test, gconstpointer)
+{
+ static const char* filename = "test.pdf";
+ GRefPtr<WebKitDownload> download = downloadLocalFileSuccessfully(test, filename);
+ test->checkDestinationAndDeleteFile(download.get(), filename);
+}
+
+static void createFileAtDestination(const char* filename)
+{
+ GUniquePtr<char> path(g_build_filename(Test::dataDirectory(), filename, nullptr));
+ GRefPtr<GFile> file = adoptGRef(g_file_new_for_path(path.get()));
+ GUniqueOutPtr<GError> error;
+ g_file_create(file.get(), G_FILE_CREATE_NONE, nullptr, &error.outPtr());
+ g_assert(!error);
+ g_assert(g_file_query_exists(file.get(), nullptr));
+}
+
+static void testDownloadOverwriteDestinationAllowed(DownloadTest* test, gconstpointer)
+{
+ static const char* filename = "test.pdf";
+ createFileAtDestination(filename);
+
+ test->m_allowOverwrite = true;
+ GRefPtr<WebKitDownload> download = downloadLocalFileSuccessfully(test, filename);
+ test->checkDestinationAndDeleteFile(download.get(), filename);
}
class DownloadErrorTest: public DownloadTest {
public:
MAKE_GLIB_TEST_FIXTURE(DownloadErrorTest);
+ enum ExpectedError {
+ NetworkError,
+ DownloadCancelled,
+ InvalidDestination,
+ DestinationExists
+ };
+
DownloadErrorTest()
- : m_expectedError(WEBKIT_DOWNLOAD_ERROR_NETWORK)
+ : m_expectedError(NetworkError)
{
}
@@ -223,7 +272,7 @@ public:
void createdDestination(WebKitDownload* download, const char* destination)
{
- if (m_expectedError == WEBKIT_DOWNLOAD_ERROR_CANCELLED_BY_USER)
+ if (m_expectedError == DownloadCancelled)
webkit_download_cancel(download);
else
g_assert_not_reached();
@@ -231,26 +280,65 @@ public:
void failed(WebKitDownload* download, GError* error)
{
- g_assert(g_error_matches(error, WEBKIT_DOWNLOAD_ERROR, m_expectedError));
+ g_assert(g_error_matches(error, WEBKIT_DOWNLOAD_ERROR, expectedErrorToWebKitDownloadError(m_expectedError)));
DownloadTest::failed(download, error);
}
void decideDestination(WebKitDownload* download, const gchar* suggestedFilename)
{
- if (m_expectedError != WEBKIT_DOWNLOAD_ERROR_DESTINATION) {
+ if (m_expectedError != InvalidDestination) {
DownloadTest::decideDestination(download, suggestedFilename);
return;
}
webkit_download_set_destination(download, "file:///foo/bar");
}
- WebKitDownloadError m_expectedError;
+ static WebKitDownloadError expectedErrorToWebKitDownloadError(ExpectedError expected)
+ {
+ switch (expected) {
+ case NetworkError:
+ return WEBKIT_DOWNLOAD_ERROR_NETWORK;
+ case DownloadCancelled:
+ return WEBKIT_DOWNLOAD_ERROR_CANCELLED_BY_USER;
+ case InvalidDestination:
+ return WEBKIT_DOWNLOAD_ERROR_DESTINATION;
+ case DestinationExists:
+ return WEBKIT_DOWNLOAD_ERROR_DESTINATION;
+ default:
+ g_assert_not_reached();
+ }
+ }
+
+ ExpectedError m_expectedError;
};
+static void testDownloadOverwriteDestinationDisallowed(DownloadErrorTest* test, gconstpointer)
+{
+ static const char* filename = "test.pdf";
+ createFileAtDestination(filename);
+
+ test->m_expectedError = DownloadErrorTest::DestinationExists;
+ GUniquePtr<char> sourcePath(g_build_filename(Test::getResourcesDir().data(), filename, nullptr));
+ GRefPtr<GFile> source = adoptGRef(g_file_new_for_path(sourcePath.get()));
+ GUniquePtr<char> sourceURI(g_file_get_uri(source.get()));
+ GRefPtr<WebKitDownload> download = test->downloadURIAndWaitUntilFinishes(sourceURI.get());
+ g_assert(!webkit_download_get_web_view(download.get()));
+
+ Vector<DownloadTest::DownloadEvent>& events = test->m_downloadEvents;
+ g_assert_cmpint(events.size(), ==, 4);
+ g_assert_cmpint(events[0], ==, DownloadTest::Started);
+ g_assert_cmpint(events[1], ==, DownloadTest::ReceivedResponse);
+ g_assert_cmpint(events[2], ==, DownloadTest::Failed);
+ g_assert_cmpint(events[3], ==, DownloadTest::Finished);
+ g_assert_cmpfloat(webkit_download_get_estimated_progress(download.get()), ==, 0);
+
+ test->checkDestinationAndDeleteFile(download.get(), filename);
+}
+
static void testDownloadLocalFileError(DownloadErrorTest* test, gconstpointer)
{
- test->m_expectedError = WEBKIT_DOWNLOAD_ERROR_NETWORK;
- GRefPtr<WebKitDownload> download = adoptGRef(test->downloadURIAndWaitUntilFinishes("file:///foo/bar"));
+ test->m_expectedError = DownloadErrorTest::NetworkError;
+ GRefPtr<WebKitDownload> download = test->downloadURIAndWaitUntilFinishes("file:///foo/bar");
g_assert(!webkit_download_get_web_view(download.get()));
Vector<DownloadTest::DownloadEvent>& events = test->m_downloadEvents;
@@ -261,11 +349,11 @@ static void testDownloadLocalFileError(DownloadErrorTest* test, gconstpointer)
events.clear();
g_assert_cmpfloat(webkit_download_get_estimated_progress(download.get()), <, 1);
- test->m_expectedError = WEBKIT_DOWNLOAD_ERROR_DESTINATION;
- GUniquePtr<char> path(g_build_filename(Test::getWebKit1TestResoucesDir().data(), "test.pdf", NULL));
+ test->m_expectedError = DownloadErrorTest::InvalidDestination;
+ GUniquePtr<char> path(g_build_filename(Test::getResourcesDir().data(), "test.pdf", nullptr));
GRefPtr<GFile> file = adoptGRef(g_file_new_for_path(path.get()));
GUniquePtr<char> uri(g_file_get_uri(file.get()));
- download = adoptGRef(test->downloadURIAndWaitUntilFinishes(uri.get()));
+ download = test->downloadURIAndWaitUntilFinishes(uri.get());
g_assert(!webkit_download_get_web_view(download.get()));
g_assert_cmpint(events.size(), ==, 4);
@@ -277,8 +365,8 @@ static void testDownloadLocalFileError(DownloadErrorTest* test, gconstpointer)
g_assert_cmpfloat(webkit_download_get_estimated_progress(download.get()), <, 1);
test->checkDestinationAndDeleteFile(download.get(), "bar");
- test->m_expectedError = WEBKIT_DOWNLOAD_ERROR_CANCELLED_BY_USER;
- download = adoptGRef(test->downloadURIAndWaitUntilFinishes(uri.get()));
+ test->m_expectedError = DownloadErrorTest::DownloadCancelled;
+ download = test->downloadURIAndWaitUntilFinishes(uri.get());
g_assert(!webkit_download_get_web_view(download.get()));
g_assert_cmpint(events.size(), ==, 4);
@@ -300,15 +388,17 @@ static void addContentDispositionHTTPHeaderToResponse(SoupMessage* message)
soup_message_headers_append(message->response_headers, "Content-Disposition", contentDisposition.get());
}
-static gboolean writeNextChunkIdle(SoupMessage* message)
-{
- soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, "chunk", 5);
- return FALSE;
-}
-
static void writeNextChunk(SoupMessage* message)
{
- g_timeout_add(100, reinterpret_cast<GSourceFunc>(writeNextChunkIdle), message);
+ /* We need a big enough chunk for the sniffer to not block the load */
+ static const char* chunk = "Testing!Testing!Testing!Testing!Testing!Testing!Testing!"
+ "Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!"
+ "Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!"
+ "Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!"
+ "Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!"
+ "Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!"
+ "Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!";
+ soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, chunk, strlen(chunk));
}
static void serverCallback(SoupServer* server, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, gpointer)
@@ -329,7 +419,10 @@ static void serverCallback(SoupServer* server, SoupMessage* message, const char*
return;
}
- GUniquePtr<char> filePath(g_build_filename(Test::getWebKit1TestResoucesDir().data(), path, NULL));
+ if (g_str_equal(path, "/unknown"))
+ path = "/test.pdf";
+
+ GUniquePtr<char> filePath(g_build_filename(Test::getResourcesDir().data(), path, nullptr));
char* contents;
gsize contentsLength;
if (!g_file_get_contents(filePath.get(), &contents, &contentsLength, 0)) {
@@ -346,7 +439,7 @@ static void serverCallback(SoupServer* server, SoupMessage* message, const char*
static void testDownloadRemoteFile(DownloadTest* test, gconstpointer)
{
- GRefPtr<WebKitDownload> download = adoptGRef(test->downloadURIAndWaitUntilFinishes(kServer->getURIForPath("/test.pdf")));
+ GRefPtr<WebKitDownload> download = test->downloadURIAndWaitUntilFinishes(kServer->getURIForPath("/test.pdf"));
g_assert(!webkit_download_get_web_view(download.get()));
Vector<DownloadTest::DownloadEvent>& events = test->m_downloadEvents;
@@ -364,13 +457,14 @@ static void testDownloadRemoteFile(DownloadTest* test, gconstpointer)
g_assert(webkit_download_get_destination(download.get()));
g_assert_cmpfloat(webkit_download_get_estimated_progress(download.get()), ==, 1);
- test->checkDestinationAndDeleteFile(download.get(), kServerSuggestedFilename);
+ GUniquePtr<char> expectedFilename(g_strdup_printf("%s.pdf", kServerSuggestedFilename));
+ test->checkDestinationAndDeleteFile(download.get(), expectedFilename.get());
}
static void testDownloadRemoteFileError(DownloadErrorTest* test, gconstpointer)
{
- test->m_expectedError = WEBKIT_DOWNLOAD_ERROR_NETWORK;
- GRefPtr<WebKitDownload> download = adoptGRef(test->downloadURIAndWaitUntilFinishes(kServer->getURIForPath("/foo")));
+ test->m_expectedError = DownloadErrorTest::NetworkError;
+ GRefPtr<WebKitDownload> download = test->downloadURIAndWaitUntilFinishes(kServer->getURIForPath("/foo"));
g_assert(!webkit_download_get_web_view(download.get()));
Vector<DownloadTest::DownloadEvent>& events = test->m_downloadEvents;
@@ -384,8 +478,8 @@ static void testDownloadRemoteFileError(DownloadErrorTest* test, gconstpointer)
g_assert_cmpuint(webkit_uri_response_get_status_code(response), ==, 404);
g_assert_cmpfloat(webkit_download_get_estimated_progress(download.get()), <, 1);
- test->m_expectedError = WEBKIT_DOWNLOAD_ERROR_DESTINATION;
- download = adoptGRef(test->downloadURIAndWaitUntilFinishes(kServer->getURIForPath("/test.pdf")));
+ test->m_expectedError = DownloadErrorTest::InvalidDestination;
+ download = test->downloadURIAndWaitUntilFinishes(kServer->getURIForPath("/test.pdf"));
g_assert(!webkit_download_get_web_view(download.get()));
g_assert_cmpint(events.size(), ==, 4);
@@ -397,8 +491,8 @@ static void testDownloadRemoteFileError(DownloadErrorTest* test, gconstpointer)
g_assert_cmpfloat(webkit_download_get_estimated_progress(download.get()), <, 1);
test->checkDestinationAndDeleteFile(download.get(), "bar");
- test->m_expectedError = WEBKIT_DOWNLOAD_ERROR_CANCELLED_BY_USER;
- download = adoptGRef(test->downloadURIAndWaitUntilFinishes(kServer->getURIForPath("/cancel-after-destination")));
+ test->m_expectedError = DownloadErrorTest::DownloadCancelled;
+ download = test->downloadURIAndWaitUntilFinishes(kServer->getURIForPath("/cancel-after-destination"));
g_assert(!webkit_download_get_web_view(download.get()));
g_assert_cmpint(events.size(), ==, 4);
@@ -422,6 +516,8 @@ public:
{
test->m_download = download;
test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(download));
+ g_signal_connect(download, "decide-destination", G_CALLBACK(downloadDecideDestinationCallback), test);
+ g_signal_connect(download, "finished", G_CALLBACK(downloadFinishedCallback), test);
test->quitMainLoop();
}
@@ -444,8 +540,10 @@ public:
static gboolean downloadDecideDestinationCallback(WebKitDownload* download, const gchar* suggestedFilename, WebViewDownloadTest* test)
{
- GUniquePtr<char> destination(g_build_filename(kTempDirectory, suggestedFilename, NULL));
+ GUniquePtr<char> destination(g_build_filename(Test::dataDirectory(), suggestedFilename, nullptr));
GUniquePtr<char> destinationURI(g_filename_to_uri(destination.get(), 0, 0));
+ if (test->m_shouldDelayDecideDestination)
+ g_usleep(0.2 * G_USEC_PER_SEC);
webkit_download_set_destination(download, destinationURI.get());
return TRUE;
}
@@ -457,17 +555,17 @@ public:
void waitUntilDownloadFinished()
{
- g_signal_connect(m_download.get(), "decide-destination", G_CALLBACK(downloadDecideDestinationCallback), this);
- g_signal_connect(m_download.get(), "finished", G_CALLBACK(downloadFinishedCallback), this);
g_main_loop_run(m_mainLoop);
}
GRefPtr<WebKitDownload> m_download;
+ bool m_shouldDelayDecideDestination { false };
};
static void testWebViewDownloadURI(WebViewDownloadTest* test, gconstpointer)
{
GRefPtr<WebKitDownload> download = adoptGRef(webkit_web_view_download_uri(test->m_webView, kServer->getURIForPath("/test.pdf").data()));
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(download.get()));
test->waitUntilDownloadStarted();
g_assert(test->m_webView == webkit_download_get_web_view(download.get()));
test->waitUntilDownloadFinished();
@@ -511,7 +609,28 @@ public:
static void testPolicyResponseDownload(PolicyResponseDownloadTest* test, gconstpointer)
{
- // Test that a download started by the the policy checker contains the web view.
+ CString requestURI = kServer->getURIForPath("/test.pdf").data();
+ // Delay the DecideDestination to ensure that the load is aborted before the network task has became a download.
+ // See https://bugs.webkit.org/show_bug.cgi?id=164220.
+ test->m_shouldDelayDecideDestination = true;
+ test->loadURI(requestURI.data());
+ test->waitUntilDownloadStarted();
+
+ WebKitURIRequest* request = webkit_download_get_request(test->m_download.get());
+ g_assert(request);
+ ASSERT_CMP_CSTRING(webkit_uri_request_get_uri(request), ==, requestURI);
+
+ g_assert(test->m_webView == webkit_download_get_web_view(test->m_download.get()));
+ test->waitUntilDownloadFinished();
+
+ GRefPtr<GFile> downloadFile = adoptGRef(g_file_new_for_uri(webkit_download_get_destination(test->m_download.get())));
+ GRefPtr<GFileInfo> downloadFileInfo = adoptGRef(g_file_query_info(downloadFile.get(), G_FILE_ATTRIBUTE_STANDARD_SIZE, static_cast<GFileQueryInfoFlags>(0), nullptr, nullptr));
+ g_assert_cmpint(g_file_info_get_size(downloadFileInfo.get()), >, 0);
+ g_file_delete(downloadFile.get(), nullptr, nullptr);
+}
+
+static void testPolicyResponseDownloadCancel(PolicyResponseDownloadTest* test, gconstpointer)
+{
CString requestURI = kServer->getURIForPath("/test.pdf").data();
test->loadURI(requestURI.data());
test->waitUntilDownloadStarted();
@@ -524,24 +643,146 @@ static void testPolicyResponseDownload(PolicyResponseDownloadTest* test, gconstp
test->cancelDownloadAndWaitUntilFinished();
}
+static void testDownloadMIMEType(DownloadTest* test, gconstpointer)
+{
+ GRefPtr<WebKitDownload> download = test->downloadURIAndWaitUntilFinishes(kServer->getURIForPath("/unknown"));
+ g_assert(!webkit_download_get_web_view(download.get()));
+
+ Vector<DownloadTest::DownloadEvent>& events = test->m_downloadEvents;
+ g_assert_cmpint(events.size(), ==, 5);
+ g_assert_cmpint(events[0], ==, DownloadTest::Started);
+ g_assert_cmpint(events[1], ==, DownloadTest::ReceivedResponse);
+ g_assert_cmpint(events[2], ==, DownloadTest::CreatedDestination);
+ g_assert_cmpint(events[3], ==, DownloadTest::ReceivedData);
+ g_assert_cmpint(events[4], ==, DownloadTest::Finished);
+ events.clear();
+
+ WebKitURIRequest* request = webkit_download_get_request(download.get());
+ WEBKIT_IS_URI_REQUEST(request);
+ ASSERT_CMP_CSTRING(webkit_uri_request_get_uri(request), ==, kServer->getURIForPath("/unknown"));
+
+ WebKitURIResponse* response = webkit_download_get_response(download.get());
+ WEBKIT_IS_URI_RESPONSE(response);
+ g_assert_cmpstr(webkit_uri_response_get_mime_type(response), ==, "application/pdf");
+
+ g_assert(webkit_download_get_destination(download.get()));
+ g_assert_cmpfloat(webkit_download_get_estimated_progress(download.get()), ==, 1);
+ GUniquePtr<char> expectedFilename(g_strdup_printf("%s.pdf", kServerSuggestedFilename));
+ test->checkDestinationAndDeleteFile(download.get(), expectedFilename.get());
+}
+
+static gboolean contextMenuCallback(WebKitWebView* webView, WebKitContextMenu* contextMenu, GdkEvent*, WebKitHitTestResult* hitTestResult, WebViewDownloadTest* test)
+{
+ g_assert(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult));
+ g_assert(webkit_hit_test_result_context_is_link(hitTestResult));
+ GList* items = webkit_context_menu_get_items(contextMenu);
+ GRefPtr<WebKitContextMenuItem> contextMenuItem;
+ for (GList* l = items; l; l = g_list_next(l)) {
+ g_assert(WEBKIT_IS_CONTEXT_MENU_ITEM(l->data));
+ auto* item = WEBKIT_CONTEXT_MENU_ITEM(l->data);
+ if (webkit_context_menu_item_get_stock_action(item) == WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_LINK_TO_DISK) {
+ contextMenuItem = item;
+ break;
+ }
+ }
+ g_assert(contextMenuItem.get());
+ webkit_context_menu_remove_all(contextMenu);
+ webkit_context_menu_append(contextMenu, contextMenuItem.get());
+ test->quitMainLoop();
+ return FALSE;
+}
+
+static void testContextMenuDownloadActions(WebViewDownloadTest* test, gconstpointer)
+{
+ test->showInWindowAndWaitUntilMapped();
+
+ static const char* linkHTMLFormat = "<html><body><a style='position:absolute; left:1; top:1' href='%s'>Download Me</a></body></html>";
+ GUniquePtr<char> linkHTML(g_strdup_printf(linkHTMLFormat, kServer->getURIForPath("/test.pdf").data()));
+ test->loadHtml(linkHTML.get(), kServer->getURIForPath("/").data());
+ test->waitUntilLoadFinished();
+
+ g_signal_connect(test->m_webView, "context-menu", G_CALLBACK(contextMenuCallback), test);
+ g_idle_add([](gpointer userData) -> gboolean {
+ auto* test = static_cast<WebViewDownloadTest*>(userData);
+ test->clickMouseButton(1, 1, 3);
+ return FALSE;
+ }, test);
+ g_main_loop_run(test->m_mainLoop);
+
+ g_idle_add([](gpointer userData) -> gboolean {
+ auto* test = static_cast<WebViewDownloadTest*>(userData);
+ // Select and activate the context menu action.
+ test->keyStroke(GDK_KEY_Down);
+ test->keyStroke(GDK_KEY_Return);
+ return FALSE;
+ }, test);
+ test->waitUntilDownloadStarted();
+
+ g_assert(test->m_webView == webkit_download_get_web_view(test->m_download.get()));
+ test->waitUntilDownloadFinished();
+
+ GRefPtr<GFile> downloadFile = adoptGRef(g_file_new_for_uri(webkit_download_get_destination(test->m_download.get())));
+ GRefPtr<GFileInfo> downloadFileInfo = adoptGRef(g_file_query_info(downloadFile.get(), G_FILE_ATTRIBUTE_STANDARD_SIZE, static_cast<GFileQueryInfoFlags>(0), nullptr, nullptr));
+ g_assert_cmpint(g_file_info_get_size(downloadFileInfo.get()), >, 0);
+ g_file_delete(downloadFile.get(), nullptr, nullptr);
+}
+
+static void testBlobDownload(WebViewDownloadTest* test, gconstpointer)
+{
+ test->showInWindowAndWaitUntilMapped();
+
+ static const char* linkBlobHTML =
+ "<html><body>"
+ "<a id='downloadLink' style='position:absolute; left:1; top:1' download='foo.pdf'>Download Me</a>"
+ "<script>"
+ " blob = new Blob(['Hello world'], {type: 'text/plain'});"
+ " document.getElementById('downloadLink').href = window.URL.createObjectURL(blob);"
+ "</script>"
+ "</body></html>";
+ test->loadHtml(linkBlobHTML, kServer->getURIForPath("/").data());
+ test->waitUntilLoadFinished();
+
+ g_idle_add([](gpointer userData) -> gboolean {
+ auto* test = static_cast<WebViewDownloadTest*>(userData);
+ test->clickMouseButton(1, 1, 1);
+ return FALSE;
+ }, test);
+ test->waitUntilDownloadStarted();
+
+ g_assert(test->m_webView == webkit_download_get_web_view(test->m_download.get()));
+ test->waitUntilDownloadFinished();
+
+ GRefPtr<GFile> downloadFile = adoptGRef(g_file_new_for_uri(webkit_download_get_destination(test->m_download.get())));
+ GRefPtr<GFileInfo> downloadFileInfo = adoptGRef(g_file_query_info(downloadFile.get(), G_FILE_ATTRIBUTE_STANDARD_SIZE, static_cast<GFileQueryInfoFlags>(0), nullptr, nullptr));
+ GUniquePtr<char> downloadPath(g_file_get_path(downloadFile.get()));
+ GUniqueOutPtr<char> downloadContents;
+ gsize downloadContentsLength;
+ g_assert(g_file_get_contents(downloadPath.get(), &downloadContents.outPtr(), &downloadContentsLength, nullptr));
+ g_assert_cmpint(g_file_info_get_size(downloadFileInfo.get()), ==, downloadContentsLength);
+ g_assert_cmpstr(downloadContents.get(), ==, "Hello world");
+ g_file_delete(downloadFile.get(), nullptr, nullptr);
+}
+
void beforeAll()
{
kServer = new WebKitTestServer();
kServer->run(serverCallback);
- kTempDirectory = g_dir_make_tmp("WebKit2Tests-XXXXXX", 0);
- g_assert(kTempDirectory);
-
DownloadTest::add("Downloads", "local-file", testDownloadLocalFile);
+ DownloadTest::add("Downloads", "overwrite-destination-allowed", testDownloadOverwriteDestinationAllowed);
+ DownloadErrorTest::add("Downloads", "overwrite-destination-disallowed", testDownloadOverwriteDestinationDisallowed);
DownloadErrorTest::add("Downloads", "local-file-error", testDownloadLocalFileError);
DownloadTest::add("Downloads", "remote-file", testDownloadRemoteFile);
DownloadErrorTest::add("Downloads", "remote-file-error", testDownloadRemoteFileError);
WebViewDownloadTest::add("WebKitWebView", "download-uri", testWebViewDownloadURI);
PolicyResponseDownloadTest::add("Downloads", "policy-decision-download", testPolicyResponseDownload);
+ PolicyResponseDownloadTest::add("Downloads", "policy-decision-download-cancel", testPolicyResponseDownloadCancel);
+ DownloadTest::add("Downloads", "mime-type", testDownloadMIMEType);
+ WebViewDownloadTest::add("Downloads", "contex-menu-download-actions", testContextMenuDownloadActions);
+ WebViewDownloadTest::add("Downloads", "blob-download", testBlobDownload);
}
void afterAll()
{
delete kServer;
- g_rmdir(kTempDirectory);
}
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testapplicationcache.c b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestEditor.cpp
index 718f401a7..fc429d4c3 100644
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testapplicationcache.c
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestEditor.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Lukasz Slachciak
+ * Copyright (C) 2015 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -18,32 +18,25 @@
*/
#include "config.h"
-#include <glib.h>
-#include <glib/gprintf.h>
+
+#include "WebViewTest.h"
#include <gtk/gtk.h>
-#include <webkit/webkit.h>
+#include <webkit2/webkit2.h>
-static void test_application_cache_maximum_size()
+static void testWebKitWebEditorSelectionChanged(WebViewTest* test, gconstpointer)
{
- unsigned long long maxSize = 8192;
- webkit_application_cache_set_maximum_size(maxSize);
-
- // Creating a WebView - make sure that it didn't change anything
- WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(webView);
- g_object_unref(webView);
+ static const gchar* testHTML = "<html><body>All work and no play make Jack a dull boy.</body></html>";
+ test->loadHtml(testHTML, nullptr);
+ test->waitUntilLoadFinished();
- g_assert(maxSize == webkit_application_cache_get_maximum_size());
+ g_assert(test->runWebProcessTest("WebKitWebEditor", "selection-changed"));
}
-int main(int argc, char** argv)
+void beforeAll()
{
- gtk_test_init(&argc, &argv, NULL);
-
- g_test_bug_base("https://bugs.webkit.org/");
- g_test_add_func("/webkit/application_cache/maximum_size",
- test_application_cache_maximum_size);
-
- return g_test_run();
+ WebViewTest::add("WebKitWebEditor", "selection-changed", testWebKitWebEditorSelectionChanged);
}
+void afterAll()
+{
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestFrame.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestFrame.cpp
index 69b5082cd..9145ab813 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestFrame.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestFrame.cpp
@@ -49,8 +49,6 @@ static void testWebKitFrameJavaScriptContext(WebViewTest* test, gconstpointer)
void beforeAll()
{
- webkit_web_context_set_web_extensions_directory(webkit_web_context_get_default(), WEBKIT_TEST_WEB_EXTENSIONS_DIR);
-
WebViewTest::add("WebKitFrame", "main-frame", testWebKitFrameMainFrame);
WebViewTest::add("WebKitFrame", "uri", testWebKitFrameURI);
WebViewTest::add("WebKitFrame", "javascript-context", testWebKitFrameJavaScriptContext);
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestInspector.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestInspector.cpp
index 1f0430389..3d993e24f 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestInspector.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestInspector.cpp
@@ -21,7 +21,7 @@
#include "WebViewTest.h"
#include <wtf/Vector.h>
-#include <wtf/gobject/GRefPtr.h>
+#include <wtf/glib/GRefPtr.h>
class InspectorTest: public WebViewTest {
public:
@@ -125,10 +125,22 @@ public:
g_main_loop_run(m_mainLoop);
}
+ static void canAttachChanged(InspectorTest* test)
+ {
+ g_main_loop_quit(test->m_mainLoop);
+ }
+
void resizeViewAndAttach()
{
// Resize the view to make room for the inspector.
- resizeView(gMinimumAttachedInspectorWidth, (gMinimumAttachedInspectorHeight + 1) * 4 / 3);
+ if (!webkit_web_inspector_get_can_attach(m_inspector)) {
+ unsigned long handler = g_signal_connect_swapped(m_inspector, "notify::can-attach", G_CALLBACK(canAttachChanged), this);
+ resizeView(gMinimumAttachedInspectorWidth, (gMinimumAttachedInspectorHeight + 1) * 4 / 3);
+ g_main_loop_run(m_mainLoop);
+ g_signal_handler_disconnect(m_inspector, handler);
+ }
+
+ g_assert(webkit_web_inspector_get_can_attach(m_inspector));
webkit_web_inspector_attach(m_inspector);
}
@@ -167,6 +179,7 @@ static void testInspectorDefault(InspectorTest* test, gconstpointer)
test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(inspectorView.get()));
g_assert(!webkit_web_inspector_is_attached(test->m_inspector));
g_assert_cmpuint(webkit_web_inspector_get_attached_height(test->m_inspector), ==, 0);
+ g_assert(!webkit_web_inspector_get_can_attach(test->m_inspector));
Vector<InspectorTest::InspectorEvents>& events = test->m_events;
g_assert_cmpint(events.size(), ==, 1);
g_assert_cmpint(events[0], ==, InspectorTest::OpenWindow);
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestInspectorServer.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestInspectorServer.cpp
index 58fefea5e..bbdd104c5 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestInspectorServer.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestInspectorServer.cpp
@@ -25,7 +25,7 @@
#include "config.h"
#include "WebViewTest.h"
-#include <wtf/gobject/GRefPtr.h>
+#include <wtf/glib/GRefPtr.h>
#include <wtf/text/WTFString.h>
// Name of the test server application creating the webView object.
@@ -237,12 +237,10 @@ static void openRemoteDebuggingSession(InspectorServerTest* test, gconstpointer)
test->loadURI(resolvedURL.utf8().data());
test->waitUntilLoadFinished();
- javascriptResult = test->runJavaScriptAndWaitUntilFinished("window.document.getElementsByTagName('li')[0].title", &error.outPtr());
- g_assert(javascriptResult);
- g_assert(!error.get());
-
- GUniquePtr<char> title(WebViewTest::javascriptResultToCString(javascriptResult));
- g_assert_cmpstr(title.get(), ==, "http://127.0.0.1:2999/");
+ const char* title = webkit_web_view_get_title(test->m_webView);
+ if (!title || !*title)
+ test->waitUntilTitleChanged();
+ g_assert_cmpstr(webkit_web_view_get_title(test->m_webView), ==, "127.0.0.1");
}
static void sendIncompleteRequest(InspectorServerTest* test, gconstpointer)
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestLoaderClient.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestLoaderClient.cpp
index 331915e00..7dd69f5f9 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestLoaderClient.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestLoaderClient.cpp
@@ -27,6 +27,7 @@
#include "WebViewTest.h"
#include <gtk/gtk.h>
#include <libsoup/soup.h>
+#include <wtf/Vector.h>
#include <wtf/text/CString.h>
static WebKitTestBus* bus;
@@ -82,6 +83,13 @@ static void testLoadAlternateHTML(LoadTrackingTest* test, gconstpointer)
assertNormalLoadHappened(test->m_loadEvents);
}
+static void testLoadAlternateHTMLForLocalPage(LoadTrackingTest* test, gconstpointer)
+{
+ test->loadAlternateHTML("<html><body>Alternate page</body></html>", "file:///not/actually/loaded.html", 0);
+ test->waitUntilLoadFinished();
+ assertNormalLoadHappened(test->m_loadEvents);
+}
+
static void testLoadPlainText(LoadTrackingTest* test, gconstpointer)
{
test->loadPlainText("Hello WebKit-GTK+");
@@ -89,6 +97,18 @@ static void testLoadPlainText(LoadTrackingTest* test, gconstpointer)
assertNormalLoadHappened(test->m_loadEvents);
}
+static void testLoadBytes(LoadTrackingTest* test, gconstpointer)
+{
+ GUniquePtr<char> filePath(g_build_filename(Test::getResourcesDir().data(), "blank.ico", nullptr));
+ char* contents;
+ gsize contentsLength;
+ g_file_get_contents(filePath.get(), &contents, &contentsLength, nullptr);
+ GRefPtr<GBytes> bytes = adoptGRef(g_bytes_new_take(contents, contentsLength));
+ test->loadBytes(bytes.get(), "image/vnd.microsoft.icon", nullptr, nullptr);
+ test->waitUntilLoadFinished();
+ assertNormalLoadHappened(test->m_loadEvents);
+}
+
static void testLoadRequest(LoadTrackingTest* test, gconstpointer)
{
GRefPtr<WebKitURIRequest> request(webkit_uri_request_new(kServer->getURIForPath("/normal").data()));
@@ -97,6 +117,14 @@ static void testLoadRequest(LoadTrackingTest* test, gconstpointer)
assertNormalLoadHappened(test->m_loadEvents);
}
+static void testLoadFromGResource(LoadTrackingTest* test, gconstpointer)
+{
+ GRefPtr<WebKitURIRequest> request(webkit_uri_request_new("resource:///org/webkit/webkit2gtk/tests/boring.html"));
+ test->loadRequest(request.get());
+ test->waitUntilLoadFinished();
+ assertNormalLoadHappened(test->m_loadEvents);
+}
+
class LoadStopTrackingTest : public LoadTrackingTest {
public:
MAKE_GLIB_TEST_FIXTURE(LoadStopTrackingTest);
@@ -182,51 +210,100 @@ public:
static void uriChanged(GObject*, GParamSpec*, ViewURITrackingTest* test)
{
- g_assert_cmpstr(test->m_activeURI.data(), !=, webkit_web_view_get_uri(test->m_webView));
- test->m_activeURI = webkit_web_view_get_uri(test->m_webView);
+ g_assert_cmpstr(test->m_currentURI.data(), !=, webkit_web_view_get_uri(test->m_webView));
+ test->m_currentURI = webkit_web_view_get_uri(test->m_webView);
}
ViewURITrackingTest()
- : m_activeURI(webkit_web_view_get_uri(m_webView))
+ : m_currentURI(webkit_web_view_get_uri(m_webView))
{
- g_assert(m_activeURI.isNull());
+ g_assert(m_currentURI.isNull());
+ m_currentURIList.grow(m_currentURIList.capacity());
g_signal_connect(m_webView, "notify::uri", G_CALLBACK(uriChanged), this);
}
+ enum State { Provisional, ProvisionalAfterRedirect, Commited, Finished };
+
+ void loadURI(const char* uri)
+ {
+ reset();
+ LoadTrackingTest::loadURI(uri);
+ }
+
void provisionalLoadStarted()
{
- checkActiveURI("/redirect");
+ m_currentURIList[Provisional] = m_currentURI;
}
void provisionalLoadReceivedServerRedirect()
{
- checkActiveURI("/normal");
+ m_currentURIList[ProvisionalAfterRedirect] = m_currentURI;
}
void loadCommitted()
{
- checkActiveURI("/normal");
+ m_currentURIList[Commited] = m_currentURI;
}
void loadFinished()
{
- checkActiveURI("/normal");
+ m_currentURIList[Finished] = m_currentURI;
LoadTrackingTest::loadFinished();
}
- CString m_activeURI;
+ void checkURIAtState(State state, const char* path)
+ {
+ if (path)
+ ASSERT_CMP_CSTRING(m_currentURIList[state], ==, kServer->getURIForPath(path));
+ else
+ g_assert(m_currentURIList[state].isNull());
+ }
private:
- void checkActiveURI(const char* uri)
+ void reset()
{
- ASSERT_CMP_CSTRING(m_activeURI, ==, kServer->getURIForPath(uri));
+ m_currentURI = CString();
+ m_currentURIList.clear();
+ m_currentURIList.grow(m_currentURIList.capacity());
}
+
+ CString m_currentURI;
+ Vector<CString, 4> m_currentURIList;
};
static void testWebViewActiveURI(ViewURITrackingTest* test, gconstpointer)
{
+ // Normal load, the URL doesn't change.
+ test->loadURI(kServer->getURIForPath("/normal1").data());
+ test->waitUntilLoadFinished();
+ test->checkURIAtState(ViewURITrackingTest::State::Provisional, "/normal1");
+ test->checkURIAtState(ViewURITrackingTest::State::ProvisionalAfterRedirect, nullptr);
+ test->checkURIAtState(ViewURITrackingTest::State::Commited, "/normal1");
+ test->checkURIAtState(ViewURITrackingTest::State::Finished, "/normal1");
+
+ // Redirect, the URL changes after the redirect.
test->loadURI(kServer->getURIForPath("/redirect").data());
test->waitUntilLoadFinished();
+ test->checkURIAtState(ViewURITrackingTest::State::Provisional, "/redirect");
+ test->checkURIAtState(ViewURITrackingTest::State::ProvisionalAfterRedirect, "/normal");
+ test->checkURIAtState(ViewURITrackingTest::State::Commited, "/normal");
+ test->checkURIAtState(ViewURITrackingTest::State::Finished, "/normal");
+
+ // Normal load, URL changed by WebKitPage::send-request.
+ test->loadURI(kServer->getURIForPath("/normal-change-request").data());
+ test->waitUntilLoadFinished();
+ test->checkURIAtState(ViewURITrackingTest::State::Provisional, "/normal-change-request");
+ test->checkURIAtState(ViewURITrackingTest::State::ProvisionalAfterRedirect, nullptr);
+ test->checkURIAtState(ViewURITrackingTest::State::Commited, "/request-changed");
+ test->checkURIAtState(ViewURITrackingTest::State::Finished, "/request-changed");
+
+ // Redirect, URL changed by WebKitPage::send-request.
+ test->loadURI(kServer->getURIForPath("/redirect-to-change-request").data());
+ test->waitUntilLoadFinished();
+ test->checkURIAtState(ViewURITrackingTest::State::Provisional, "/redirect-to-change-request");
+ test->checkURIAtState(ViewURITrackingTest::State::ProvisionalAfterRedirect, "/normal-change-request");
+ test->checkURIAtState(ViewURITrackingTest::State::Commited, "/request-changed-on-redirect");
+ test->checkURIAtState(ViewURITrackingTest::State::Finished, "/request-changed-on-redirect");
}
class ViewIsLoadingTest: public LoadTrackingTest {
@@ -303,7 +380,8 @@ public:
WebPageURITest()
{
- GRefPtr<GDBusProxy> proxy = adoptGRef(bus->createProxy("org.webkit.gtk.WebExtensionTest",
+ GUniquePtr<char> extensionBusName(g_strdup_printf("org.webkit.gtk.WebExtensionTest%u", Test::s_webExtensionID));
+ GRefPtr<GDBusProxy> proxy = adoptGRef(bus->createProxy(extensionBusName.get(),
"/org/webkit/gtk/WebExtensionTest", "org.webkit.gtk.WebExtensionTest", m_mainLoop));
m_uriChangedSignalID = g_dbus_connection_signal_subscribe(
g_dbus_proxy_get_connection(proxy.get()),
@@ -327,6 +405,20 @@ public:
g_dbus_connection_signal_unsubscribe(bus->connection(), m_uriChangedSignalID);
}
+ void loadURI(const char* uri)
+ {
+ m_webPageURIs.clear();
+ m_webViewURIs.clear();
+ WebViewTest::loadURI(uri);
+ }
+
+ void checkViewAndPageURIsMatch() const
+ {
+ g_assert_cmpint(m_webPageURIs.size(), ==, m_webViewURIs.size());
+ for (size_t i = 0; i < m_webPageURIs.size(); ++i)
+ ASSERT_CMP_CSTRING(m_webPageURIs[i], ==, m_webViewURIs[i]);
+ }
+
unsigned m_uriChangedSignalID;
Vector<CString> m_webPageURIs;
Vector<CString> m_webViewURIs;
@@ -334,17 +426,37 @@ public:
static void testWebPageURI(WebPageURITest* test, gconstpointer)
{
- test->loadURI(kServer->getURIForPath("/redirect").data());
+ // Normal load.
+ test->loadURI(kServer->getURIForPath("/normal1").data());
test->waitUntilLoadFinished();
+ test->checkViewAndPageURIsMatch();
+ g_assert_cmpint(test->m_webPageURIs.size(), ==, 1);
+ ASSERT_CMP_CSTRING(test->m_webPageURIs[0], ==, kServer->getURIForPath("/normal1"));
- g_assert_cmpint(test->m_webPageURIs.size(), ==, test->m_webViewURIs.size());
- for (size_t i = 0; i < test->m_webPageURIs.size(); ++i)
- ASSERT_CMP_CSTRING(test->m_webPageURIs[i], ==, test->m_webViewURIs[i]);
-
+ // Redirect
+ test->loadURI(kServer->getURIForPath("/redirect").data());
+ test->waitUntilLoadFinished();
+ test->checkViewAndPageURIsMatch();
g_assert_cmpint(test->m_webPageURIs.size(), ==, 2);
ASSERT_CMP_CSTRING(test->m_webPageURIs[0], ==, kServer->getURIForPath("/redirect"));
ASSERT_CMP_CSTRING(test->m_webPageURIs[1], ==, kServer->getURIForPath("/normal"));
+ // Normal load, URL changed by WebKitPage::send-request.
+ test->loadURI(kServer->getURIForPath("/normal-change-request").data());
+ test->waitUntilLoadFinished();
+ test->checkViewAndPageURIsMatch();
+ g_assert_cmpint(test->m_webPageURIs.size(), ==, 2);
+ ASSERT_CMP_CSTRING(test->m_webPageURIs[0], ==, kServer->getURIForPath("/normal-change-request"));
+ ASSERT_CMP_CSTRING(test->m_webPageURIs[1], ==, kServer->getURIForPath("/request-changed"));
+
+ // Redirect, URL changed by WebKitPage::send-request.
+ test->loadURI(kServer->getURIForPath("/redirect-to-change-request").data());
+ test->waitUntilLoadFinished();
+ test->checkViewAndPageURIsMatch();
+ g_assert_cmpint(test->m_webPageURIs.size(), ==, 3);
+ ASSERT_CMP_CSTRING(test->m_webPageURIs[0], ==, kServer->getURIForPath("/redirect-to-change-request"));
+ ASSERT_CMP_CSTRING(test->m_webPageURIs[1], ==, kServer->getURIForPath("/normal-change-request"));
+ ASSERT_CMP_CSTRING(test->m_webPageURIs[2], ==, kServer->getURIForPath("/request-changed-on-redirect"));
}
static void testURIRequestHTTPHeaders(WebViewTest* test, gconstpointer)
@@ -384,6 +496,53 @@ static void testURIRequestHTTPHeaders(WebViewTest* test, gconstpointer)
g_assert(!strncmp(mainResourceData, "1", mainResourceDataSize));
}
+static void testURIRequestHTTPMethod(WebViewTest* test, gconstpointer)
+{
+ GRefPtr<WebKitURIRequest> uriRequest = adoptGRef(webkit_uri_request_new("file:///foo/bar"));
+ g_assert(uriRequest.get());
+ g_assert_cmpstr(webkit_uri_request_get_uri(uriRequest.get()), ==, "file:///foo/bar");
+ g_assert(!webkit_uri_request_get_http_method(uriRequest.get()));
+
+ webkit_uri_request_set_uri(uriRequest.get(), kServer->getURIForPath("/http-get-method").data());
+ test->loadRequest(uriRequest.get());
+ test->waitUntilLoadFinished();
+
+ test->runJavaScriptAndWaitUntilFinished("xhr = new XMLHttpRequest; xhr.open('POST', '/http-post-method', false); xhr.send();", nullptr);
+}
+
+static void testURIResponseHTTPHeaders(WebViewTest* test, gconstpointer)
+{
+ test->loadHtml("<html><body>No HTTP headers</body></html>", "file:///");
+ test->waitUntilLoadFinished();
+ WebKitWebResource* resource = webkit_web_view_get_main_resource(test->m_webView);
+ g_assert(WEBKIT_IS_WEB_RESOURCE(resource));
+ WebKitURIResponse* response = webkit_web_resource_get_response(resource);
+ g_assert(WEBKIT_IS_URI_RESPONSE(response));
+ g_assert(!webkit_uri_response_get_http_headers(response));
+
+ test->loadURI(kServer->getURIForPath("/headers").data());
+ test->waitUntilLoadFinished();
+ resource = webkit_web_view_get_main_resource(test->m_webView);
+ g_assert(WEBKIT_IS_WEB_RESOURCE(resource));
+ response = webkit_web_resource_get_response(resource);
+ g_assert(WEBKIT_IS_URI_RESPONSE(response));
+ SoupMessageHeaders* headers = webkit_uri_response_get_http_headers(response);
+ g_assert(headers);
+ g_assert_cmpstr(soup_message_headers_get_one(headers, "Foo"), ==, "bar");
+}
+
+static void testRedirectToDataURI(WebViewTest* test, gconstpointer)
+{
+ test->loadURI(kServer->getURIForPath("/redirect-to-data").data());
+ test->waitUntilLoadFinished();
+
+ static const char* expectedData = "data-uri";
+ size_t mainResourceDataSize = 0;
+ const char* mainResourceData = test->mainResourceData(mainResourceDataSize);
+ g_assert_cmpint(mainResourceDataSize, ==, strlen(expectedData));
+ g_assert(!strncmp(mainResourceData, expectedData, mainResourceDataSize));
+}
+
static void serverCallback(SoupServer* server, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, gpointer)
{
static const char* responseString = "<html><body>Testing!Testing!Testing!Testing!Testing!Testing!Testing!"
@@ -402,13 +561,16 @@ static void serverCallback(SoupServer* server, SoupMessage* message, const char*
soup_message_set_status(message, SOUP_STATUS_OK);
- if (g_str_has_prefix(path, "/normal"))
+ if (g_str_has_prefix(path, "/normal") || g_str_has_prefix(path, "/http-get-method"))
soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, responseString, strlen(responseString));
else if (g_str_equal(path, "/error"))
soup_message_set_status(message, SOUP_STATUS_CANT_CONNECT);
else if (g_str_equal(path, "/redirect")) {
soup_message_set_status(message, SOUP_STATUS_MOVED_PERMANENTLY);
soup_message_headers_append(message->response_headers, "Location", "/normal");
+ } else if (g_str_equal(path, "/redirect-to-change-request")) {
+ soup_message_set_status(message, SOUP_STATUS_MOVED_PERMANENTLY);
+ soup_message_headers_append(message->response_headers, "Location", "/normal-change-request");
} else if (g_str_equal(path, "/cancelled")) {
soup_message_headers_set_encoding(message->response_headers, SOUP_ENCODING_CHUNKED);
soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, responseString, strlen(responseString));
@@ -421,6 +583,12 @@ static void serverCallback(SoupServer* server, SoupMessage* message, const char*
else
soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, kDNTHeaderNotPresent, strlen(kDNTHeaderNotPresent));
soup_message_set_status(message, SOUP_STATUS_OK);
+ } else if (g_str_equal(path, "/headers")) {
+ soup_message_headers_append(message->response_headers, "Foo", "bar");
+ soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, responseString, strlen(responseString));
+ } else if (g_str_equal(path, "/redirect-to-data")) {
+ soup_message_set_status(message, SOUP_STATUS_MOVED_PERMANENTLY);
+ soup_message_headers_append(message->response_headers, "Location", "data:text/plain;charset=utf-8,data-uri");
} else
soup_message_set_status(message, SOUP_STATUS_NOT_FOUND);
@@ -429,7 +597,6 @@ static void serverCallback(SoupServer* server, SoupMessage* message, const char*
void beforeAll()
{
- webkit_web_context_set_web_extensions_directory(webkit_web_context_get_default(), WEBKIT_TEST_WEB_EXTENSIONS_DIR);
bus = new WebKitTestBus();
if (!bus->run())
return;
@@ -441,8 +608,11 @@ void beforeAll()
LoadTrackingTest::add("WebKitWebView", "loading-error", testLoadingError);
LoadTrackingTest::add("WebKitWebView", "load-html", testLoadHtml);
LoadTrackingTest::add("WebKitWebView", "load-alternate-html", testLoadAlternateHTML);
+ LoadTrackingTest::add("WebKitWebView", "load-alternate-html-for-local-page", testLoadAlternateHTMLForLocalPage);
LoadTrackingTest::add("WebKitWebView", "load-plain-text", testLoadPlainText);
+ LoadTrackingTest::add("WebKitWebView", "load-bytes", testLoadBytes);
LoadTrackingTest::add("WebKitWebView", "load-request", testLoadRequest);
+ LoadTrackingTest::add("WebKitWebView", "load-gresource", testLoadFromGResource);
LoadStopTrackingTest::add("WebKitWebView", "stop-loading", testLoadCancelled);
LoadTrackingTest::add("WebKitWebView", "title", testWebViewTitle);
LoadTrackingTest::add("WebKitWebView", "progress", testLoadProgress);
@@ -456,6 +626,9 @@ void beforeAll()
ViewIsLoadingTest::add("WebKitWebView", "is-loading", testWebViewIsLoading);
WebPageURITest::add("WebKitWebPage", "get-uri", testWebPageURI);
WebViewTest::add("WebKitURIRequest", "http-headers", testURIRequestHTTPHeaders);
+ WebViewTest::add("WebKitURIRequest", "http-method", testURIRequestHTTPMethod);
+ WebViewTest::add("WebKitURIResponse", "http-headers", testURIResponseHTTPHeaders);
+ WebViewTest::add("WebKitWebPage", "redirect-to-data-uri", testRedirectToDataURI);
}
void afterAll()
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestMultiprocess.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestMultiprocess.cpp
index f48b6a3b6..020ad3529 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestMultiprocess.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestMultiprocess.cpp
@@ -26,8 +26,6 @@
#include <wtf/Vector.h>
static const unsigned numViews = 2;
-static guint32 nextInitializationId = 1;
-static unsigned initializeWebExtensionsSignalCount;
static WebKitTestBus* bus;
class MultiprocessTest: public Test {
@@ -36,8 +34,18 @@ public:
MultiprocessTest()
: m_mainLoop(g_main_loop_new(nullptr, TRUE))
+ , m_initializeWebExtensionsSignalCount(0)
, m_webViewBusNames(numViews)
- , m_webViews(numViews) { }
+ , m_webViews(numViews)
+ {
+ webkit_web_context_set_process_model(m_webContext.get(), WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES);
+ }
+
+ void initializeWebExtensions() override
+ {
+ Test::initializeWebExtensions();
+ m_initializeWebExtensionsSignalCount++;
+ }
static void loadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent, MultiprocessTest* test)
{
@@ -51,11 +59,11 @@ public:
{
g_assert_cmpuint(index, <, numViews);
- m_webViewBusNames[index] = GUniquePtr<char>(g_strdup_printf("org.webkit.gtk.WebExtensionTest%u", nextInitializationId));
-
- m_webViews[index] = WEBKIT_WEB_VIEW(webkit_web_view_new());
+ m_webViews[index] = WEBKIT_WEB_VIEW(webkit_web_view_new_with_context(m_webContext.get()));
assertObjectIsDeletedWhenTestFinishes(G_OBJECT(m_webViews[index].get()));
+ m_webViewBusNames[index] = GUniquePtr<char>(g_strdup_printf("org.webkit.gtk.WebExtensionTest%u", Test::s_webExtensionID));
+
webkit_web_view_load_html(m_webViews[index].get(), "<html></html>", nullptr);
g_signal_connect(m_webViews[index].get(), "load-changed", G_CALLBACK(loadChanged), this);
g_main_loop_run(m_mainLoop);
@@ -88,8 +96,6 @@ public:
void destroyWebViewAndWaitUntilWebProcessFinishes(unsigned index)
{
- // FIXME: This test is disabled because the web processed don't actually die
- // due to bug https://bugs.webkit.org/show_bug.cgi?id=129684.
g_assert_cmpuint(index, <, numViews);
unsigned watcherID = g_bus_watch_name_on_connection(bus->connection(), m_webViewBusNames[index].get(), G_BUS_NAME_WATCHER_FLAGS_NONE,
@@ -100,6 +106,7 @@ public:
}
GMainLoop* m_mainLoop;
+ unsigned m_initializeWebExtensionsSignalCount;
Vector<GUniquePtr<char>, numViews> m_webViewBusNames;
Vector<GRefPtr<WebKitWebView>, numViews> m_webViews;
};
@@ -118,7 +125,7 @@ static void testProcessPerWebView(MultiprocessTest* test, gconstpointer)
g_assert(test->m_webViewBusNames[i]);
}
- g_assert_cmpuint(initializeWebExtensionsSignalCount, ==, numViews);
+ g_assert_cmpuint(test->m_initializeWebExtensionsSignalCount, ==, numViews);
g_assert_cmpstr(test->m_webViewBusNames[0].get(), !=, test->m_webViewBusNames[1].get());
g_assert_cmpuint(test->webProcessPid(0), !=, test->webProcessPid(1));
@@ -130,7 +137,7 @@ static void testProcessPerWebView(MultiprocessTest* test, gconstpointer)
}
}
-class UIClientMultiprocessTest: public WebViewTest {
+class UIClientMultiprocessTest: public Test {
public:
MAKE_GLIB_TEST_FIXTURE(UIClientMultiprocessTest);
@@ -140,7 +147,7 @@ public:
Close
};
- static GtkWidget* viewCreateCallback(WebKitWebView* webView, UIClientMultiprocessTest* test)
+ static GtkWidget* viewCreateCallback(WebKitWebView* webView, WebKitNavigationAction*, UIClientMultiprocessTest* test)
{
return test->viewCreate(webView);
}
@@ -156,14 +163,26 @@ public:
}
UIClientMultiprocessTest()
+ : m_mainLoop(g_main_loop_new(nullptr, TRUE))
+ , m_initializeWebExtensionsSignalCount(0)
{
+ webkit_web_context_set_process_model(m_webContext.get(), WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES);
+ m_webView = WEBKIT_WEB_VIEW(g_object_ref_sink(webkit_web_view_new_with_context(m_webContext.get())));
webkit_settings_set_javascript_can_open_windows_automatically(webkit_web_view_get_settings(m_webView), TRUE);
+
g_signal_connect(m_webView, "create", G_CALLBACK(viewCreateCallback), this);
}
~UIClientMultiprocessTest()
{
g_signal_handlers_disconnect_matched(m_webView, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
+ gtk_widget_destroy(GTK_WIDGET(m_webView));
+ }
+
+ void initializeWebExtensions() override
+ {
+ Test::initializeWebExtensions();
+ m_initializeWebExtensionsSignalCount++;
}
GtkWidget* viewCreate(WebKitWebView* webView)
@@ -201,16 +220,15 @@ public:
g_main_loop_run(m_mainLoop);
}
+ WebKitWebView* m_webView;
+ GMainLoop* m_mainLoop;
+ unsigned m_initializeWebExtensionsSignalCount;
Vector<WebViewEvents> m_webViewEvents;
};
static void testMultiprocessWebViewCreateReadyClose(UIClientMultiprocessTest* test, gconstpointer)
{
- // At this point the web process of the current view has already been created.
- // We save it here to check that after window.open() the number of processes
- // is the same.
- guint32 processCountBefore = nextInitializationId - 1;
- test->loadHtml("<html><body onLoad=\"window.open().close();\"></html>", nullptr);
+ webkit_web_view_load_html(test->m_webView, "<html><body onLoad=\"window.open().close();\"></html>", nullptr);
test->waitUntilNewWebViewClose();
Vector<UIClientMultiprocessTest::WebViewEvents>& events = test->m_webViewEvents;
@@ -219,23 +237,27 @@ static void testMultiprocessWebViewCreateReadyClose(UIClientMultiprocessTest* te
g_assert_cmpint(events[1], ==, UIClientMultiprocessTest::ReadyToShow);
g_assert_cmpint(events[2], ==, UIClientMultiprocessTest::Close);
- guint32 processesCountAfter = nextInitializationId - 1;
- g_assert_cmpuint(processesCountAfter, ==, processCountBefore);
+ g_assert_cmpuint(test->m_initializeWebExtensionsSignalCount, ==, 1);
}
-static void initializeWebExtensions(WebKitWebContext* context, gpointer)
+static void testWebProcessLimit(MultiprocessTest* test, gconstpointer)
{
- initializeWebExtensionsSignalCount++;
- webkit_web_context_set_web_extensions_directory(context, WEBKIT_TEST_WEB_EXTENSIONS_DIR);
- webkit_web_context_set_web_extensions_initialization_user_data(context,
- g_variant_new_uint32(nextInitializationId++));
+ g_assert_cmpuint(webkit_web_context_get_web_process_count_limit(test->m_webContext.get()), ==, 0);
+
+ webkit_web_context_set_web_process_count_limit(test->m_webContext.get(), 1);
+ g_assert_cmpuint(webkit_web_context_get_web_process_count_limit(test->m_webContext.get()), ==, 1);
+
+ // Create two web views but there should be only one web process.
+ for (unsigned i = 0; i < numViews; i++) {
+ test->loadWebViewAndWaitUntilLoaded(i);
+ g_assert(WEBKIT_IS_WEB_VIEW(test->m_webViews[i].get()));
+ }
+
+ g_assert_cmpuint(test->m_initializeWebExtensionsSignalCount, ==, 1);
}
void beforeAll()
{
- g_signal_connect(webkit_web_context_get_default(),
- "initialize-web-extensions", G_CALLBACK(initializeWebExtensions), nullptr);
-
// Check that default setting is the one stated in the documentation
g_assert_cmpuint(webkit_web_context_get_process_model(webkit_web_context_get_default()),
==, WEBKIT_PROCESS_MODEL_SHARED_SECONDARY_PROCESS);
@@ -253,11 +275,10 @@ void beforeAll()
MultiprocessTest::add("WebKitWebContext", "process-per-web-view", testProcessPerWebView);
UIClientMultiprocessTest::add("WebKitWebView", "multiprocess-create-ready-close", testMultiprocessWebViewCreateReadyClose);
+ MultiprocessTest::add("WebKitWebContext", "web-process-limit", testWebProcessLimit);
}
void afterAll()
{
delete bus;
- g_signal_handlers_disconnect_by_func(webkit_web_context_get_default(),
- reinterpret_cast<void*>(initializeWebExtensions), nullptr);
}
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestPrinting.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestPrinting.cpp
index 99efa7cfb..2b5221192 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestPrinting.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestPrinting.cpp
@@ -20,14 +20,12 @@
#include "config.h"
#include "WebViewTest.h"
#include <glib/gstdio.h>
-#include <wtf/gobject/GRefPtr.h>
+#include <wtf/glib/GRefPtr.h>
#ifdef HAVE_GTK_UNIX_PRINTING
#include <gtk/gtkunixprint.h>
#endif
-static char* kTempDirectory;
-
static void testPrintOperationPrintSettings(WebViewTest* test, gconstpointer)
{
GRefPtr<WebKitPrintOperation> printOperation = adoptGRef(webkit_print_operation_new(test->m_webView));
@@ -134,7 +132,7 @@ static void testPrintOperationPrint(PrintTest* test, gconstpointer)
return;
}
- GUniquePtr<char> outputFilename(g_build_filename(kTempDirectory, "webkit-print.pdf", NULL));
+ GUniquePtr<char> outputFilename(g_build_filename(Test::dataDirectory(), "webkit-print.pdf", nullptr));
GRefPtr<GFile> outputFile = adoptGRef(g_file_new_for_path(outputFilename.get()));
GUniquePtr<char> outputURI(g_file_get_uri(outputFile.get()));
@@ -194,7 +192,7 @@ class CloseAfterPrintTest: public WebViewTest {
public:
MAKE_GLIB_TEST_FIXTURE(CloseAfterPrintTest);
- static GtkWidget* webViewCreate(WebKitWebView* webView, CloseAfterPrintTest* test)
+ static GtkWidget* webViewCreate(WebKitWebView* webView, WebKitNavigationAction*, CloseAfterPrintTest* test)
{
return test->createWebView();
}
@@ -228,7 +226,7 @@ public:
GtkWidget* createWebView()
{
- GtkWidget* newWebView = webkit_web_view_new();
+ GtkWidget* newWebView = webkit_web_view_new_with_context(m_webContext.get());
g_object_ref_sink(newWebView);
assertObjectIsDeletedWhenTestFinishes(G_OBJECT(newWebView));
@@ -247,7 +245,7 @@ public:
return;
}
- GUniquePtr<char> outputFilename(g_build_filename(kTempDirectory, "webkit-close-after-print.pdf", NULL));
+ GUniquePtr<char> outputFilename(g_build_filename(Test::dataDirectory(), "webkit-close-after-print.pdf", nullptr));
m_outputFile = adoptGRef(g_file_new_for_path(outputFilename.get()));
GUniquePtr<char> outputURI(g_file_get_uri(m_outputFile.get()));
@@ -288,23 +286,210 @@ static void testPrintOperationCloseAfterPrint(CloseAfterPrintTest* test, gconstp
test->loadHtml("<html><body onLoad=\"w = window.open();w.print();w.close();\"></body></html>", 0);
test->waitUntilPrintFinishedAndViewClosed();
}
+
+class PrintCustomWidgetTest: public WebViewTest {
+public:
+ MAKE_GLIB_TEST_FIXTURE(PrintCustomWidgetTest);
+
+ static void applyCallback(WebKitPrintCustomWidget*, PrintCustomWidgetTest* test)
+ {
+ test->m_applyEmitted = true;
+ }
+
+ static gboolean scheduleJumpToCustomWidget(PrintCustomWidgetTest* test)
+ {
+ test->jumpToCustomWidget();
+
+ return FALSE;
+ }
+
+ static void updateCallback(WebKitPrintCustomWidget* customWidget, GtkPageSetup*, GtkPrintSettings*, PrintCustomWidgetTest* test)
+ {
+ g_assert(test->m_widget == webkit_print_custom_widget_get_widget(customWidget));
+
+ test->m_updateEmitted = true;
+ // Would be nice to avoid the 1 second timeout here - but I didn't found
+ // a way to do so without making the test flaky.
+ g_timeout_add_seconds(1, reinterpret_cast<GSourceFunc>(scheduleJumpToCustomWidget), test);
+ }
+
+ static void widgetRealizeCallback(GtkWidget* widget, PrintCustomWidgetTest* test)
+ {
+ g_assert(GTK_IS_LABEL(widget));
+ g_assert(!g_strcmp0(gtk_label_get_text(GTK_LABEL(widget)), "Label"));
+
+ test->m_widgetRealized = true;
+ test->startPrinting();
+ }
+
+ static WebKitPrintCustomWidget* createCustomWidgetCallback(WebKitPrintOperation* printOperation, PrintCustomWidgetTest* test)
+ {
+ test->m_createEmitted = true;
+ WebKitPrintCustomWidget* printCustomWidget = test->createPrintCustomWidget();
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(printCustomWidget));
+ g_signal_connect(printCustomWidget, "apply", G_CALLBACK(applyCallback), test);
+ g_signal_connect(printCustomWidget, "update", G_CALLBACK(updateCallback), test);
+
+ GtkWidget* widget = webkit_print_custom_widget_get_widget(printCustomWidget);
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(widget));
+ g_signal_connect(widget, "realize", G_CALLBACK(widgetRealizeCallback), test);
+
+ return printCustomWidget;
+ }
+
+ static gboolean scheduleMovementThroughDialog(PrintCustomWidgetTest* test)
+ {
+ test->jumpToFirstPrinter();
+
+ return FALSE;
+ }
+
+ static gboolean openPrintDialog(PrintCustomWidgetTest* test)
+ {
+ g_idle_add(reinterpret_cast<GSourceFunc>(scheduleMovementThroughDialog), test);
+ test->m_response = webkit_print_operation_run_dialog(test->m_printOperation.get(), GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(test->m_webView))));
+
+ return FALSE;
+ }
+
+ static void printOperationFinished(WebKitPrintOperation* printOperation, PrintCustomWidgetTest* test)
+ {
+ test->printFinished();
+ }
+
+ void printFinished()
+ {
+ g_assert(m_outputFile);
+ g_file_delete(m_outputFile.get(), nullptr, nullptr);
+ m_outputFile = nullptr;
+ g_main_loop_quit(m_mainLoop);
+ }
+
+ void sendKeyEvent(unsigned gdkKeyValue, GdkEventType type, unsigned modifiers)
+ {
+ GdkEvent* event = gdk_event_new(type);
+ event->key.keyval = gdkKeyValue;
+ event->key.state = modifiers;
+ event->key.window = gtk_widget_get_window(GTK_WIDGET(m_webView));
+ event->key.time = GDK_CURRENT_TIME;
+ g_object_ref(event->key.window);
+ gdk_event_set_device(event, gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(gdk_display_get_default())));
+
+ GUniqueOutPtr<GdkKeymapKey> keys;
+ gint nKeys;
+ if (gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), gdkKeyValue, &keys.outPtr(), &nKeys))
+ event->key.hardware_keycode = keys.get()[0].keycode;
+
+ gtk_main_do_event(event);
+
+ gdk_event_free(event);
+ }
+
+ void sendKeyPressAndReleaseEvent(unsigned gdkKeyValue, unsigned modifiers = 0)
+ {
+ sendKeyEvent(gdkKeyValue, GDK_KEY_PRESS, modifiers);
+ sendKeyEvent(gdkKeyValue, GDK_KEY_RELEASE, modifiers);
+ }
+
+ void createWebKitPrintOperation()
+ {
+ m_printOperation = adoptGRef(webkit_print_operation_new(m_webView));
+ g_assert(m_printOperation);
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(m_printOperation.get()));
+
+ g_signal_connect(m_printOperation.get(), "create-custom-widget", G_CALLBACK(createCustomWidgetCallback), this);
+ g_signal_connect(m_printOperation.get(), "finished", G_CALLBACK(printOperationFinished), this);
+ }
+
+ WebKitPrintCustomWidget* createPrintCustomWidget()
+ {
+ m_widget = gtk_label_new("Label");
+ return webkit_print_custom_widget_new(m_widget, "Custom Widget");
+ }
+
+ void startPrinting()
+ {
+ // To start printing it is enough to press the Return key
+ sendKeyPressAndReleaseEvent(GDK_KEY_Return);
+ }
+
+ void jumpToFirstPrinter()
+ {
+ // Initially the GtkNotebook has focus, so we just need to press the Tab
+ // key to jump to the first printer
+ sendKeyPressAndReleaseEvent(GDK_KEY_Tab);
+ }
+
+ void jumpToCustomWidget()
+ {
+ // Jump back to the GtkNotebook
+ sendKeyPressAndReleaseEvent(GDK_KEY_Tab, GDK_SHIFT_MASK);
+ // Custom widget is on the third tab
+ sendKeyPressAndReleaseEvent(GDK_KEY_Right);
+ sendKeyPressAndReleaseEvent(GDK_KEY_Right);
+ }
+
+ void openDialogMoveThroughItAndWaitUntilClosed()
+ {
+ g_idle_add(reinterpret_cast<GSourceFunc>(openPrintDialog), this);
+ g_main_loop_run(m_mainLoop);
+ }
+
+ GRefPtr<WebKitPrintOperation> m_printOperation;
+ GRefPtr<GFile> m_outputFile;
+ GtkWidget* m_widget;
+ bool m_widgetRealized {false};
+ bool m_applyEmitted {false};
+ bool m_updateEmitted {false};
+ bool m_createEmitted {false};
+ WebKitPrintOperationResponse m_response {WEBKIT_PRINT_OPERATION_RESPONSE_CANCEL};
+};
+
+static void testPrintCustomWidget(PrintCustomWidgetTest* test, gconstpointer)
+{
+ test->showInWindowAndWaitUntilMapped(GTK_WINDOW_TOPLEVEL, 0, 0);
+
+ test->loadHtml("<html><body>Text</body></html>", 0);
+ test->waitUntilLoadFinished();
+
+ test->createWebKitPrintOperation();
+
+ GRefPtr<GtkPrinter> printer = adoptGRef(findPrintToFilePrinter());
+ if (!printer) {
+ g_message("%s", "Cannot test WebKitPrintOperation/print: no suitable printer found");
+ return;
+ }
+
+ GUniquePtr<char> outputFilename(g_build_filename(Test::dataDirectory(), "webkit-close-after-print.pdf", nullptr));
+ test->m_outputFile = adoptGRef(g_file_new_for_path(outputFilename.get()));
+ GUniquePtr<char> outputURI(g_file_get_uri(test->m_outputFile.get()));
+
+ GRefPtr<GtkPrintSettings> printSettings = adoptGRef(gtk_print_settings_new());
+ gtk_print_settings_set(printSettings.get(), GTK_PRINT_SETTINGS_OUTPUT_URI, outputURI.get());
+ webkit_print_operation_set_print_settings(test->m_printOperation.get(), printSettings.get());
+
+ test->openDialogMoveThroughItAndWaitUntilClosed();
+
+ g_assert(test->m_response == WEBKIT_PRINT_OPERATION_RESPONSE_PRINT);
+ g_assert(test->m_createEmitted);
+ g_assert(test->m_widgetRealized);
+ g_assert(test->m_updateEmitted);
+ g_assert(test->m_applyEmitted);
+}
#endif // HAVE_GTK_UNIX_PRINTING
void beforeAll()
{
- kTempDirectory = g_dir_make_tmp("WebKit2Tests-XXXXXX", 0);
- g_assert(kTempDirectory);
-
WebViewTest::add("WebKitPrintOperation", "printing-settings", testPrintOperationPrintSettings);
WebViewTest::add("WebKitWebView", "print", testWebViewPrint);
#ifdef HAVE_GTK_UNIX_PRINTING
PrintTest::add("WebKitPrintOperation", "print", testPrintOperationPrint);
PrintTest::add("WebKitPrintOperation", "print-errors", testPrintOperationErrors);
CloseAfterPrintTest::add("WebKitPrintOperation", "close-after-print", testPrintOperationCloseAfterPrint);
+ PrintCustomWidgetTest::add("WebKitPrintOperation", "custom-widget", testPrintCustomWidget);
#endif
}
void afterAll()
{
- g_rmdir(kTempDirectory);
}
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestResources.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestResources.cpp
index 4d97846a2..1510e5d49 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestResources.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestResources.cpp
@@ -22,7 +22,8 @@
#include "WebKitTestServer.h"
#include "WebViewTest.h"
#include <wtf/Vector.h>
-#include <wtf/gobject/GRefPtr.h>
+#include <wtf/glib/GMutexLocker.h>
+#include <wtf/glib/GRefPtr.h>
static WebKitTestServer* kServer;
@@ -189,6 +190,13 @@ public:
} else if (uri == kServer->getURIForPath("/javascript.js")) {
g_assert_cmpint(m_resourceDataSize, ==, strlen(kJavascript));
g_assert(!strncmp(m_resourceData.get(), kJavascript, m_resourceDataSize));
+ } else if (uri == kServer->getURIForPath("/blank.ico")) {
+ GUniquePtr<char> filePath(g_build_filename(Test::getResourcesDir().data(), "blank.ico", nullptr));
+ GUniqueOutPtr<char> contents;
+ gsize contentsLength;
+ g_file_get_contents(filePath.get(), &contents.outPtr(), &contentsLength, nullptr);
+ g_assert_cmpint(m_resourceDataSize, ==, contentsLength);
+ g_assert(!memcmp(m_resourceData.get(), contents.get(), contentsLength));
} else
g_assert_not_reached();
m_resourceData.reset();
@@ -417,7 +425,7 @@ static void testWebResourceMimeType(SingleResourceLoadTest* test, gconstpointer)
test->loadURI(kServer->getURIForPath("/image.html").data());
response = test->waitUntilResourceLoadFinishedAndReturnURIResponse();
- g_assert_cmpstr(webkit_uri_response_get_mime_type(response), ==, "image/vnd.microsoft.icon");
+ g_assert_cmpstr(webkit_uri_response_get_mime_type(response), ==, "image/x-icon");
test->loadURI(kServer->getURIForPath("/redirected-css.html").data());
response = test->waitUntilResourceLoadFinishedAndReturnURIResponse();
@@ -517,9 +525,7 @@ static void testWebResourceActiveURI(ResourceURITrackingTest* test, gconstpointe
static void testWebResourceGetData(ResourcesTest* test, gconstpointer)
{
test->loadURI(kServer->getURIForPath("/").data());
- // FIXME: this should be 4 instead of 3, but we don't get the css image resource
- // due to bug https://bugs.webkit.org/show_bug.cgi?id=78510.
- test->waitUntilResourcesLoaded(3);
+ test->waitUntilResourcesLoaded(4);
WebKitWebResource* resource = webkit_web_view_get_main_resource(test->m_webView);
g_assert(resource);
@@ -667,6 +673,66 @@ static void testWebResourceSendRequest(SendRequestTest* test, gconstpointer)
events.clear();
}
+static GMutex s_serverMutex;
+static const unsigned s_maxConnectionsPerHost = 6;
+
+class SyncRequestOnMaxConnsTest: public ResourcesTest {
+public:
+ MAKE_GLIB_TEST_FIXTURE(SyncRequestOnMaxConnsTest);
+
+ void resourceLoadStarted(WebKitWebResource*, WebKitURIRequest*) override
+ {
+ if (!m_resourcesToStartPending)
+ return;
+
+ if (!--m_resourcesToStartPending)
+ g_main_loop_quit(m_mainLoop);
+ }
+
+ void waitUntilResourcesStarted(unsigned requestCount)
+ {
+ m_resourcesToStartPending = requestCount;
+ g_main_loop_run(m_mainLoop);
+ }
+
+ unsigned m_resourcesToStartPending;
+};
+
+static void testWebViewSyncRequestOnMaxConns(SyncRequestOnMaxConnsTest* test, gconstpointer)
+{
+ WTF::GMutexLocker<GMutex> lock(s_serverMutex);
+ test->loadURI(kServer->getURIForPath("/sync-request-on-max-conns-0").data());
+ test->waitUntilResourcesStarted(s_maxConnectionsPerHost + 1); // s_maxConnectionsPerHost resource + main resource.
+
+ for (unsigned i = 0; i < 2; ++i) {
+ GUniquePtr<char> xhr(g_strdup_printf("xhr = new XMLHttpRequest; xhr.open('GET', '/sync-request-on-max-conns-xhr%u', false); xhr.send();", i));
+ webkit_web_view_run_javascript(test->m_webView, xhr.get(), nullptr, nullptr, nullptr);
+ }
+
+ // By default sync XHRs have a 10 seconds timeout, we don't want to wait all that so use our own timeout.
+ guint timeoutSourceID = g_timeout_add(1000, [] (gpointer) -> gboolean {
+ g_assert_not_reached();
+ return G_SOURCE_REMOVE;
+ }, nullptr);
+
+ struct UnlockServerSourceContext {
+ WTF::GMutexLocker<GMutex>& lock;
+ guint unlockServerSourceID;
+ } context = {
+ lock,
+ g_idle_add_full(G_PRIORITY_DEFAULT, [](gpointer userData) -> gboolean {
+ auto& context = *static_cast<UnlockServerSourceContext*>(userData);
+ context.unlockServerSourceID = 0;
+ context.lock.unlock();
+ return G_SOURCE_REMOVE;
+ }, &context, nullptr)
+ };
+ test->waitUntilResourcesLoaded(s_maxConnectionsPerHost + 3); // s_maxConnectionsPerHost resource + main resource + 2 XHR.
+ g_source_remove(timeoutSourceID);
+ if (context.unlockServerSourceID)
+ g_source_remove(context.unlockServerSourceID);
+}
+
static void addCacheHTTPHeadersToResponse(SoupMessage* message)
{
// The actual date doesn't really matter.
@@ -734,7 +800,7 @@ static void serverCallback(SoupServer* server, SoupMessage* message, const char*
static const char* javascriptRelativeHTML = "<html><head><script language='javascript' src='/redirected-to-cancel.js'></script></head><body></body></html>";
soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, javascriptRelativeHTML, strlen(javascriptRelativeHTML));
} else if (g_str_equal(path, "/blank.ico")) {
- GUniquePtr<char> filePath(g_build_filename(Test::getWebKit1TestResoucesDir().data(), path, NULL));
+ GUniquePtr<char> filePath(g_build_filename(Test::getResourcesDir().data(), path, nullptr));
char* contents;
gsize contentsLength;
g_file_get_contents(filePath.get(), &contents, &contentsLength, 0);
@@ -760,18 +826,37 @@ static void serverCallback(SoupServer* server, SoupMessage* message, const char*
soup_message_headers_append(message->response_headers, "Location", "/cancel-this.js");
} else if (g_str_equal(path, "/invalid.css"))
soup_message_set_status(message, SOUP_STATUS_CANT_CONNECT);
- else
+ else if (g_str_has_prefix(path, "/sync-request-on-max-conns-")) {
+ char* contents;
+ gsize contentsLength;
+ if (g_str_equal(path, "/sync-request-on-max-conns-0")) {
+ GString* imagesHTML = g_string_new("<html><body>");
+ for (unsigned i = 1; i <= s_maxConnectionsPerHost; ++i)
+ g_string_append_printf(imagesHTML, "<img src='/sync-request-on-max-conns-%u'>", i);
+ g_string_append(imagesHTML, "</body></html>");
+
+ contentsLength = imagesHTML->len;
+ contents = g_string_free(imagesHTML, FALSE);
+ } else {
+ {
+ // We don't actually need to keep the mutex, so we release it as soon as we get it.
+ WTF::GMutexLocker<GMutex> lock(s_serverMutex);
+ }
+
+ GUniquePtr<char> filePath(g_build_filename(Test::getResourcesDir().data(), "blank.ico", nullptr));
+ g_file_get_contents(filePath.get(), &contents, &contentsLength, 0);
+ }
+ soup_message_body_append(message->response_body, SOUP_MEMORY_TAKE, contents, contentsLength);
+ } else
soup_message_set_status(message, SOUP_STATUS_NOT_FOUND);
soup_message_body_complete(message->response_body);
}
void beforeAll()
{
- kServer = new WebKitTestServer();
+ kServer = new WebKitTestServer(WebKitTestServer::ServerOptions::ServerRunInThread);
kServer->run(serverCallback);
- webkit_web_context_set_web_extensions_directory(webkit_web_context_get_default(), WEBKIT_TEST_WEB_EXTENSIONS_DIR);
-
ResourcesTest::add("WebKitWebView", "resources", testWebViewResources);
SingleResourceLoadTest::add("WebKitWebResource", "loading", testWebResourceLoading);
SingleResourceLoadTest::add("WebKitWebResource", "response", testWebResourceResponse);
@@ -781,6 +866,9 @@ void beforeAll()
ResourcesTest::add("WebKitWebResource", "get-data", testWebResourceGetData);
SingleResourceLoadTest::add("WebKitWebView", "history-cache", testWebViewResourcesHistoryCache);
SendRequestTest::add("WebKitWebPage", "send-request", testWebResourceSendRequest);
+#if SOUP_CHECK_VERSION(2, 49, 91)
+ SyncRequestOnMaxConnsTest::add("WebKitWebView", "sync-request-on-max-conns", testWebViewSyncRequestOnMaxConns);
+#endif
}
void afterAll()
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestSSL.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestSSL.cpp
index c3075b697..10c5e73b6 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestSSL.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestSSL.cpp
@@ -67,6 +67,10 @@ public:
static void testSSL(SSLTest* test, gconstpointer)
{
+ WebKitWebContext* context = webkit_web_view_get_context(test->m_webView);
+ WebKitTLSErrorsPolicy originalPolicy = webkit_web_context_get_tls_errors_policy(context);
+ webkit_web_context_set_tls_errors_policy(context, WEBKIT_TLS_ERRORS_POLICY_IGNORE);
+
test->loadURI(kHttpsServer->getURIForPath("/").data());
test->waitUntilLoadFinished();
g_assert(test->m_certificate);
@@ -80,6 +84,8 @@ static void testSSL(SSLTest* test, gconstpointer)
test->waitUntilLoadFinished();
g_assert(!test->m_certificate);
g_assert(!test->m_tlsErrors);
+
+ webkit_web_context_set_tls_errors_policy(context, originalPolicy);
}
class InsecureContentTest: public WebViewTest {
@@ -110,38 +116,64 @@ public:
static void testInsecureContent(InsecureContentTest* test, gconstpointer)
{
+ WebKitWebContext* context = webkit_web_view_get_context(test->m_webView);
+ WebKitTLSErrorsPolicy originalPolicy = webkit_web_context_get_tls_errors_policy(context);
+ webkit_web_context_set_tls_errors_policy(context, WEBKIT_TLS_ERRORS_POLICY_IGNORE);
+
test->loadURI(kHttpsServer->getURIForPath("/insecure-content/").data());
test->waitUntilLoadFinished();
- g_assert(test->m_insecureContentRun);
+ g_assert(!test->m_insecureContentRun);
+ // Images are currently always displayed, even bypassing mixed content settings. Check
+ // https://bugs.webkit.org/show_bug.cgi?id=142469
g_assert(test->m_insecureContentDisplayed);
+
+ webkit_web_context_set_tls_errors_policy(context, originalPolicy);
}
+static bool assertIfSSLRequestProcessed = false;
+
static void testTLSErrorsPolicy(SSLTest* test, gconstpointer)
{
WebKitWebContext* context = webkit_web_view_get_context(test->m_webView);
- // TLS errors are ignored by default.
- g_assert(webkit_web_context_get_tls_errors_policy(context) == WEBKIT_TLS_ERRORS_POLICY_IGNORE);
- test->loadURI(kHttpsServer->getURIForPath("/").data());
- test->waitUntilLoadFinished();
- g_assert(!test->m_loadFailed);
+ // TLS errors are treated as transport failures by default.
+ g_assert(webkit_web_context_get_tls_errors_policy(context) == WEBKIT_TLS_ERRORS_POLICY_FAIL);
- webkit_web_context_set_tls_errors_policy(context, WEBKIT_TLS_ERRORS_POLICY_FAIL);
+ assertIfSSLRequestProcessed = true;
test->loadURI(kHttpsServer->getURIForPath("/").data());
test->waitUntilLoadFinished();
g_assert(test->m_loadFailed);
g_assert(test->m_loadEvents.contains(LoadTrackingTest::ProvisionalLoadFailed));
g_assert(!test->m_loadEvents.contains(LoadTrackingTest::LoadCommitted));
+ assertIfSSLRequestProcessed = false;
+
+ webkit_web_context_set_tls_errors_policy(context, WEBKIT_TLS_ERRORS_POLICY_IGNORE);
+ g_assert(webkit_web_context_get_tls_errors_policy(context) == WEBKIT_TLS_ERRORS_POLICY_IGNORE);
+
+ test->m_loadFailed = false;
+ test->loadURI(kHttpsServer->getURIForPath("/").data());
+ test->waitUntilLoadFinished();
+ g_assert(!test->m_loadFailed);
+
+ webkit_web_context_set_tls_errors_policy(context, WEBKIT_TLS_ERRORS_POLICY_FAIL);
+ g_assert(webkit_web_context_get_tls_errors_policy(context) == WEBKIT_TLS_ERRORS_POLICY_FAIL);
}
static void testTLSErrorsRedirect(SSLTest* test, gconstpointer)
{
- webkit_web_context_set_tls_errors_policy(webkit_web_view_get_context(test->m_webView), WEBKIT_TLS_ERRORS_POLICY_FAIL);
+ WebKitWebContext* context = webkit_web_view_get_context(test->m_webView);
+ WebKitTLSErrorsPolicy originalPolicy = webkit_web_context_get_tls_errors_policy(context);
+ webkit_web_context_set_tls_errors_policy(context, WEBKIT_TLS_ERRORS_POLICY_FAIL);
+
+ assertIfSSLRequestProcessed = true;
test->loadURI(kHttpsServer->getURIForPath("/redirect").data());
test->waitUntilLoadFinished();
g_assert(test->m_loadFailed);
g_assert(test->m_loadEvents.contains(LoadTrackingTest::ProvisionalLoadFailed));
g_assert(!test->m_loadEvents.contains(LoadTrackingTest::LoadCommitted));
+ assertIfSSLRequestProcessed = false;
+
+ webkit_web_context_set_tls_errors_policy(context, originalPolicy);
}
static gboolean webViewAuthenticationCallback(WebKitWebView*, WebKitAuthenticationRequest* request)
@@ -153,13 +185,20 @@ static gboolean webViewAuthenticationCallback(WebKitWebView*, WebKitAuthenticati
static void testTLSErrorsHTTPAuth(SSLTest* test, gconstpointer)
{
- webkit_web_context_set_tls_errors_policy(webkit_web_view_get_context(test->m_webView), WEBKIT_TLS_ERRORS_POLICY_FAIL);
+ WebKitWebContext* context = webkit_web_view_get_context(test->m_webView);
+ WebKitTLSErrorsPolicy originalPolicy = webkit_web_context_get_tls_errors_policy(context);
+ webkit_web_context_set_tls_errors_policy(context, WEBKIT_TLS_ERRORS_POLICY_FAIL);
+
+ assertIfSSLRequestProcessed = true;
g_signal_connect(test->m_webView, "authenticate", G_CALLBACK(webViewAuthenticationCallback), NULL);
test->loadURI(kHttpsServer->getURIForPath("/auth").data());
test->waitUntilLoadFinished();
g_assert(test->m_loadFailed);
g_assert(test->m_loadEvents.contains(LoadTrackingTest::ProvisionalLoadFailed));
g_assert(!test->m_loadEvents.contains(LoadTrackingTest::LoadCommitted));
+ assertIfSSLRequestProcessed = false;
+
+ webkit_web_context_set_tls_errors_policy(context, originalPolicy);
}
class TLSErrorsTest: public SSLTest {
@@ -167,69 +206,60 @@ public:
MAKE_GLIB_TEST_FIXTURE(TLSErrorsTest);
TLSErrorsTest()
+ : m_tlsErrors(static_cast<GTlsCertificateFlags>(0))
+ , m_failingURI(nullptr)
{
- g_signal_connect(m_webView, "load-failed-with-tls-errors", G_CALLBACK(runLoadFailedWithTLSErrorsCallback), this);
}
~TLSErrorsTest()
{
- g_signal_handlers_disconnect_matched(m_webView, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
- if (m_certificateInfo)
- webkit_certificate_info_free(m_certificateInfo);
- }
-
- static gboolean runLoadFailedWithTLSErrorsCallback(WebKitWebView*, WebKitCertificateInfo* info, const char* host, TLSErrorsTest* test)
- {
- test->runLoadFailedWithTLSErrors(info, host);
- return TRUE;
- }
-
- void runLoadFailedWithTLSErrors(WebKitCertificateInfo* info, const char* host)
- {
- if (m_certificateInfo)
- webkit_certificate_info_free(m_certificateInfo);
- m_certificateInfo = webkit_certificate_info_copy(info);
- m_host.reset(g_strdup(host));
- g_main_loop_quit(m_mainLoop);
+ if (m_failingURI)
+ soup_uri_free(m_failingURI);
}
- void waitUntilLoadFailedWithTLSErrors()
+ bool loadFailedWithTLSErrors(const char* failingURI, GTlsCertificate* certificate, GTlsCertificateFlags tlsErrors) override
{
- g_main_loop_run(m_mainLoop);
- }
+ LoadTrackingTest::loadFailedWithTLSErrors(failingURI, certificate, tlsErrors);
- WebKitCertificateInfo* certificateInfo()
- {
- return m_certificateInfo;
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(certificate));
+ m_certificate = certificate;
+ m_tlsErrors = tlsErrors;
+ if (m_failingURI)
+ soup_uri_free(m_failingURI);
+ m_failingURI = soup_uri_new(failingURI);
+ return true;
}
- const char* host()
- {
- return m_host.get();
- }
+ GTlsCertificate* certificate() const { return m_certificate.get(); }
+ GTlsCertificateFlags tlsErrors() const { return m_tlsErrors; }
+ const char* host() const { return m_failingURI->host; }
private:
- WebKitCertificateInfo* m_certificateInfo;
- GUniquePtr<char> m_host;
+ GRefPtr<GTlsCertificate> m_certificate;
+ GTlsCertificateFlags m_tlsErrors;
+ SoupURI* m_failingURI;
};
static void testLoadFailedWithTLSErrors(TLSErrorsTest* test, gconstpointer)
{
WebKitWebContext* context = webkit_web_view_get_context(test->m_webView);
+ WebKitTLSErrorsPolicy originalPolicy = webkit_web_context_get_tls_errors_policy(context);
webkit_web_context_set_tls_errors_policy(context, WEBKIT_TLS_ERRORS_POLICY_FAIL);
+ assertIfSSLRequestProcessed = true;
// The load-failed-with-tls-errors signal should be emitted when there is a TLS failure.
test->loadURI(kHttpsServer->getURIForPath("/test-tls/").data());
- test->waitUntilLoadFailedWithTLSErrors();
- // Test the WebKitCertificateInfo API.
- g_assert(G_IS_TLS_CERTIFICATE(webkit_certificate_info_get_tls_certificate(test->certificateInfo())));
- g_assert_cmpuint(webkit_certificate_info_get_tls_errors(test->certificateInfo()), ==, G_TLS_CERTIFICATE_UNKNOWN_CA);
+ test->waitUntilLoadFinished();
+ g_assert(G_IS_TLS_CERTIFICATE(test->certificate()));
+ g_assert_cmpuint(test->tlsErrors(), ==, G_TLS_CERTIFICATE_UNKNOWN_CA);
g_assert_cmpstr(test->host(), ==, soup_uri_get_host(kHttpsServer->baseURI()));
g_assert_cmpint(test->m_loadEvents[0], ==, LoadTrackingTest::ProvisionalLoadStarted);
- g_assert_cmpint(test->m_loadEvents[1], ==, LoadTrackingTest::LoadFinished);
+ g_assert_cmpint(test->m_loadEvents[1], ==, LoadTrackingTest::LoadFailedWithTLSErrors);
+ g_assert_cmpint(test->m_loadEvents[2], ==, LoadTrackingTest::LoadFinished);
+ assertIfSSLRequestProcessed = false;
// Test allowing an exception for this certificate on this host.
- webkit_web_context_allow_tls_certificate_for_host(context, test->certificateInfo(), test->host());
+ webkit_web_context_allow_tls_certificate_for_host(context, test->certificate(), test->host());
// The page should now load without errors.
test->loadURI(kHttpsServer->getURIForPath("/test-tls/").data());
test->waitUntilLoadFinished();
@@ -238,8 +268,76 @@ static void testLoadFailedWithTLSErrors(TLSErrorsTest* test, gconstpointer)
g_assert_cmpint(test->m_loadEvents[1], ==, LoadTrackingTest::LoadCommitted);
g_assert_cmpint(test->m_loadEvents[2], ==, LoadTrackingTest::LoadFinished);
g_assert_cmpstr(webkit_web_view_get_title(test->m_webView), ==, TLSExpectedSuccessTitle);
+
+ webkit_web_context_set_tls_errors_policy(context, originalPolicy);
}
+class TLSSubresourceTest : public WebViewTest {
+public:
+ MAKE_GLIB_TEST_FIXTURE(TLSSubresourceTest);
+
+ static void resourceLoadStartedCallback(WebKitWebView* webView, WebKitWebResource* resource, WebKitURIRequest* request, TLSSubresourceTest* test)
+ {
+ if (webkit_web_view_get_main_resource(test->m_webView) == resource)
+ return;
+
+ // Ignore favicons.
+ if (g_str_has_suffix(webkit_uri_request_get_uri(request), "favicon.ico"))
+ return;
+
+ test->subresourceLoadStarted(resource);
+ }
+
+ TLSSubresourceTest()
+ : m_tlsErrors(static_cast<GTlsCertificateFlags>(0))
+ {
+ g_signal_connect(m_webView, "resource-load-started", G_CALLBACK(resourceLoadStartedCallback), this);
+ }
+
+ static void subresourceFailedCallback(WebKitWebResource*, GError*)
+ {
+ g_assert_not_reached();
+ }
+
+ static void subresourceFailedWithTLSErrorsCallback(WebKitWebResource* resource, GTlsCertificate* certificate, GTlsCertificateFlags tlsErrors, TLSSubresourceTest* test)
+ {
+ test->subresourceFailedWithTLSErrors(resource, certificate, tlsErrors);
+ }
+
+ void subresourceLoadStarted(WebKitWebResource* resource)
+ {
+ g_signal_connect(resource, "failed", G_CALLBACK(subresourceFailedCallback), nullptr);
+ g_signal_connect(resource, "failed-with-tls-errors", G_CALLBACK(subresourceFailedWithTLSErrorsCallback), this);
+ }
+
+ void subresourceFailedWithTLSErrors(WebKitWebResource* resource, GTlsCertificate* certificate, GTlsCertificateFlags tlsErrors)
+ {
+ m_certificate = certificate;
+ m_tlsErrors = tlsErrors;
+ g_main_loop_quit(m_mainLoop);
+ }
+
+ void waitUntilSubresourceLoadFail()
+ {
+ g_main_loop_run(m_mainLoop);
+ }
+
+ GRefPtr<GTlsCertificate> m_certificate;
+ GTlsCertificateFlags m_tlsErrors;
+};
+
+static void testSubresourceLoadFailedWithTLSErrors(TLSSubresourceTest* test, gconstpointer)
+{
+ WebKitWebContext* context = webkit_web_view_get_context(test->m_webView);
+ webkit_web_context_set_tls_errors_policy(context, WEBKIT_TLS_ERRORS_POLICY_FAIL);
+
+ assertIfSSLRequestProcessed = true;
+ test->loadURI(kHttpServer->getURIForPath("/").data());
+ test->waitUntilSubresourceLoadFail();
+ g_assert(G_IS_TLS_CERTIFICATE(test->m_certificate.get()));
+ g_assert_cmpuint(test->m_tlsErrors, ==, G_TLS_CERTIFICATE_UNKNOWN_CA);
+ assertIfSSLRequestProcessed = false;
+}
static void httpsServerCallback(SoupServer* server, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, gpointer)
{
@@ -248,6 +346,8 @@ static void httpsServerCallback(SoupServer* server, SoupMessage* message, const
return;
}
+ g_assert(!assertIfSSLRequestProcessed);
+
if (g_str_equal(path, "/")) {
soup_message_set_status(message, SOUP_STATUS_OK);
soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, indexHTML, strlen(indexHTML));
@@ -267,6 +367,10 @@ static void httpsServerCallback(SoupServer* server, SoupMessage* message, const
} else if (g_str_equal(path, "/auth")) {
soup_message_set_status(message, SOUP_STATUS_UNAUTHORIZED);
soup_message_headers_append(message->response_headers, "WWW-Authenticate", "Basic realm=\"HTTPS auth\"");
+ } else if (g_str_equal(path, "/style.css")) {
+ soup_message_set_status(message, SOUP_STATUS_OK);
+ static const char* styleCSS = "body { color: black; }";
+ soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, styleCSS, strlen(styleCSS));
} else
soup_message_set_status(message, SOUP_STATUS_NOT_FOUND);
}
@@ -279,7 +383,7 @@ static void httpServerCallback(SoupServer* server, SoupMessage* message, const c
}
if (g_str_equal(path, "/test-script")) {
- GUniquePtr<char> pathToFile(g_build_filename(Test::getResourcesDir().data(), "link-title.js", NULL));
+ GUniquePtr<char> pathToFile(g_build_filename(Test::getResourcesDir().data(), "link-title.js", nullptr));
char* contents;
gsize length;
g_file_get_contents(pathToFile.get(), &contents, &length, 0);
@@ -288,7 +392,7 @@ static void httpServerCallback(SoupServer* server, SoupMessage* message, const c
soup_message_set_status(message, SOUP_STATUS_OK);
soup_message_body_complete(message->response_body);
} else if (g_str_equal(path, "/test-image")) {
- GUniquePtr<char> pathToFile(g_build_filename(Test::getWebKit1TestResoucesDir().data(), "blank.ico", NULL));
+ GUniquePtr<char> pathToFile(g_build_filename(Test::getResourcesDir().data(), "blank.ico", nullptr));
char* contents;
gsize length;
g_file_get_contents(pathToFile.get(), &contents, &length, 0);
@@ -296,6 +400,12 @@ static void httpServerCallback(SoupServer* server, SoupMessage* message, const c
soup_message_body_append(message->response_body, SOUP_MEMORY_TAKE, contents, length);
soup_message_set_status(message, SOUP_STATUS_OK);
soup_message_body_complete(message->response_body);
+ } else if (g_str_equal(path, "/")) {
+ soup_message_set_status(message, SOUP_STATUS_OK);
+ char* responseHTML = g_strdup_printf("<html><head><link rel='stylesheet' href='%s' type='text/css'></head><body>SSL subresource test</body></html>",
+ kHttpsServer->getURIForPath("/style.css").data());
+ soup_message_body_append(message->response_body, SOUP_MEMORY_TAKE, responseHTML, strlen(responseHTML));
+ soup_message_body_complete(message->response_body);
} else
soup_message_set_status(message, SOUP_STATUS_NOT_FOUND);
}
@@ -310,12 +420,10 @@ void beforeAll()
SSLTest::add("WebKitWebView", "ssl", testSSL);
InsecureContentTest::add("WebKitWebView", "insecure-content", testInsecureContent);
- // In this case the order of the tests does matter because tls-errors-policy tests the default policy,
- // and expects that no exception will have been added for this certificate and host pair as is
- // done in the tls-permission-request test.
SSLTest::add("WebKitWebView", "tls-errors-policy", testTLSErrorsPolicy);
SSLTest::add("WebKitWebView", "tls-errors-redirect-to-http", testTLSErrorsRedirect);
SSLTest::add("WebKitWebView", "tls-http-auth", testTLSErrorsHTTPAuth);
+ TLSSubresourceTest::add("WebKitWebView", "tls-subresource", testSubresourceLoadFailedWithTLSErrors);
TLSErrorsTest::add("WebKitWebView", "load-failed-with-tls-errors", testLoadFailedWithTLSErrors);
}
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestUIClient.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestUIClient.cpp
index d24edc601..4c44039cc 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestUIClient.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestUIClient.cpp
@@ -20,13 +20,14 @@
#include "config.h"
#include "WebViewTest.h"
#include <wtf/HashSet.h>
-#include <wtf/gobject/GRefPtr.h>
+#include <wtf/glib/GRefPtr.h>
#include <wtf/text/StringHash.h>
static const char* kAlertDialogMessage = "WebKitGTK+ alert dialog message";
static const char* kConfirmDialogMessage = "WebKitGTK+ confirm dialog message";
static const char* kPromptDialogMessage = "WebKitGTK+ prompt dialog message";
static const char* kPromptDialogReturnedText = "WebKitGTK+ prompt dialog returned text";
+static const char* kBeforeUnloadConfirmDialogMessage = "WebKitGTK+ beforeunload dialog message";
class UIClientTest: public WebViewTest {
public:
@@ -117,9 +118,9 @@ public:
test->m_windowPropertiesChanged.add(g_param_spec_get_name(paramSpec));
}
- static GtkWidget* viewCreateCallback(WebKitWebView* webView, UIClientTest* test)
+ static GtkWidget* viewCreateCallback(WebKitWebView* webView, WebKitNavigationAction* navigation, UIClientTest* test)
{
- return test->viewCreate(webView);
+ return test->viewCreate(webView, navigation);
}
static void viewReadyToShowCallback(WebKitWebView* webView, UIClientTest* test)
@@ -146,6 +147,9 @@ public:
case WEBKIT_SCRIPT_DIALOG_PROMPT:
g_assert_cmpstr(webkit_script_dialog_get_message(dialog), ==, kPromptDialogReturnedText);
break;
+ case WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM:
+ g_assert_not_reached();
+ break;
}
g_main_loop_quit(m_mainLoop);
@@ -165,6 +169,13 @@ public:
webkit_script_dialog_prompt_set_text(dialog, kPromptDialogReturnedText);
}
+ void scriptBeforeUnloadConfirm(WebKitScriptDialog* dialog)
+ {
+ g_assert_cmpstr(webkit_script_dialog_get_message(dialog), ==, kBeforeUnloadConfirmDialogMessage);
+ m_scriptDialogConfirmed = true;
+ webkit_script_dialog_confirm_set_confirmed(dialog, m_scriptDialogConfirmed);
+ }
+
static gboolean scriptDialog(WebKitWebView*, WebKitScriptDialog* dialog, UIClientTest* test)
{
switch (webkit_script_dialog_get_dialog_type(dialog)) {
@@ -177,6 +188,9 @@ public:
case WEBKIT_SCRIPT_DIALOG_PROMPT:
test->scriptPrompt(dialog);
break;
+ case WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM:
+ test->scriptBeforeUnloadConfirm(dialog);
+ break;
}
return TRUE;
@@ -197,6 +211,12 @@ public:
g_assert(WEBKIT_IS_PERMISSION_REQUEST(request));
test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(request));
+ if (test->m_verifyMediaTypes && WEBKIT_IS_USER_MEDIA_PERMISSION_REQUEST(request)) {
+ WebKitUserMediaPermissionRequest* userMediaRequest = WEBKIT_USER_MEDIA_PERMISSION_REQUEST(request);
+ g_assert(webkit_user_media_permission_is_for_audio_device(userMediaRequest) == test->m_expectedAudioMedia);
+ g_assert(webkit_user_media_permission_is_for_video_device(userMediaRequest) == test->m_expectedVideoMedia);
+ }
+
if (test->m_allowPermissionRequests)
webkit_permission_request_allow(request);
else
@@ -205,10 +225,19 @@ public:
return TRUE;
}
+ static void permissionResultMessageReceivedCallback(WebKitUserContentManager* userContentManager, WebKitJavascriptResult* javascriptResult, UIClientTest* test)
+ {
+ test->m_permissionResult.reset(WebViewTest::javascriptResultToCString(javascriptResult));
+ g_main_loop_quit(test->m_mainLoop);
+ }
+
UIClientTest()
: m_scriptDialogType(WEBKIT_SCRIPT_DIALOG_ALERT)
, m_scriptDialogConfirmed(true)
, m_allowPermissionRequests(false)
+ , m_verifyMediaTypes(false)
+ , m_expectedAudioMedia(false)
+ , m_expectedVideoMedia(false)
, m_mouseTargetModifiers(0)
{
webkit_settings_set_javascript_can_open_windows_automatically(webkit_web_view_get_settings(m_webView), TRUE);
@@ -216,11 +245,33 @@ public:
g_signal_connect(m_webView, "script-dialog", G_CALLBACK(scriptDialog), this);
g_signal_connect(m_webView, "mouse-target-changed", G_CALLBACK(mouseTargetChanged), this);
g_signal_connect(m_webView, "permission-request", G_CALLBACK(permissionRequested), this);
+ webkit_user_content_manager_register_script_message_handler(m_userContentManager.get(), "permission");
+ g_signal_connect(m_userContentManager.get(), "script-message-received::permission", G_CALLBACK(permissionResultMessageReceivedCallback), this);
}
~UIClientTest()
{
g_signal_handlers_disconnect_matched(m_webView, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
+ g_signal_handlers_disconnect_matched(m_userContentManager.get(), G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
+ webkit_user_content_manager_unregister_script_message_handler(m_userContentManager.get(), "permission");
+ }
+
+ static void tryWebViewCloseCallback(UIClientTest* test)
+ {
+ g_main_loop_quit(test->m_mainLoop);
+ }
+
+ void tryCloseAndWaitUntilClosed()
+ {
+ gulong handler = g_signal_connect_swapped(m_webView, "close", G_CALLBACK(tryWebViewCloseCallback), this);
+ // Use an idle because webkit_web_view_try_close can emit the close signal in the
+ // current run loop iteration.
+ g_idle_add([](gpointer data) -> gboolean {
+ webkit_web_view_try_close(WEBKIT_WEB_VIEW(data));
+ return G_SOURCE_REMOVE;
+ }, m_webView);
+ g_main_loop_run(m_mainLoop);
+ g_signal_handler_disconnect(m_webView, handler);
}
void waitUntilMainLoopFinishes()
@@ -228,6 +279,13 @@ public:
g_main_loop_run(m_mainLoop);
}
+ const char* waitUntilPermissionResultMessageReceived()
+ {
+ m_permissionResult = nullptr;
+ g_main_loop_run(m_mainLoop);
+ return m_permissionResult.get();
+ }
+
void setExpectedWindowProperties(const WindowProperties& windowProperties)
{
m_windowProperties = windowProperties;
@@ -240,9 +298,19 @@ public:
return m_mouseTargetHitTestResult.get();
}
- virtual GtkWidget* viewCreate(WebKitWebView* webView)
+ void simulateUserInteraction()
+ {
+ runJavaScriptAndWaitUntilFinished("document.getElementById('testInput').focus()", nullptr);
+ keyStroke(GDK_KEY_a);
+ keyStroke(GDK_KEY_b);
+ while (gtk_events_pending())
+ gtk_main_iteration();
+ }
+
+ virtual GtkWidget* viewCreate(WebKitWebView* webView, WebKitNavigationAction* navigation)
{
g_assert(webView == m_webView);
+ g_assert(navigation);
GtkWidget* newWebView = webkit_web_view_new_with_context(webkit_web_view_get_context(webView));
g_object_ref_sink(newWebView);
@@ -287,10 +355,14 @@ public:
WebKitScriptDialogType m_scriptDialogType;
bool m_scriptDialogConfirmed;
bool m_allowPermissionRequests;
+ gboolean m_verifyMediaTypes;
+ gboolean m_expectedAudioMedia;
+ gboolean m_expectedVideoMedia;
WindowProperties m_windowProperties;
HashSet<WTF::String> m_windowPropertiesChanged;
GRefPtr<WebKitHitTestResult> m_mouseTargetHitTestResult;
unsigned m_mouseTargetModifiers;
+ GUniquePtr<char> m_permissionResult;
};
static void testWebViewCreateReadyClose(UIClientTest* test, gconstpointer)
@@ -305,6 +377,91 @@ static void testWebViewCreateReadyClose(UIClientTest* test, gconstpointer)
g_assert_cmpint(events[2], ==, UIClientTest::Close);
}
+class CreateNavigationDataTest: public UIClientTest {
+public:
+ MAKE_GLIB_TEST_FIXTURE(CreateNavigationDataTest);
+
+ CreateNavigationDataTest()
+ : m_navigation(nullptr)
+ {
+ }
+
+ ~CreateNavigationDataTest()
+ {
+ clearNavigation();
+ }
+
+ void clearNavigation()
+ {
+ if (m_navigation)
+ webkit_navigation_action_free(m_navigation);
+ m_navigation = nullptr;
+ }
+
+ GtkWidget* viewCreate(WebKitWebView* webView, WebKitNavigationAction* navigation)
+ {
+ g_assert(navigation);
+ g_assert(!m_navigation);
+ m_navigation = webkit_navigation_action_copy(navigation);
+ g_main_loop_quit(m_mainLoop);
+ return nullptr;
+ }
+
+ void loadHTML(const char* html)
+ {
+ clearNavigation();
+ WebViewTest::loadHtml(html, nullptr);
+ }
+
+ void clickAndWaitUntilMainLoopFinishes(int x, int y)
+ {
+ clearNavigation();
+ clickMouseButton(x, y, 1);
+ g_main_loop_run(m_mainLoop);
+ }
+
+ WebKitNavigationAction* m_navigation;
+};
+
+static void testWebViewCreateNavigationData(CreateNavigationDataTest* test, gconstpointer)
+{
+ test->showInWindowAndWaitUntilMapped();
+
+ test->loadHTML(
+ "<html><body>"
+ "<input style=\"position:absolute; left:0; top:0; margin:0; padding:0\" type=\"button\" value=\"click to show a popup\" onclick=\"window.open('data:foo');\"/>"
+ "<a style=\"position:absolute; left:20; top:20;\" href=\"data:bar\" target=\"_blank\">popup link</a>"
+ "</body></html>");
+ test->waitUntilLoadFinished();
+
+ // Click on a button.
+ test->clickAndWaitUntilMainLoopFinishes(5, 5);
+ g_assert_cmpstr(webkit_uri_request_get_uri(webkit_navigation_action_get_request(test->m_navigation)), ==, "data:foo");
+ g_assert_cmpuint(webkit_navigation_action_get_navigation_type(test->m_navigation), ==, WEBKIT_NAVIGATION_TYPE_OTHER);
+ // FIXME: This should be button 1.
+ g_assert_cmpuint(webkit_navigation_action_get_mouse_button(test->m_navigation), ==, 0);
+ g_assert_cmpuint(webkit_navigation_action_get_modifiers(test->m_navigation), ==, 0);
+ g_assert(webkit_navigation_action_is_user_gesture(test->m_navigation));
+
+ // Click on a link.
+ test->clickAndWaitUntilMainLoopFinishes(21, 21);
+ g_assert_cmpstr(webkit_uri_request_get_uri(webkit_navigation_action_get_request(test->m_navigation)), ==, "data:bar");
+ g_assert_cmpuint(webkit_navigation_action_get_navigation_type(test->m_navigation), ==, WEBKIT_NAVIGATION_TYPE_LINK_CLICKED);
+ g_assert_cmpuint(webkit_navigation_action_get_mouse_button(test->m_navigation), ==, 1);
+ g_assert_cmpuint(webkit_navigation_action_get_modifiers(test->m_navigation), ==, 0);
+ g_assert(webkit_navigation_action_is_user_gesture(test->m_navigation));
+
+ // No user interaction.
+ test->loadHTML("<html><body onLoad=\"window.open();\"></html>");
+ test->waitUntilMainLoopFinishes();
+
+ g_assert_cmpstr(webkit_uri_request_get_uri(webkit_navigation_action_get_request(test->m_navigation)), ==, "");
+ g_assert_cmpuint(webkit_navigation_action_get_navigation_type(test->m_navigation), ==, WEBKIT_NAVIGATION_TYPE_OTHER);
+ g_assert_cmpuint(webkit_navigation_action_get_mouse_button(test->m_navigation), ==, 0);
+ g_assert_cmpuint(webkit_navigation_action_get_modifiers(test->m_navigation), ==, 0);
+ g_assert(!webkit_navigation_action_is_user_gesture(test->m_navigation));
+}
+
static gboolean checkMimeTypeForFilter(GtkFileFilter* filter, const gchar* mimeType)
{
GtkFileFilterInfo filterInfo;
@@ -323,11 +480,11 @@ public:
test->m_webViewEvents.append(RunAsModal);
}
- GtkWidget* viewCreate(WebKitWebView* webView)
+ GtkWidget* viewCreate(WebKitWebView* webView, WebKitNavigationAction* navigation)
{
g_assert(webView == m_webView);
- GtkWidget* newWebView = UIClientTest::viewCreate(webView);
+ GtkWidget* newWebView = UIClientTest::viewCreate(webView, navigation);
g_signal_connect(newWebView, "run-as-modal", G_CALLBACK(dialogRunAsModalCallback), this);
return newWebView;
}
@@ -371,28 +528,80 @@ static void testWebViewDisallowModalDialogs(ModalDialogsTest* test, gconstpointe
static void testWebViewJavaScriptDialogs(UIClientTest* test, gconstpointer)
{
+ test->showInWindowAndWaitUntilMapped(GTK_WINDOW_TOPLEVEL);
+
static const char* htmlOnLoadFormat = "<html><body onLoad=\"%s\"></body></html>";
static const char* jsAlertFormat = "alert('%s')";
static const char* jsConfirmFormat = "do { confirmed = confirm('%s'); } while (!confirmed); alert('confirmed');";
static const char* jsPromptFormat = "alert(prompt('%s', 'default'));";
+ static const char* htmlOnBeforeUnloadFormat =
+ "<html><body onbeforeunload=\"return beforeUnloadHandler();\"><input id=\"testInput\" type=\"text\"></input><script>function beforeUnloadHandler() { return \"%s\"; }</script></body></html>";
test->m_scriptDialogType = WEBKIT_SCRIPT_DIALOG_ALERT;
GUniquePtr<char> alertDialogMessage(g_strdup_printf(jsAlertFormat, kAlertDialogMessage));
GUniquePtr<char> alertHTML(g_strdup_printf(htmlOnLoadFormat, alertDialogMessage.get()));
test->loadHtml(alertHTML.get(), 0);
test->waitUntilMainLoopFinishes();
+ webkit_web_view_stop_loading(test->m_webView);
+ test->waitUntilLoadFinished();
test->m_scriptDialogType = WEBKIT_SCRIPT_DIALOG_CONFIRM;
GUniquePtr<char> confirmDialogMessage(g_strdup_printf(jsConfirmFormat, kConfirmDialogMessage));
GUniquePtr<char> confirmHTML(g_strdup_printf(htmlOnLoadFormat, confirmDialogMessage.get()));
test->loadHtml(confirmHTML.get(), 0);
test->waitUntilMainLoopFinishes();
+ webkit_web_view_stop_loading(test->m_webView);
+ test->waitUntilLoadFinished();
test->m_scriptDialogType = WEBKIT_SCRIPT_DIALOG_PROMPT;
GUniquePtr<char> promptDialogMessage(g_strdup_printf(jsPromptFormat, kPromptDialogMessage));
GUniquePtr<char> promptHTML(g_strdup_printf(htmlOnLoadFormat, promptDialogMessage.get()));
test->loadHtml(promptHTML.get(), 0);
test->waitUntilMainLoopFinishes();
+ webkit_web_view_stop_loading(test->m_webView);
+ test->waitUntilLoadFinished();
+
+ test->m_scriptDialogType = WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM;
+ GUniquePtr<char> beforeUnloadDialogHTML(g_strdup_printf(htmlOnBeforeUnloadFormat, kBeforeUnloadConfirmDialogMessage));
+ test->loadHtml(beforeUnloadDialogHTML.get(), nullptr);
+ test->waitUntilLoadFinished();
+
+ // Reload should trigger onbeforeunload.
+#if 0
+ test->simulateUserInteraction();
+ // FIXME: reloading HTML data doesn't emit finished load event.
+ // See https://bugs.webkit.org/show_bug.cgi?id=139089.
+ test->m_scriptDialogConfirmed = false;
+ webkit_web_view_reload(test->m_webView);
+ test->waitUntilLoadFinished();
+ g_assert(test->m_scriptDialogConfirmed);
+#endif
+
+ // Navigation should trigger onbeforeunload.
+ test->simulateUserInteraction();
+ test->m_scriptDialogConfirmed = false;
+ test->loadHtml("<html></html>", nullptr);
+ test->waitUntilLoadFinished();
+ g_assert(test->m_scriptDialogConfirmed);
+
+ // Try close should trigger onbeforeunload.
+ test->m_scriptDialogConfirmed = false;
+ test->loadHtml(beforeUnloadDialogHTML.get(), nullptr);
+ test->waitUntilLoadFinished();
+ test->simulateUserInteraction();
+ test->tryCloseAndWaitUntilClosed();
+ g_assert(test->m_scriptDialogConfirmed);
+
+ // Try close on a page with no unload handlers should not trigger onbeforeunload,
+ // but should actually close the page.
+ test->m_scriptDialogConfirmed = false;
+ test->loadHtml("<html><body></body></html>", nullptr);
+ test->waitUntilLoadFinished();
+ // We got a onbeforeunload of the previous page.
+ g_assert(test->m_scriptDialogConfirmed);
+ test->m_scriptDialogConfirmed = false;
+ test->tryCloseAndWaitUntilClosed();
+ g_assert(!test->m_scriptDialogConfirmed);
}
static void testWebViewWindowProperties(UIClientTest* test, gconstpointer)
@@ -423,13 +632,22 @@ static void testWebViewMouseTarget(UIClientTest* test, gconstpointer)
test->showInWindowAndWaitUntilMapped(GTK_WINDOW_TOPLEVEL);
const char* linksHoveredHTML =
- "<html><body>"
+ "<html><head>"
+ " <script>"
+ " window.onload = function () {"
+ " window.getSelection().removeAllRanges();"
+ " var select_range = document.createRange();"
+ " select_range.selectNodeContents(document.getElementById('text_to_select'));"
+ " window.getSelection().addRange(select_range);"
+ " }"
+ " </script>"
+ "</head><body>"
" <a style='position:absolute; left:1; top:1' href='http://www.webkitgtk.org' title='WebKitGTK+ Title'>WebKitGTK+ Website</a>"
" <img style='position:absolute; left:1; top:10' src='0xdeadbeef' width=5 height=5></img>"
" <a style='position:absolute; left:1; top:20' href='http://www.webkitgtk.org/logo' title='WebKitGTK+ Logo'><img src='0xdeadbeef' width=5 height=5></img></a>"
" <input style='position:absolute; left:1; top:30' size='10'></input>"
- " <div style='position:absolute; left:1; top:50; width:30; height:30; overflow:scroll'>&nbsp;</div>"
" <video style='position:absolute; left:1; top:100' width='300' height='300' controls='controls' preload='none'><source src='movie.ogg' type='video/ogg' /></video>"
+ " <p style='position:absolute; left:1; top:120' id='text_to_select'>Lorem ipsum.</p>"
"</body></html>";
test->loadHtml(linksHoveredHTML, "file:///");
@@ -441,6 +659,7 @@ static void testWebViewMouseTarget(UIClientTest* test, gconstpointer)
g_assert(!webkit_hit_test_result_context_is_image(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_media(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult));
+ g_assert(!webkit_hit_test_result_context_is_selection(hitTestResult));
g_assert_cmpstr(webkit_hit_test_result_get_link_uri(hitTestResult), ==, "http://www.webkitgtk.org/");
g_assert_cmpstr(webkit_hit_test_result_get_link_title(hitTestResult), ==, "WebKitGTK+ Title");
g_assert_cmpstr(webkit_hit_test_result_get_link_label(hitTestResult), ==, "WebKitGTK+ Website");
@@ -452,6 +671,7 @@ static void testWebViewMouseTarget(UIClientTest* test, gconstpointer)
g_assert(!webkit_hit_test_result_context_is_image(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_media(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult));
+ g_assert(!webkit_hit_test_result_context_is_selection(hitTestResult));
g_assert(!test->m_mouseTargetModifiers);
// Move over image with GDK_CONTROL_MASK.
@@ -460,6 +680,7 @@ static void testWebViewMouseTarget(UIClientTest* test, gconstpointer)
g_assert(webkit_hit_test_result_context_is_image(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_media(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult));
+ g_assert(!webkit_hit_test_result_context_is_selection(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_scrollbar(hitTestResult));
g_assert_cmpstr(webkit_hit_test_result_get_image_uri(hitTestResult), ==, "file:///0xdeadbeef");
g_assert(test->m_mouseTargetModifiers & GDK_CONTROL_MASK);
@@ -471,6 +692,7 @@ static void testWebViewMouseTarget(UIClientTest* test, gconstpointer)
g_assert(!webkit_hit_test_result_context_is_media(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_scrollbar(hitTestResult));
+ g_assert(!webkit_hit_test_result_context_is_selection(hitTestResult));
g_assert_cmpstr(webkit_hit_test_result_get_link_uri(hitTestResult), ==, "http://www.webkitgtk.org/logo");
g_assert_cmpstr(webkit_hit_test_result_get_image_uri(hitTestResult), ==, "file:///0xdeadbeef");
g_assert_cmpstr(webkit_hit_test_result_get_link_title(hitTestResult), ==, "WebKitGTK+ Logo");
@@ -484,6 +706,7 @@ static void testWebViewMouseTarget(UIClientTest* test, gconstpointer)
g_assert(webkit_hit_test_result_context_is_media(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_scrollbar(hitTestResult));
+ g_assert(!webkit_hit_test_result_context_is_selection(hitTestResult));
g_assert_cmpstr(webkit_hit_test_result_get_media_uri(hitTestResult), ==, "file:///movie.ogg");
g_assert(!test->m_mouseTargetModifiers);
@@ -494,19 +717,32 @@ static void testWebViewMouseTarget(UIClientTest* test, gconstpointer)
g_assert(!webkit_hit_test_result_context_is_media(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_scrollbar(hitTestResult));
g_assert(webkit_hit_test_result_context_is_editable(hitTestResult));
+ g_assert(!webkit_hit_test_result_context_is_selection(hitTestResult));
g_assert(!test->m_mouseTargetModifiers);
// Move over scrollbar.
- hitTestResult = test->moveMouseAndWaitUntilMouseTargetChanged(5, 75);
+ hitTestResult = test->moveMouseAndWaitUntilMouseTargetChanged(gtk_widget_get_allocated_width(GTK_WIDGET(test->m_webView)) - 4, 5);
g_assert(!webkit_hit_test_result_context_is_link(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_image(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_media(hitTestResult));
g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult));
g_assert(webkit_hit_test_result_context_is_scrollbar(hitTestResult));
+ g_assert(!webkit_hit_test_result_context_is_selection(hitTestResult));
+ g_assert(!test->m_mouseTargetModifiers);
+
+ // Move over selection.
+ hitTestResult = test->moveMouseAndWaitUntilMouseTargetChanged(2, 145);
+ g_assert(!webkit_hit_test_result_context_is_link(hitTestResult));
+ g_assert(!webkit_hit_test_result_context_is_image(hitTestResult));
+ g_assert(!webkit_hit_test_result_context_is_media(hitTestResult));
+ g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult));
+ g_assert(!webkit_hit_test_result_context_is_scrollbar(hitTestResult));
+ g_assert(webkit_hit_test_result_context_is_selection(hitTestResult));
g_assert(!test->m_mouseTargetModifiers);
+
}
-static void testWebViewPermissionRequests(UIClientTest* test, gconstpointer)
+static void testWebViewGeolocationPermissionRequests(UIClientTest* test, gconstpointer)
{
// Some versions of geoclue give a runtime warning because it tries
// to register the error quark twice. See https://bugs.webkit.org/show_bug.cgi?id=89858.
@@ -518,35 +754,108 @@ static void testWebViewPermissionRequests(UIClientTest* test, gconstpointer)
" <script>"
" function runTest()"
" {"
- " navigator.geolocation.getCurrentPosition(function(p) { document.title = \"OK\" },"
- " function(e) { document.title = e.code });"
+ " navigator.geolocation.getCurrentPosition(function(p) { window.webkit.messageHandlers.permission.postMessage('OK'); },"
+ " function(e) { window.webkit.messageHandlers.permission.postMessage(e.code.toString()); });"
" }"
" </script>"
" <body onload='runTest();'></body>"
"</html>";
- // Test denying a permission request.
+ // Geolocation is not allowed from insecure connections like HTTP,
+ // POSITION_UNAVAILABLE ('2') is returned in that case without even
+ // asking the API layer.
test->m_allowPermissionRequests = false;
- test->loadHtml(geolocationRequestHTML, 0);
- test->waitUntilTitleChanged();
+ test->loadHtml(geolocationRequestHTML, "http://foo.com/bar");
+ const gchar* result = test->waitUntilPermissionResultMessageReceived();
+ g_assert_cmpstr(result, ==, "2");
- // According to the Geolocation API specification, '1' is the
- // error code returned for the PERMISSION_DENIED error.
- // http://dev.w3.org/geo/api/spec-source.html#position_error_interface
- const gchar* result = webkit_web_view_get_title(test->m_webView);
+ // Test denying a permission request. PERMISSION_DENIED ('1') is
+ // returned in this case.
+ test->m_allowPermissionRequests = false;
+ test->loadHtml(geolocationRequestHTML, "https://foo.com/bar");
+ result = test->waitUntilPermissionResultMessageReceived();
g_assert_cmpstr(result, ==, "1");
- // Test allowing a permission request.
+ // Test allowing a permission request. Result should be different
+ // to PERMISSION_DENIED ('1').
test->m_allowPermissionRequests = true;
- test->loadHtml(geolocationRequestHTML, 0);
- test->waitUntilTitleChanged();
-
- // Check that we did not get the PERMISSION_DENIED error now.
- result = webkit_web_view_get_title(test->m_webView);
+ test->loadHtml(geolocationRequestHTML, "https://foo.com/bar");
+ result = test->waitUntilPermissionResultMessageReceived();
g_assert_cmpstr(result, !=, "1");
test->addLogFatalFlag(G_LOG_LEVEL_WARNING);
}
+#if ENABLE(MEDIA_STREAM)
+static void testWebViewUserMediaPermissionRequests(UIClientTest* test, gconstpointer)
+{
+ WebKitSettings* settings = webkit_web_view_get_settings(test->m_webView);
+ gboolean enabled = webkit_settings_get_enable_media_stream(settings);
+ webkit_settings_set_enable_media_stream(settings, TRUE);
+
+ test->showInWindowAndWaitUntilMapped();
+ static const char* userMediaRequestHTML =
+ "<html>"
+ " <script>"
+ " function runTest()"
+ " {"
+ " navigator.webkitGetUserMedia({audio: true, video: true},"
+ " function(s) { document.title = \"OK\" },"
+ " function(e) { document.title = e.name });"
+ " }"
+ " </script>"
+ " <body onload='runTest();'></body>"
+ "</html>";
+
+ test->m_verifyMediaTypes = TRUE;
+ test->m_expectedAudioMedia = TRUE;
+ test->m_expectedVideoMedia = TRUE;
+
+ // Test denying a permission request.
+ test->m_allowPermissionRequests = false;
+ test->loadHtml(userMediaRequestHTML, nullptr);
+ test->waitUntilTitleChangedTo("PermissionDeniedError");
+
+ // Test allowing a permission request.
+ test->m_allowPermissionRequests = true;
+ test->loadHtml(userMediaRequestHTML, nullptr);
+ test->waitUntilTitleChangedTo("OK");
+
+ webkit_settings_set_enable_media_stream(settings, enabled);
+}
+
+static void testWebViewAudioOnlyUserMediaPermissionRequests(UIClientTest* test, gconstpointer)
+{
+ WebKitSettings* settings = webkit_web_view_get_settings(test->m_webView);
+ gboolean enabled = webkit_settings_get_enable_media_stream(settings);
+ webkit_settings_set_enable_media_stream(settings, TRUE);
+
+ test->showInWindowAndWaitUntilMapped();
+ static const char* userMediaRequestHTML =
+ "<html>"
+ " <script>"
+ " function runTest()"
+ " {"
+ " navigator.webkitGetUserMedia({audio: true, video: false},"
+ " function(s) { document.title = \"OK\" },"
+ " function(e) { document.title = e.name });"
+ " }"
+ " </script>"
+ " <body onload='runTest();'></body>"
+ "</html>";
+
+ test->m_verifyMediaTypes = TRUE;
+ test->m_expectedAudioMedia = TRUE;
+ test->m_expectedVideoMedia = FALSE;
+
+ // Test denying a permission request.
+ test->m_allowPermissionRequests = false;
+ test->loadHtml(userMediaRequestHTML, nullptr);
+ test->waitUntilTitleChangedTo("PermissionDeniedError");
+
+ webkit_settings_set_enable_media_stream(settings, enabled);
+}
+#endif // ENABLE(MEDIA_STREAM)
+
class FileChooserTest: public UIClientTest {
public:
MAKE_GLIB_TEST_FIXTURE(FileChooserTest);
@@ -662,16 +971,124 @@ static void testWebViewFileChooserRequest(FileChooserTest* test, gconstpointer)
webkit_file_chooser_request_cancel(fileChooserRequest);
}
+class ColorChooserTest: public WebViewTest {
+public:
+ MAKE_GLIB_TEST_FIXTURE(ColorChooserTest);
+
+ static gboolean runColorChooserCallback(WebKitWebView*, WebKitColorChooserRequest* request, ColorChooserTest* test)
+ {
+ test->runColorChooser(request);
+ return TRUE;
+ }
+
+ static void requestFinishedCallback(WebKitColorChooserRequest* request, ColorChooserTest* test)
+ {
+ g_assert(test->m_request.get() == request);
+ test->m_request = nullptr;
+ if (g_main_loop_is_running(test->m_mainLoop))
+ g_main_loop_quit(test->m_mainLoop);
+ }
+
+ ColorChooserTest()
+ {
+ g_signal_connect(m_webView, "run-color-chooser", G_CALLBACK(runColorChooserCallback), this);
+ }
+
+ void runColorChooser(WebKitColorChooserRequest* request)
+ {
+ g_assert(WEBKIT_IS_COLOR_CHOOSER_REQUEST(request));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(request));
+ m_request = request;
+ g_signal_connect(request, "finished", G_CALLBACK(requestFinishedCallback), this);
+ g_main_loop_quit(m_mainLoop);
+ }
+
+ void finishRequest()
+ {
+ g_assert(m_request.get());
+ webkit_color_chooser_request_finish(m_request.get());
+ g_assert(!m_request);
+ }
+
+ void cancelRequest()
+ {
+ g_assert(m_request.get());
+ webkit_color_chooser_request_cancel(m_request.get());
+ g_assert(!m_request);
+ }
+
+ WebKitColorChooserRequest* clickMouseButtonAndWaitForColorChooserRequest(int x, int y)
+ {
+ clickMouseButton(x, y);
+ g_main_loop_run(m_mainLoop);
+ g_assert(m_request.get());
+ return m_request.get();
+ }
+
+private:
+ GRefPtr<WebKitColorChooserRequest> m_request;
+};
+
+static void testWebViewColorChooserRequest(ColorChooserTest* test, gconstpointer)
+{
+ static const char* colorChooserHTMLFormat = "<html><body><input style='position:absolute;left:1;top:1;margin:0;padding:0;width:45;height:25' type='color' %s/></body></html>";
+ test->showInWindowAndWaitUntilMapped();
+
+ GUniquePtr<char> defaultColorHTML(g_strdup_printf(colorChooserHTMLFormat, ""));
+ test->loadHtml(defaultColorHTML.get(), nullptr);
+ test->waitUntilLoadFinished();
+ WebKitColorChooserRequest* request = test->clickMouseButtonAndWaitForColorChooserRequest(5, 5);
+
+ // Default color is black (#000000).
+ GdkRGBA rgba1;
+ GdkRGBA rgba2 = { 0., 0., 0., 1. };
+ webkit_color_chooser_request_get_rgba(request, &rgba1);
+ g_assert(gdk_rgba_equal(&rgba1, &rgba2));
+
+ // Set a different color.
+ rgba2.green = 1;
+ webkit_color_chooser_request_set_rgba(request, &rgba2);
+ webkit_color_chooser_request_get_rgba(request, &rgba1);
+ g_assert(gdk_rgba_equal(&rgba1, &rgba2));
+
+ GdkRectangle rect;
+ webkit_color_chooser_request_get_element_rectangle(request, &rect);
+ g_assert_cmpint(rect.x, == , 1);
+ g_assert_cmpint(rect.y, == , 1);
+ g_assert_cmpint(rect.width, == , 45);
+ g_assert_cmpint(rect.height, == , 25);
+
+ test->finishRequest();
+
+ // Use an initial color.
+ GUniquePtr<char> initialColorHTML(g_strdup_printf(colorChooserHTMLFormat, "value='#FF00FF'"));
+ test->loadHtml(initialColorHTML.get(), nullptr);
+ test->waitUntilLoadFinished();
+ request = test->clickMouseButtonAndWaitForColorChooserRequest(5, 5);
+
+ webkit_color_chooser_request_get_rgba(request, &rgba1);
+ GdkRGBA rgba3 = { 1., 0., 1., 1. };
+ g_assert(gdk_rgba_equal(&rgba1, &rgba3));
+
+ test->cancelRequest();
+}
+
void beforeAll()
{
UIClientTest::add("WebKitWebView", "create-ready-close", testWebViewCreateReadyClose);
+ CreateNavigationDataTest::add("WebKitWebView", "create-navigation-data", testWebViewCreateNavigationData);
ModalDialogsTest::add("WebKitWebView", "allow-modal-dialogs", testWebViewAllowModalDialogs);
ModalDialogsTest::add("WebKitWebView", "disallow-modal-dialogs", testWebViewDisallowModalDialogs);
UIClientTest::add("WebKitWebView", "javascript-dialogs", testWebViewJavaScriptDialogs);
UIClientTest::add("WebKitWebView", "window-properties", testWebViewWindowProperties);
UIClientTest::add("WebKitWebView", "mouse-target", testWebViewMouseTarget);
- UIClientTest::add("WebKitWebView", "permission-requests", testWebViewPermissionRequests);
+ UIClientTest::add("WebKitWebView", "geolocation-permission-requests", testWebViewGeolocationPermissionRequests);
+#if ENABLE(MEDIA_STREAM)
+ UIClientTest::add("WebKitWebView", "usermedia-permission-requests", testWebViewUserMediaPermissionRequests);
+ UIClientTest::add("WebKitWebView", "audio-usermedia-permission-request", testWebViewAudioOnlyUserMediaPermissionRequests);
+#endif
FileChooserTest::add("WebKitWebView", "file-chooser-request", testWebViewFileChooserRequest);
+ ColorChooserTest::add("WebKitWebView", "color-chooser-request", testWebViewColorChooserRequest);
}
void afterAll()
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebExtensions.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebExtensions.cpp
index b02cdfd03..fa4ab2d6c 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebExtensions.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebExtensions.cpp
@@ -21,19 +21,24 @@
#include "WebKitTestBus.h"
#include "WebViewTest.h"
-#include <wtf/gobject/GRefPtr.h>
+#include <wtf/glib/GRefPtr.h>
static const char* webExtensionsUserData = "Web Extensions user data";
static WebKitTestBus* bus;
static GUniquePtr<char> scriptDialogResult;
+#define INPUT_ID "input-id"
+#define FORM_ID "form-id"
+#define FORM2_ID "form2-id"
+
static void testWebExtensionGetTitle(WebViewTest* test, gconstpointer)
{
test->loadHtml("<html><head><title>WebKitGTK+ Web Extensions Test</title></head><body></body></html>", 0);
test->waitUntilLoadFinished();
- GRefPtr<GDBusProxy> proxy = adoptGRef(bus->createProxy("org.webkit.gtk.WebExtensionTest",
- "/org/webkit/gtk/WebExtensionTest" , "org.webkit.gtk.WebExtensionTest", test->m_mainLoop));
+ GUniquePtr<char> extensionBusName(g_strdup_printf("org.webkit.gtk.WebExtensionTest%u", Test::s_webExtensionID));
+ GRefPtr<GDBusProxy> proxy = adoptGRef(bus->createProxy(extensionBusName.get(),
+ "/org/webkit/gtk/WebExtensionTest", "org.webkit.gtk.WebExtensionTest", test->m_mainLoop));
GRefPtr<GVariant> result = adoptGRef(g_dbus_proxy_call_sync(
proxy.get(),
"GetTitle",
@@ -54,7 +59,8 @@ static void documentLoadedCallback(GDBusConnection*, const char*, const char*, c
static void testDocumentLoadedSignal(WebViewTest* test, gconstpointer)
{
- GRefPtr<GDBusProxy> proxy = adoptGRef(bus->createProxy("org.webkit.gtk.WebExtensionTest",
+ GUniquePtr<char> extensionBusName(g_strdup_printf("org.webkit.gtk.WebExtensionTest%u", Test::s_webExtensionID));
+ GRefPtr<GDBusProxy> proxy = adoptGRef(bus->createProxy(extensionBusName.get(),
"/org/webkit/gtk/WebExtensionTest", "org.webkit.gtk.WebExtensionTest", test->m_mainLoop));
GDBusConnection* connection = g_dbus_proxy_get_connection(proxy.get());
guint id = g_dbus_connection_signal_subscribe(connection,
@@ -86,10 +92,13 @@ static void testWebKitWebViewProcessCrashed(WebViewTest* test, gconstpointer)
test->loadHtml("<html></html>", 0);
test->waitUntilLoadFinished();
- g_signal_connect(test->m_webView, "web-process-crashed",
+ g_signal_connect_after(test->m_webView, "web-process-crashed",
G_CALLBACK(webProcessCrashedCallback), test);
- GRefPtr<GDBusProxy> proxy = adoptGRef(bus->createProxy("org.webkit.gtk.WebExtensionTest",
+ test->m_expectedWebProcessCrash = true;
+
+ GUniquePtr<char> extensionBusName(g_strdup_printf("org.webkit.gtk.WebExtensionTest%u", Test::s_webExtensionID));
+ GRefPtr<GDBusProxy> proxy = adoptGRef(bus->createProxy(extensionBusName.get(),
"/org/webkit/gtk/WebExtensionTest", "org.webkit.gtk.WebExtensionTest", test->m_mainLoop));
GRefPtr<GVariant> result = adoptGRef(g_dbus_proxy_call_sync(
@@ -100,6 +109,7 @@ static void testWebKitWebViewProcessCrashed(WebViewTest* test, gconstpointer)
-1, 0, 0));
g_assert(!result);
g_main_loop_run(test->m_mainLoop);
+ test->m_expectedWebProcessCrash = false;
}
static void testWebExtensionWindowObjectCleared(WebViewTest* test, gconstpointer)
@@ -152,7 +162,8 @@ static void testWebExtensionIsolatedWorld(WebViewTest* test, gconstpointer)
"document.getElementById('console').innerHTML = top.foo;\n"
"window.open = function () { alert('Isolated World'); }\n"
"document.open(1, 2, 3);";
- GRefPtr<GDBusProxy> proxy = adoptGRef(bus->createProxy("org.webkit.gtk.WebExtensionTest",
+ GUniquePtr<char> extensionBusName(g_strdup_printf("org.webkit.gtk.WebExtensionTest%u", Test::s_webExtensionID));
+ GRefPtr<GDBusProxy> proxy = adoptGRef(bus->createProxy(extensionBusName.get(),
"/org/webkit/gtk/WebExtensionTest" , "org.webkit.gtk.WebExtensionTest", test->m_mainLoop));
g_dbus_proxy_call(proxy.get(),
"RunJavaScriptInIsolatedWorld",
@@ -173,49 +184,110 @@ static void testWebExtensionIsolatedWorld(WebViewTest* test, gconstpointer)
g_signal_handler_disconnect(test->m_webView, scriptDialogID);
}
-static void testWebExtensionInitializationUserData(WebViewTest* test, gconstpointer)
+static gboolean permissionRequestCallback(WebKitWebView*, WebKitPermissionRequest* request, WebViewTest* test)
{
- test->loadHtml("<html></html>", 0);
- test->waitUntilLoadFinished();
+ if (!WEBKIT_IS_INSTALL_MISSING_MEDIA_PLUGINS_PERMISSION_REQUEST(request))
+ return FALSE;
+
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(request));
+ WebKitInstallMissingMediaPluginsPermissionRequest* missingPluginsRequest = WEBKIT_INSTALL_MISSING_MEDIA_PLUGINS_PERMISSION_REQUEST(request);
+ g_assert(webkit_install_missing_media_plugins_permission_request_get_description(missingPluginsRequest));
+ webkit_permission_request_deny(request);
+ test->quitMainLoop();
+
+ return TRUE;
+}
- GRefPtr<GDBusProxy> proxy = adoptGRef(bus->createProxy("org.webkit.gtk.WebExtensionTest",
+static void testInstallMissingPluginsPermissionRequest(WebViewTest* test, gconstpointer)
+{
+ GUniquePtr<char> extensionBusName(g_strdup_printf("org.webkit.gtk.WebExtensionTest%u", Test::s_webExtensionID));
+ GRefPtr<GDBusProxy> proxy = adoptGRef(bus->createProxy(extensionBusName.get(),
"/org/webkit/gtk/WebExtensionTest", "org.webkit.gtk.WebExtensionTest", test->m_mainLoop));
+ GRefPtr<GVariant> result = adoptGRef(g_dbus_proxy_call_sync(proxy.get(), "RemoveAVPluginsFromGSTRegistry",
+ nullptr, G_DBUS_CALL_FLAGS_NONE, -1, nullptr, nullptr));
- GRefPtr<GVariant> result = adoptGRef(g_dbus_proxy_call_sync(
- proxy.get(),
- "GetInitializationUserData",
- nullptr,
- G_DBUS_CALL_FLAGS_NONE,
- -1, 0, 0));
- g_assert(result);
+ test->showInWindowAndWaitUntilMapped();
- const gchar* userData = nullptr;
- g_variant_get(result.get(), "(&s)", &userData);
- g_assert_cmpstr(userData, ==, webExtensionsUserData);
+ gulong permissionRequestSignalID = g_signal_connect(test->m_webView, "permission-request", G_CALLBACK(permissionRequestCallback), test);
+ // FIXME: the base URI needs to finish with / to work, that shouldn't happen.
+ GUniquePtr<char> baseURI(g_strconcat("file://", Test::getResourcesDir(Test::WebKit2Resources).data(), "/", nullptr));
+ test->loadHtml("<html><body><video src=\"test.mp4\" autoplay></video></body></html>", baseURI.get());
+ g_main_loop_run(test->m_mainLoop);
+ g_signal_handler_disconnect(test->m_webView, permissionRequestSignalID);
}
-static void initializeWebExtensions(WebKitWebContext* context, gpointer)
+static void didAssociateFormControlsCallback(GDBusConnection*, const char*, const char*, const char*, const char*, GVariant* result, WebViewTest* test)
{
- webkit_web_context_set_web_extensions_directory(context, WEBKIT_TEST_WEB_EXTENSIONS_DIR);
- webkit_web_context_set_web_extensions_initialization_user_data(context,
- g_variant_new("&s", webExtensionsUserData));
+ const char* formIds;
+ g_variant_get(result, "(&s)", &formIds);
+ g_assert(!g_strcmp0(formIds, FORM_ID FORM2_ID) || !g_strcmp0(formIds, INPUT_ID));
+
+ test->quitMainLoop();
}
-void beforeAll()
+static void testWebExtensionFormControlsAssociated(WebViewTest* test, gconstpointer)
{
- g_signal_connect(webkit_web_context_get_default(),
- "initialize-web-extensions", G_CALLBACK(initializeWebExtensions), nullptr);
+ GUniquePtr<char> extensionBusName(g_strdup_printf("org.webkit.gtk.WebExtensionTest%u", Test::s_webExtensionID));
+ GRefPtr<GDBusProxy> proxy = adoptGRef(bus->createProxy(extensionBusName.get(),
+ "/org/webkit/gtk/WebExtensionTest", "org.webkit.gtk.WebExtensionTest", test->m_mainLoop));
+ GDBusConnection* connection = g_dbus_proxy_get_connection(proxy.get());
+ guint id = g_dbus_connection_signal_subscribe(connection,
+ nullptr,
+ "org.webkit.gtk.WebExtensionTest",
+ "FormControlsAssociated",
+ "/org/webkit/gtk/WebExtensionTest",
+ nullptr,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ reinterpret_cast<GDBusSignalCallback>(didAssociateFormControlsCallback),
+ test,
+ nullptr);
+ g_assert(id);
+
+ test->loadHtml("<!DOCTYPE html><head><title>WebKitGTK+ Web Extensions Test</title></head><div id=\"placeholder\"/>", 0);
+ test->waitUntilLoadFinished();
+
+ static const char* addFormScript =
+ "var input = document.createElement(\"input\");"
+ "input.id = \"" INPUT_ID "\";"
+ "input.type = \"password\";"
+ "var form = document.createElement(\"form\");"
+ "form.id = \"" FORM_ID "\";"
+ "form.appendChild(input);"
+ "var form2 = document.createElement(\"form\");"
+ "form2.id = \"" FORM2_ID "\";"
+ "var placeholder = document.getElementById(\"placeholder\");"
+ "placeholder.appendChild(form);"
+ "placeholder.appendChild(form2);";
+
+ webkit_web_view_run_javascript(test->m_webView, addFormScript, nullptr, nullptr, nullptr);
+ g_main_loop_run(test->m_mainLoop);
+
+ static const char* moveFormElementScript =
+ "var form = document.getElementById(\"" FORM_ID "\");"
+ "var form2 = document.getElementById(\"" FORM2_ID "\");"
+ "var input = document.getElementById(\"" INPUT_ID "\");"
+ "form.removeChild(input);"
+ "form2.appendChild(input);";
+
+ webkit_web_view_run_javascript(test->m_webView, moveFormElementScript, nullptr, nullptr, nullptr);
+ g_main_loop_run(test->m_mainLoop);
+ g_dbus_connection_signal_unsubscribe(connection, id);
+}
+
+void beforeAll()
+{
bus = new WebKitTestBus();
if (!bus->run())
return;
- WebViewTest::add("WebKitWebContext", "initialization-user-data", testWebExtensionInitializationUserData);
WebViewTest::add("WebKitWebExtension", "dom-document-title", testWebExtensionGetTitle);
WebViewTest::add("WebKitWebExtension", "document-loaded-signal", testDocumentLoadedSignal);
WebViewTest::add("WebKitWebView", "web-process-crashed", testWebKitWebViewProcessCrashed);
WebViewTest::add("WebKitWebExtension", "window-object-cleared", testWebExtensionWindowObjectCleared);
WebViewTest::add("WebKitWebExtension", "isolated-world", testWebExtensionIsolatedWorld);
+ WebViewTest::add("WebKitWebView", "install-missing-plugins-permission-request", testInstallMissingPluginsPermissionRequest);
+ WebViewTest::add("WebKitWebExtension", "form-controls-associated-signal", testWebExtensionFormControlsAssociated);
}
void afterAll()
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitAccessibility.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitAccessibility.cpp
index a5d8df9de..9c6bbdd7c 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitAccessibility.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitAccessibility.cpp
@@ -32,9 +32,8 @@ extern "C" {
#include <glib.h>
#include <signal.h>
#include <unistd.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/gobject/GRefPtr.h>
-#include <wtf/gobject/GUniquePtr.h>
+#include <wtf/glib/GRefPtr.h>
+#include <wtf/glib/GUniquePtr.h>
// Name of the test server application creating the webView object.
static const char* kTestServerAppName = "AccessibilityTestServer";
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitFaviconDatabase.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitFaviconDatabase.cpp
index 0f5a82042..5a3b057fd 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitFaviconDatabase.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitFaviconDatabase.cpp
@@ -23,21 +23,19 @@
#include "WebViewTest.h"
#include <glib/gstdio.h>
#include <libsoup/soup.h>
-#include <wtf/gobject/GUniquePtr.h>
+#include <wtf/glib/GUniquePtr.h>
static WebKitTestServer* kServer;
-static char* kTempDirectory;
class FaviconDatabaseTest: public WebViewTest {
public:
MAKE_GLIB_TEST_FIXTURE(FaviconDatabaseTest);
FaviconDatabaseTest()
- : m_webContext(webkit_web_context_get_default())
- , m_favicon(0)
+ : m_favicon(nullptr)
, m_faviconNotificationReceived(false)
{
- WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(m_webContext);
+ WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(m_webContext.get());
g_signal_connect(database, "favicon-changed", G_CALLBACK(faviconChangedCallback), this);
}
@@ -46,7 +44,7 @@ public:
if (m_favicon)
cairo_surface_destroy(m_favicon);
- WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(m_webContext);
+ WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(m_webContext.get());
g_signal_handlers_disconnect_matched(database, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
}
@@ -67,7 +65,7 @@ public:
static void getFaviconCallback(GObject* sourceObject, GAsyncResult* result, void* data)
{
FaviconDatabaseTest* test = static_cast<FaviconDatabaseTest*>(data);
- WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(test->m_webContext);
+ WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(test->m_webContext.get());
test->m_favicon = webkit_favicon_database_get_favicon_finish(database, result, &test->m_error.outPtr());
test->quitMainLoop();
}
@@ -87,12 +85,11 @@ public:
m_favicon = 0;
}
- WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(m_webContext);
+ WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(m_webContext.get());
webkit_favicon_database_get_favicon(database, pageURI, 0, getFaviconCallback, this);
g_main_loop_run(m_mainLoop);
}
- WebKitWebContext* m_webContext;
cairo_surface_t* m_favicon;
CString m_faviconURI;
GUniqueOutPtr<GError> m_error;
@@ -116,7 +113,7 @@ serverCallback(SoupServer* server, SoupMessage* message, const char* path, GHash
char* contents;
gsize length;
if (g_str_equal(path, "/icon/favicon.ico")) {
- GUniquePtr<char> pathToFavicon(g_build_filename(Test::getWebKit1TestResoucesDir().data(), "blank.ico", NULL));
+ GUniquePtr<char> pathToFavicon(g_build_filename(Test::getResourcesDir().data(), "blank.ico", nullptr));
g_file_get_contents(pathToFavicon.get(), &contents, &length, 0);
soup_message_body_append(message->response_body, SOUP_MEMORY_TAKE, contents, length);
} else if (g_str_equal(path, "/nofavicon")) {
@@ -142,19 +139,43 @@ static void testNotInitialized(FaviconDatabaseTest* test)
static void testSetDirectory(FaviconDatabaseTest* test)
{
- webkit_web_context_set_favicon_database_directory(test->m_webContext, kTempDirectory);
- g_assert_cmpstr(kTempDirectory, ==, webkit_web_context_get_favicon_database_directory(test->m_webContext));
+ webkit_web_context_set_favicon_database_directory(test->m_webContext.get(), Test::dataDirectory());
+ g_assert_cmpstr(Test::dataDirectory(), ==, webkit_web_context_get_favicon_database_directory(test->m_webContext.get()));
}
static void testClearDatabase(FaviconDatabaseTest* test)
{
- WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(test->m_webContext);
+ WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(test->m_webContext.get());
webkit_favicon_database_clear(database);
GUniquePtr<char> iconURI(webkit_favicon_database_get_favicon_uri(database, kServer->getURIForPath("/foo").data()));
g_assert(!iconURI);
}
+static void ephemeralViewLoadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent, WebViewTest* test)
+{
+ if (loadEvent != WEBKIT_LOAD_FINISHED)
+ return;
+ g_signal_handlers_disconnect_by_func(webView, reinterpret_cast<void*>(ephemeralViewLoadChanged), test);
+ test->quitMainLoop();
+}
+
+static void testPrivateBrowsing(FaviconDatabaseTest* test)
+{
+ GRefPtr<WebKitWebView> webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW,
+ "web-context", test->m_webContext.get(),
+ "is-ephemeral", TRUE,
+ nullptr));
+ g_signal_connect(webView.get(), "load-changed", G_CALLBACK(ephemeralViewLoadChanged), test);
+ webkit_web_view_load_uri(webView.get(), kServer->getURIForPath("/foo").data());
+ g_main_loop_run(test->m_mainLoop);
+
+ // An ephemeral web view should not write to the database.
+ test->getFaviconForPageURIAndWaitUntilReady(kServer->getURIForPath("/foo").data());
+ g_assert(!test->m_favicon);
+ g_assert(test->m_error);
+}
+
static void testGetFavicon(FaviconDatabaseTest* test)
{
// We need to load the page first to ensure the icon data will be
@@ -198,7 +219,7 @@ static void testGetFavicon(FaviconDatabaseTest* test)
static void testGetFaviconURI(FaviconDatabaseTest* test)
{
- WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(test->m_webContext);
+ WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(test->m_webContext.get());
CString baseURI = kServer->getURIForPath("/foo");
GUniquePtr<char> iconURI(webkit_favicon_database_get_favicon_uri(database, baseURI.data()));
@@ -231,6 +252,7 @@ static void testFaviconDatabase(FaviconDatabaseTest* test, gconstpointer)
// See https://bugs.webkit.org/show_bug.cgi?id=111434.
testNotInitialized(test);
testSetDirectory(test);
+ testPrivateBrowsing(test);
testGetFavicon(test);
testGetFaviconURI(test);
testWebViewFavicon(test);
@@ -243,30 +265,11 @@ void beforeAll()
kServer = new WebKitTestServer();
kServer->run(serverCallback);
- kTempDirectory = g_dir_make_tmp("WebKit2Tests-XXXXXX", 0);
- g_assert(kTempDirectory);
-
// Add tests to the suite.
FaviconDatabaseTest::add("WebKitFaviconDatabase", "favicon-database-test", testFaviconDatabase);
}
-static void webkitFaviconDatabaseFinalizedCallback(gpointer, GObject*)
-{
- if (!g_file_test(kTempDirectory, G_FILE_TEST_IS_DIR))
- return;
-
- GUniquePtr<char> filename(g_build_filename(kTempDirectory, "WebpageIcons.db", nullptr));
- g_unlink(filename.get());
-
- g_rmdir(kTempDirectory);
-}
-
void afterAll()
{
delete kServer;
-
- // Delete the temporary files after the IconDatabase has been
- // closed, that is, once WebKitFaviconDatabase is being destroyed.
- WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(webkit_web_context_get_default());
- g_object_weak_ref(G_OBJECT(database), webkitFaviconDatabaseFinalizedCallback, 0);
}
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitFindController.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitFindController.cpp
index d2eef4ca4..7289fd37f 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitFindController.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitFindController.cpp
@@ -22,7 +22,7 @@
#include "LoadTrackingTest.h"
#include <gtk/gtk.h>
#include <webkit2/webkit2.h>
-#include <wtf/gobject/GRefPtr.h>
+#include <wtf/glib/GRefPtr.h>
static const char* testString = "<html><body>first testing second testing secondHalf</body></html>";
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitPolicyClient.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitPolicyClient.cpp
index 209ea045e..9f9515123 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitPolicyClient.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitPolicyClient.cpp
@@ -21,7 +21,7 @@
#include "LoadTrackingTest.h"
#include "WebKitTestServer.h"
-#include <wtf/gobject/GRefPtr.h>
+#include <wtf/glib/GRefPtr.h>
#include <wtf/text/CString.h>
static WebKitTestServer* kServer;
@@ -117,11 +117,12 @@ static void testNavigationPolicy(PolicyClientTest* test, gconstpointer)
// Ideally we'd like to have a more intensive test here, but it's still pretty tricky
// to trigger different types of navigations with the GTK+ WebKit2 API.
WebKitNavigationPolicyDecision* decision = WEBKIT_NAVIGATION_POLICY_DECISION(test->m_previousPolicyDecision.get());
- g_assert_cmpint(webkit_navigation_policy_decision_get_navigation_type(decision), ==, WEBKIT_NAVIGATION_TYPE_OTHER);
- g_assert_cmpint(webkit_navigation_policy_decision_get_mouse_button(decision), ==, 0);
- g_assert_cmpint(webkit_navigation_policy_decision_get_modifiers(decision), ==, 0);
- g_assert_cmpstr(webkit_navigation_policy_decision_get_frame_name(decision), ==, 0);
- WebKitURIRequest* request = webkit_navigation_policy_decision_get_request(decision);
+ WebKitNavigationAction* navigationAction = webkit_navigation_policy_decision_get_navigation_action(decision);
+ g_assert_cmpint(webkit_navigation_action_get_navigation_type(navigationAction), ==, WEBKIT_NAVIGATION_TYPE_OTHER);
+ g_assert_cmpint(webkit_navigation_action_get_mouse_button(navigationAction), ==, 0);
+ g_assert_cmpint(webkit_navigation_action_get_modifiers(navigationAction), ==, 0);
+ g_assert(!webkit_navigation_policy_decision_get_frame_name(decision));
+ WebKitURIRequest* request = webkit_navigation_action_get_request(navigationAction);
g_assert_cmpstr(webkit_uri_request_get_uri(request), ==, "http://webkitgtk.org/");
test->m_policyDecisionResponse = PolicyClientTest::Use;
@@ -191,7 +192,7 @@ struct CreateCallbackData {
GMainLoop* mainLoop;
};
-static WebKitWebView* createCallback(WebKitWebView* webView, CreateCallbackData* data)
+static WebKitWebView* createCallback(WebKitWebView* webView, WebKitNavigationAction*, CreateCallbackData* data)
{
data->triedToOpenWindow = true;
g_main_loop_quit(data->mainLoop);
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitSecurityOrigin.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitSecurityOrigin.cpp
new file mode 100644
index 000000000..1cc9e7709
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitSecurityOrigin.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2017 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2,1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include "TestMain.h"
+#include <webkit2/webkit2.h>
+#include <wtf/glib/GUniquePtr.h>
+
+static void testSecurityOriginBasicConstructor(Test*, gconstpointer)
+{
+ WebKitSecurityOrigin* origin = webkit_security_origin_new("http", "127.0.0.1", 1234);
+ g_assert(origin);
+ GUniquePtr<char> asString(webkit_security_origin_to_string(origin));
+ g_assert_cmpstr(asString.get(), ==, "http://127.0.0.1:1234");
+ g_assert_cmpstr(webkit_security_origin_get_protocol(origin), ==, "http");
+ g_assert_cmpstr(webkit_security_origin_get_host(origin), ==, "127.0.0.1");
+ g_assert_cmpint(webkit_security_origin_get_port(origin), ==, 1234);
+ g_assert(!webkit_security_origin_is_opaque(origin));
+ webkit_security_origin_unref(origin);
+}
+
+static void testSecurityOriginURIConstructor(Test*, gconstpointer)
+{
+ WebKitSecurityOrigin* origin = webkit_security_origin_new_for_uri("http://127.0.0.1:1234");
+ g_assert(origin);
+ GUniquePtr<char> asString(webkit_security_origin_to_string(origin));
+ g_assert_cmpstr(asString.get(), ==, "http://127.0.0.1:1234");
+ g_assert_cmpstr(webkit_security_origin_get_protocol(origin), ==, "http");
+ g_assert_cmpstr(webkit_security_origin_get_host(origin), ==, "127.0.0.1");
+ g_assert_cmpint(webkit_security_origin_get_port(origin), ==, 1234);
+ g_assert(!webkit_security_origin_is_opaque(origin));
+ webkit_security_origin_unref(origin);
+
+ origin = webkit_security_origin_new_for_uri("http://127.0.0.1:1234/this/path/?should=be#ignored");
+ g_assert(origin);
+ asString.reset(webkit_security_origin_to_string(origin));
+ g_assert_cmpstr(asString.get(), ==, "http://127.0.0.1:1234");
+ g_assert_cmpstr(webkit_security_origin_get_protocol(origin), ==, "http");
+ g_assert_cmpstr(webkit_security_origin_get_host(origin), ==, "127.0.0.1");
+ g_assert_cmpint(webkit_security_origin_get_port(origin), ==, 1234);
+ g_assert(!webkit_security_origin_is_opaque(origin));
+ webkit_security_origin_unref(origin);
+}
+
+static void testSecurityOriginDefaultPort(Test*, gconstpointer)
+{
+ WebKitSecurityOrigin* origin = webkit_security_origin_new("http", "127.0.0.1", 0);
+ g_assert(origin);
+ GUniquePtr<char> asString(webkit_security_origin_to_string(origin));
+ g_assert_cmpstr(asString.get(), ==, "http://127.0.0.1");
+ g_assert_cmpstr(webkit_security_origin_get_protocol(origin), ==, "http");
+ g_assert_cmpstr(webkit_security_origin_get_host(origin), ==, "127.0.0.1");
+ g_assert_cmpint(webkit_security_origin_get_port(origin), ==, 0);
+ g_assert(!webkit_security_origin_is_opaque(origin));
+ webkit_security_origin_unref(origin);
+
+ origin = webkit_security_origin_new("http", "127.0.0.1", 80);
+ g_assert(origin);
+ asString.reset(webkit_security_origin_to_string(origin));
+ g_assert_cmpstr(asString.get(), ==, "http://127.0.0.1");
+ g_assert_cmpstr(webkit_security_origin_get_protocol(origin), ==, "http");
+ g_assert_cmpstr(webkit_security_origin_get_host(origin), ==, "127.0.0.1");
+ g_assert_cmpint(webkit_security_origin_get_port(origin), ==, 0);
+ g_assert(!webkit_security_origin_is_opaque(origin));
+ webkit_security_origin_unref(origin);
+
+ origin = webkit_security_origin_new_for_uri("http://127.0.0.1");
+ g_assert(origin);
+ asString.reset(webkit_security_origin_to_string(origin));
+ g_assert_cmpstr(asString.get(), ==, "http://127.0.0.1");
+ g_assert_cmpstr(webkit_security_origin_get_protocol(origin), ==, "http");
+ g_assert_cmpstr(webkit_security_origin_get_host(origin), ==, "127.0.0.1");
+ g_assert_cmpint(webkit_security_origin_get_port(origin), ==, 0);
+ g_assert(!webkit_security_origin_is_opaque(origin));
+ webkit_security_origin_unref(origin);
+
+ origin = webkit_security_origin_new_for_uri("http://127.0.0.1:80");
+ g_assert(origin);
+ asString.reset(webkit_security_origin_to_string(origin));
+ g_assert_cmpstr(asString.get(), ==, "http://127.0.0.1");
+ g_assert_cmpstr(webkit_security_origin_get_protocol(origin), ==, "http");
+ g_assert_cmpstr(webkit_security_origin_get_host(origin), ==, "127.0.0.1");
+ g_assert_cmpint(webkit_security_origin_get_port(origin), ==, 0);
+ g_assert(!webkit_security_origin_is_opaque(origin));
+ webkit_security_origin_unref(origin);
+}
+
+static void testSecurityOriginFileURI(Test*, gconstpointer)
+{
+ WebKitSecurityOrigin* origin = webkit_security_origin_new_for_uri("file:///abcdefg");
+ g_assert(origin);
+ GUniquePtr<char> asString(webkit_security_origin_to_string(origin));
+ g_assert_cmpstr(asString.get(), ==, "file://");
+ g_assert_cmpstr(webkit_security_origin_get_protocol(origin), ==, "file");
+ g_assert(!webkit_security_origin_get_host(origin));
+ g_assert_cmpint(webkit_security_origin_get_port(origin), ==, 0);
+ g_assert(!webkit_security_origin_is_opaque(origin));
+ webkit_security_origin_unref(origin);
+}
+
+static void testOpaqueSecurityOrigin(Test*, gconstpointer)
+{
+ WebKitSecurityOrigin* origin = webkit_security_origin_new_for_uri("data:Lali ho!");
+ g_assert(origin);
+ GUniquePtr<char> asString(webkit_security_origin_to_string(origin));
+ g_assert(!asString);
+ g_assert(!webkit_security_origin_get_protocol(origin));
+ g_assert(!webkit_security_origin_get_host(origin));
+ g_assert_cmpint(webkit_security_origin_get_port(origin), ==, 0);
+ g_assert(webkit_security_origin_is_opaque(origin));
+ webkit_security_origin_unref(origin);
+}
+
+void beforeAll()
+{
+ Test::add("WebKitSecurityOrigin", "basic-constructor", testSecurityOriginBasicConstructor);
+ Test::add("WebKitSecurityOrigin", "uri-constructor", testSecurityOriginURIConstructor);
+ Test::add("WebKitSecruityOrigin", "default-port", testSecurityOriginDefaultPort);
+ Test::add("WebKitSecurityOrigin", "file-uri", testSecurityOriginFileURI);
+ Test::add("WebKitSecruityOrigin", "opaque-origin", testOpaqueSecurityOrigin);
+}
+
+void afterAll()
+{
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitSettings.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitSettings.cpp
index fb1091889..db60c2fe8 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitSettings.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitSettings.cpp
@@ -35,7 +35,7 @@
#include "WebKitTestServer.h"
#include <gtk/gtk.h>
#include <webkit2/webkit2.h>
-#include <wtf/gobject/GRefPtr.h>
+#include <wtf/glib/GRefPtr.h>
static WebKitTestServer* gServer;
@@ -158,9 +158,11 @@ static void testWebKitSettings(Test*, gconstpointer)
webkit_settings_set_default_charset(settings, "utf8");
g_assert_cmpstr(webkit_settings_get_default_charset(settings), ==, "utf8");
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
g_assert(!webkit_settings_get_enable_private_browsing(settings));
webkit_settings_set_enable_private_browsing(settings, TRUE);
g_assert(webkit_settings_get_enable_private_browsing(settings));
+ G_GNUC_END_IGNORE_DEPRECATIONS;
g_assert(!webkit_settings_get_enable_developer_extras(settings));
webkit_settings_set_enable_developer_extras(settings, TRUE);
@@ -273,6 +275,25 @@ static void testWebKitSettings(Test*, gconstpointer)
webkit_settings_set_enable_mediasource(settings, TRUE);
g_assert(webkit_settings_get_enable_mediasource(settings));
+ // File access from file URLs is not allowed by default.
+ g_assert(!webkit_settings_get_allow_file_access_from_file_urls(settings));
+ webkit_settings_set_allow_file_access_from_file_urls(settings, TRUE);
+ g_assert(webkit_settings_get_allow_file_access_from_file_urls(settings));
+
+ // Universal access from file URLs is not allowed by default.
+ g_assert(!webkit_settings_get_allow_universal_access_from_file_urls(settings));
+ webkit_settings_set_allow_universal_access_from_file_urls(settings, TRUE);
+ g_assert(webkit_settings_get_allow_universal_access_from_file_urls(settings));
+
+ // Ondemand is the default hardware acceleration policy.
+ g_assert_cmpuint(webkit_settings_get_hardware_acceleration_policy(settings), ==, WEBKIT_HARDWARE_ACCELERATION_POLICY_ON_DEMAND);
+ webkit_settings_set_hardware_acceleration_policy(settings, WEBKIT_HARDWARE_ACCELERATION_POLICY_NEVER);
+ g_assert_cmpuint(webkit_settings_get_hardware_acceleration_policy(settings), ==, WEBKIT_HARDWARE_ACCELERATION_POLICY_NEVER);
+ webkit_settings_set_hardware_acceleration_policy(settings, WEBKIT_HARDWARE_ACCELERATION_POLICY_ALWAYS);
+ g_assert_cmpuint(webkit_settings_get_hardware_acceleration_policy(settings), ==, WEBKIT_HARDWARE_ACCELERATION_POLICY_ALWAYS);
+ webkit_settings_set_hardware_acceleration_policy(settings, WEBKIT_HARDWARE_ACCELERATION_POLICY_ON_DEMAND);
+ g_assert_cmpuint(webkit_settings_get_hardware_acceleration_policy(settings), ==, WEBKIT_HARDWARE_ACCELERATION_POLICY_ON_DEMAND);
+
g_object_unref(G_OBJECT(settings));
}
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitUserContentManager.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitUserContentManager.cpp
new file mode 100644
index 000000000..134ad3837
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitUserContentManager.cpp
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2013-2014 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2,1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include "WebKitTestServer.h"
+#include "WebViewTest.h"
+#include <cstdarg>
+#include <gtk/gtk.h>
+#include <webkit2/webkit2.h>
+#include <wtf/glib/GRefPtr.h>
+#include <wtf/glib/GUniquePtr.h>
+
+static WebKitTestServer* kServer;
+
+// These are all here so that they can be changed easily, if necessary.
+static const char* kStyleSheetHTML = "<html><div id=\"styledElement\">Sweet stylez!</div></html>";
+static const char* kInjectedStyleSheet = "#styledElement { font-weight: bold; }";
+static const char* kStyleSheetTestScript = "getComputedStyle(document.getElementById('styledElement'))['font-weight']";
+static const char* kStyleSheetTestScriptResult = "bold";
+static const char* kInjectedScript = "document.write('<div id=\"item\">Generated by a script</div>')";
+static const char* kScriptTestScript = "document.getElementById('item').innerText";
+static const char* kScriptTestScriptResult = "Generated by a script";
+
+static void testWebViewNewWithUserContentManager(Test* test, gconstpointer)
+{
+ GRefPtr<WebKitUserContentManager> userContentManager1 = adoptGRef(webkit_user_content_manager_new());
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(userContentManager1.get()));
+ GRefPtr<WebKitWebView> webView1 = WEBKIT_WEB_VIEW(webkit_web_view_new_with_user_content_manager(userContentManager1.get()));
+ g_assert(webkit_web_view_get_user_content_manager(webView1.get()) == userContentManager1.get());
+
+ GRefPtr<WebKitWebView> webView2 = WEBKIT_WEB_VIEW(webkit_web_view_new());
+ g_assert(webkit_web_view_get_user_content_manager(webView2.get()) != userContentManager1.get());
+}
+
+static bool isStyleSheetInjectedForURLAtPath(WebViewTest* test, const char* path)
+{
+ test->loadURI(kServer->getURIForPath(path).data());
+ test->waitUntilLoadFinished();
+
+ GUniqueOutPtr<GError> error;
+ WebKitJavascriptResult* javascriptResult = test->runJavaScriptAndWaitUntilFinished(kStyleSheetTestScript, &error.outPtr());
+ g_assert(javascriptResult);
+ g_assert(!error.get());
+
+ GUniquePtr<char> resultString(WebViewTest::javascriptResultToCString(javascriptResult));
+ return !g_strcmp0(resultString.get(), kStyleSheetTestScriptResult);
+}
+
+static bool isScriptInjectedForURLAtPath(WebViewTest* test, const char* path)
+{
+ test->loadURI(kServer->getURIForPath(path).data());
+ test->waitUntilLoadFinished();
+
+ GUniqueOutPtr<GError> error;
+ if (WebKitJavascriptResult* javascriptResult = test->runJavaScriptAndWaitUntilFinished(kScriptTestScript, &error.outPtr())) {
+ g_assert(!error.get());
+
+ GUniquePtr<char> resultString(WebViewTest::javascriptResultToCString(javascriptResult));
+ return !g_strcmp0(resultString.get(), kScriptTestScriptResult);
+ }
+ return false;
+}
+
+static void fillURLListFromPaths(char** list, const char* path, ...)
+{
+ va_list argumentList;
+ va_start(argumentList, path);
+
+ int i = 0;
+ while (path) {
+ // FIXME: We must use a wildcard for the host here until http://wkbug.com/112476 is fixed.
+ // Until that time patterns with port numbers in them will not properly match URLs with port numbers.
+ list[i++] = g_strdup_printf("http://*/%s*", path);
+ path = va_arg(argumentList, const char*);
+ }
+}
+
+static void removeOldInjectedContentAndResetLists(WebKitUserContentManager* userContentManager, char** whitelist, char** blacklist)
+{
+ webkit_user_content_manager_remove_all_style_sheets(userContentManager);
+ webkit_user_content_manager_remove_all_scripts(userContentManager);
+
+ while (*whitelist) {
+ g_free(*whitelist);
+ *whitelist = 0;
+ whitelist++;
+ }
+
+ while (*blacklist) {
+ g_free(*blacklist);
+ *blacklist = 0;
+ blacklist++;
+ }
+}
+
+static void testUserContentManagerInjectedStyleSheet(WebViewTest* test, gconstpointer)
+{
+ char* whitelist[3] = { 0, 0, 0 };
+ char* blacklist[3] = { 0, 0, 0 };
+
+ removeOldInjectedContentAndResetLists(test->m_userContentManager.get(), whitelist, blacklist);
+
+ // Without a whitelist or a blacklist all URLs should have the injected style sheet.
+ static const char* randomPath = "somerandompath";
+ g_assert(!isStyleSheetInjectedForURLAtPath(test, randomPath));
+ WebKitUserStyleSheet* styleSheet = webkit_user_style_sheet_new(kInjectedStyleSheet, WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES, WEBKIT_USER_STYLE_LEVEL_USER, nullptr, nullptr);
+ webkit_user_content_manager_add_style_sheet(test->m_userContentManager.get(), styleSheet);
+ webkit_user_style_sheet_unref(styleSheet);
+ g_assert(isStyleSheetInjectedForURLAtPath(test, randomPath));
+
+ removeOldInjectedContentAndResetLists(test->m_userContentManager.get(), whitelist, blacklist);
+
+ fillURLListFromPaths(blacklist, randomPath, 0);
+ styleSheet = webkit_user_style_sheet_new(kInjectedStyleSheet, WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES, WEBKIT_USER_STYLE_LEVEL_USER, nullptr, blacklist);
+ webkit_user_content_manager_add_style_sheet(test->m_userContentManager.get(), styleSheet);
+ webkit_user_style_sheet_unref(styleSheet);
+ g_assert(!isStyleSheetInjectedForURLAtPath(test, randomPath));
+ g_assert(isStyleSheetInjectedForURLAtPath(test, "someotherrandompath"));
+
+ removeOldInjectedContentAndResetLists(test->m_userContentManager.get(), whitelist, blacklist);
+
+ static const char* inTheWhiteList = "inthewhitelist";
+ static const char* notInWhitelist = "notinthewhitelist";
+ static const char* inTheWhiteListAndBlackList = "inthewhitelistandblacklist";
+
+ fillURLListFromPaths(whitelist, inTheWhiteList, inTheWhiteListAndBlackList, 0);
+ fillURLListFromPaths(blacklist, inTheWhiteListAndBlackList, 0);
+ styleSheet = webkit_user_style_sheet_new(kInjectedStyleSheet, WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES, WEBKIT_USER_STYLE_LEVEL_USER, whitelist, blacklist);
+ webkit_user_content_manager_add_style_sheet(test->m_userContentManager.get(), styleSheet);
+ webkit_user_style_sheet_unref(styleSheet);
+ g_assert(isStyleSheetInjectedForURLAtPath(test, inTheWhiteList));
+ g_assert(!isStyleSheetInjectedForURLAtPath(test, inTheWhiteListAndBlackList));
+ g_assert(!isStyleSheetInjectedForURLAtPath(test, notInWhitelist));
+
+ // It's important to clean up the environment before other tests.
+ removeOldInjectedContentAndResetLists(test->m_userContentManager.get(), whitelist, blacklist);
+}
+
+static void testUserContentManagerInjectedScript(WebViewTest* test, gconstpointer)
+{
+ char* whitelist[3] = { 0, 0, 0 };
+ char* blacklist[3] = { 0, 0, 0 };
+
+ removeOldInjectedContentAndResetLists(test->m_userContentManager.get(), whitelist, blacklist);
+
+ // Without a whitelist or a blacklist all URLs should have the injected script.
+ static const char* randomPath = "somerandompath";
+ g_assert(!isScriptInjectedForURLAtPath(test, randomPath));
+ WebKitUserScript* script = webkit_user_script_new(kInjectedScript, WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES, WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_END, nullptr, nullptr);
+ webkit_user_content_manager_add_script(test->m_userContentManager.get(), script);
+ webkit_user_script_unref(script);
+ g_assert(isScriptInjectedForURLAtPath(test, randomPath));
+
+ removeOldInjectedContentAndResetLists(test->m_userContentManager.get(), whitelist, blacklist);
+
+ fillURLListFromPaths(blacklist, randomPath, 0);
+ script = webkit_user_script_new(kInjectedScript, WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES, WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_END, nullptr, blacklist);
+ webkit_user_content_manager_add_script(test->m_userContentManager.get(), script);
+ webkit_user_script_unref(script);
+ g_assert(!isScriptInjectedForURLAtPath(test, randomPath));
+ g_assert(isScriptInjectedForURLAtPath(test, "someotherrandompath"));
+
+ removeOldInjectedContentAndResetLists(test->m_userContentManager.get(), whitelist, blacklist);
+
+ static const char* inTheWhiteList = "inthewhitelist";
+ static const char* notInWhitelist = "notinthewhitelist";
+ static const char* inTheWhiteListAndBlackList = "inthewhitelistandblacklist";
+
+ fillURLListFromPaths(whitelist, inTheWhiteList, inTheWhiteListAndBlackList, 0);
+ fillURLListFromPaths(blacklist, inTheWhiteListAndBlackList, 0);
+ script = webkit_user_script_new(kInjectedScript, WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES, WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_END, whitelist, blacklist);
+ webkit_user_content_manager_add_script(test->m_userContentManager.get(), script);
+ webkit_user_script_unref(script);
+ g_assert(isScriptInjectedForURLAtPath(test, inTheWhiteList));
+ g_assert(!isScriptInjectedForURLAtPath(test, inTheWhiteListAndBlackList));
+ g_assert(!isScriptInjectedForURLAtPath(test, notInWhitelist));
+
+ // It's important to clean up the environment before other tests.
+ removeOldInjectedContentAndResetLists(test->m_userContentManager.get(), whitelist, blacklist);
+}
+
+class UserScriptMessageTest : public WebViewTest {
+public:
+ MAKE_GLIB_TEST_FIXTURE(UserScriptMessageTest);
+
+ UserScriptMessageTest()
+ : m_userScriptMessage(nullptr)
+ {
+ }
+
+ ~UserScriptMessageTest()
+ {
+ if (m_userScriptMessage)
+ webkit_javascript_result_unref(m_userScriptMessage);
+ }
+
+ bool registerHandler(const char* handlerName)
+ {
+ return webkit_user_content_manager_register_script_message_handler(m_userContentManager.get(), handlerName);
+ }
+
+ void unregisterHandler(const char* handlerName)
+ {
+ webkit_user_content_manager_unregister_script_message_handler(m_userContentManager.get(), handlerName);
+ }
+
+ static void scriptMessageReceived(WebKitUserContentManager* userContentManager, WebKitJavascriptResult* jsResult, UserScriptMessageTest* test)
+ {
+ g_signal_handlers_disconnect_by_func(userContentManager, reinterpret_cast<gpointer>(scriptMessageReceived), test);
+ g_main_loop_quit(test->m_mainLoop);
+
+ g_assert(!test->m_userScriptMessage);
+ test->m_userScriptMessage = webkit_javascript_result_ref(jsResult);
+ }
+
+ WebKitJavascriptResult* waitUntilMessageReceived(const char* handlerName)
+ {
+ if (m_userScriptMessage) {
+ webkit_javascript_result_unref(m_userScriptMessage);
+ m_userScriptMessage = nullptr;
+ }
+
+ GUniquePtr<char> signalName(g_strdup_printf("script-message-received::%s", handlerName));
+ g_signal_connect(m_userContentManager.get(), signalName.get(), G_CALLBACK(scriptMessageReceived), this);
+
+ g_main_loop_run(m_mainLoop);
+ g_assert(m_userScriptMessage);
+ return m_userScriptMessage;
+ }
+
+ WebKitJavascriptResult* postMessageAndWaitUntilReceived(const char* handlerName, const char* javascriptValueAsText)
+ {
+ GUniquePtr<char> javascriptSnippet(g_strdup_printf("window.webkit.messageHandlers.%s.postMessage(%s);", handlerName, javascriptValueAsText));
+ webkit_web_view_run_javascript(m_webView, javascriptSnippet.get(), nullptr, nullptr, nullptr);
+ return waitUntilMessageReceived(handlerName);
+ }
+
+private:
+ WebKitJavascriptResult* m_userScriptMessage;
+};
+
+static void testUserContentManagerScriptMessageReceived(UserScriptMessageTest* test, gconstpointer)
+{
+ g_assert(test->registerHandler("msg"));
+
+ // Trying to register the same handler a second time must fail.
+ g_assert(!test->registerHandler("msg"));
+
+ test->loadHtml("<html></html>", nullptr);
+ test->waitUntilLoadFinished();
+
+ // Check that the "window.webkit.messageHandlers" namespace exists.
+ GUniqueOutPtr<GError> error;
+ WebKitJavascriptResult* javascriptResult = test->runJavaScriptAndWaitUntilFinished("window.webkit.messageHandlers ? 'y' : 'n';", &error.outPtr());
+ g_assert(javascriptResult);
+ g_assert(!error.get());
+ GUniquePtr<char> valueString(WebViewTest::javascriptResultToCString(javascriptResult));
+ g_assert_cmpstr(valueString.get(), ==, "y");
+
+ // Check that the "document.webkit.messageHandlers.msg" namespace exists.
+ javascriptResult = test->runJavaScriptAndWaitUntilFinished("window.webkit.messageHandlers.msg ? 'y' : 'n';", &error.outPtr());
+ g_assert(javascriptResult);
+ g_assert(!error.get());
+ valueString.reset(WebViewTest::javascriptResultToCString(javascriptResult));
+ g_assert_cmpstr(valueString.get(), ==, "y");
+
+ valueString.reset(WebViewTest::javascriptResultToCString(test->postMessageAndWaitUntilReceived("msg", "'user message'")));
+ g_assert_cmpstr(valueString.get(), ==, "user message");
+
+ // Messages should arrive despite of other handlers being registered.
+ g_assert(test->registerHandler("anotherHandler"));
+
+ // Check that the "document.webkit.messageHandlers.msg" namespace still exists.
+ javascriptResult = test->runJavaScriptAndWaitUntilFinished("window.webkit.messageHandlers.msg ? 'y' : 'n';", &error.outPtr());
+ g_assert(javascriptResult);
+ g_assert(!error.get());
+ valueString.reset(WebViewTest::javascriptResultToCString(javascriptResult));
+ g_assert_cmpstr(valueString.get(), ==, "y");
+
+ // Check that the "document.webkit.messageHandlers.anotherHandler" namespace exists.
+ javascriptResult = test->runJavaScriptAndWaitUntilFinished("window.webkit.messageHandlers.anotherHandler ? 'y' : 'n';", &error.outPtr());
+ g_assert(javascriptResult);
+ g_assert(!error.get());
+ valueString.reset(WebViewTest::javascriptResultToCString(javascriptResult));
+ g_assert_cmpstr(valueString.get(), ==, "y");
+
+ valueString.reset(WebViewTest::javascriptResultToCString(test->postMessageAndWaitUntilReceived("msg", "'handler: msg'")));
+ g_assert_cmpstr(valueString.get(), ==, "handler: msg");
+
+ valueString.reset(WebViewTest::javascriptResultToCString(test->postMessageAndWaitUntilReceived("anotherHandler", "'handler: anotherHandler'")));
+ g_assert_cmpstr(valueString.get(), ==, "handler: anotherHandler");
+
+ // Unregistering a handler and re-registering again under the same name should work.
+ test->unregisterHandler("msg");
+
+ javascriptResult = test->runJavaScriptAndWaitUntilFinished("window.webkit.messageHandlers.msg.postMessage('42');", &error.outPtr());
+ g_assert(!javascriptResult);
+ g_assert(error.get());
+
+ // Re-registering a handler that has been unregistered must work
+ g_assert(test->registerHandler("msg"));
+ valueString.reset(WebViewTest::javascriptResultToCString(test->postMessageAndWaitUntilReceived("msg", "'handler: msg'")));
+ g_assert_cmpstr(valueString.get(), ==, "handler: msg");
+
+ test->unregisterHandler("anotherHandler");
+}
+
+static void testUserContentManagerScriptMessageFromDOMBindings(UserScriptMessageTest* test, gconstpointer)
+{
+ g_assert(test->registerHandler("dom"));
+
+ test->loadHtml("<html>1</html>", nullptr);
+ WebKitJavascriptResult* javascriptResult = test->waitUntilMessageReceived("dom");
+ g_assert(javascriptResult);
+ GUniquePtr<char> valueString(WebViewTest::javascriptResultToCString(javascriptResult));
+ g_assert_cmpstr(valueString.get(), ==, "DocumentLoaded");
+
+ test->unregisterHandler("dom");
+}
+
+static void serverCallback(SoupServer* server, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, gpointer)
+{
+ soup_message_set_status(message, SOUP_STATUS_OK);
+ soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, kStyleSheetHTML, strlen(kStyleSheetHTML));
+ soup_message_body_complete(message->response_body);
+}
+
+void beforeAll()
+{
+ kServer = new WebKitTestServer();
+ kServer->run(serverCallback);
+
+ Test::add("WebKitWebView", "new-with-user-content-manager", testWebViewNewWithUserContentManager);
+ WebViewTest::add("WebKitUserContentManager", "injected-style-sheet", testUserContentManagerInjectedStyleSheet);
+ WebViewTest::add("WebKitUserContentManager", "injected-script", testUserContentManagerInjectedScript);
+ UserScriptMessageTest::add("WebKitUserContentManager", "script-message-received", testUserContentManagerScriptMessageReceived);
+ UserScriptMessageTest::add("WebKitUserContentManager", "script-message-from-dom-bindings", testUserContentManagerScriptMessageFromDOMBindings);
+}
+
+void afterAll()
+{
+ delete kServer;
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitWebContext.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitWebContext.cpp
index 74e8d6817..e7b03fe0d 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitWebContext.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitWebContext.cpp
@@ -22,10 +22,13 @@
#include "LoadTrackingTest.h"
#include "WebKitTestServer.h"
#include <gtk/gtk.h>
+#include <limits.h>
+#include <stdlib.h>
#include <webkit2/webkit2.h>
#include <wtf/HashMap.h>
-#include <wtf/gobject/GRefPtr.h>
-#include <wtf/gobject/GUniquePtr.h>
+#include <wtf/glib/GRefPtr.h>
+#include <wtf/glib/GUniquePtr.h>
+#include <wtf/text/StringBuilder.h>
#include <wtf/text/StringHash.h>
static WebKitTestServer* kServer;
@@ -34,6 +37,45 @@ static void testWebContextDefault(Test* test, gconstpointer)
{
// Check there's a single instance of the default web context.
g_assert(webkit_web_context_get_default() == webkit_web_context_get_default());
+ g_assert(webkit_web_context_get_default() != test->m_webContext.get());
+}
+
+static void testWebContextEphemeral(Test* test, gconstpointer)
+{
+ // By default web contexts are not ephemeral.
+ g_assert(!webkit_web_context_is_ephemeral(webkit_web_context_get_default()));
+ g_assert(!webkit_web_context_is_ephemeral(test->m_webContext.get()));
+
+ WebKitWebsiteDataManager* manager = webkit_web_context_get_website_data_manager(webkit_web_context_get_default());
+ g_assert(WEBKIT_IS_WEBSITE_DATA_MANAGER(manager));
+ g_assert(!webkit_website_data_manager_is_ephemeral(manager));
+ manager = webkit_web_context_get_website_data_manager(test->m_webContext.get());
+ g_assert(WEBKIT_IS_WEBSITE_DATA_MANAGER(manager));
+ g_assert(!webkit_website_data_manager_is_ephemeral(manager));
+
+ GRefPtr<WebKitWebView> webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
+ g_assert(!webkit_web_view_is_ephemeral(webView.get()));
+ g_assert(webkit_web_view_get_website_data_manager(webView.get()) == webkit_web_context_get_website_data_manager(webkit_web_context_get_default()));
+
+ webView = WEBKIT_WEB_VIEW(webkit_web_view_new_with_context(test->m_webContext.get()));
+ g_assert(!webkit_web_view_is_ephemeral(webView.get()));
+ g_assert(webkit_web_view_get_website_data_manager(webView.get()) == manager);
+
+ GRefPtr<WebKitWebContext> context = adoptGRef(webkit_web_context_new_ephemeral());
+ g_assert(webkit_web_context_is_ephemeral(context.get()));
+ manager = webkit_web_context_get_website_data_manager(context.get());
+ g_assert(WEBKIT_IS_WEBSITE_DATA_MANAGER(manager));
+ g_assert(webkit_website_data_manager_is_ephemeral(manager));
+ g_assert(webkit_web_view_get_website_data_manager(webView.get()) != manager);
+
+ webView = WEBKIT_WEB_VIEW(webkit_web_view_new_with_context(context.get()));
+ g_assert(webkit_web_view_is_ephemeral(webView.get()));
+ g_assert(webkit_web_view_get_website_data_manager(webView.get()) == manager);
+
+ GRefPtr<WebKitWebsiteDataManager> ephemeralManager = adoptGRef(webkit_website_data_manager_new_ephemeral());
+ g_assert(webkit_website_data_manager_is_ephemeral(ephemeralManager.get()));
+ context = adoptGRef(webkit_web_context_new_with_website_data_manager(ephemeralManager.get()));
+ g_assert(webkit_web_context_is_ephemeral(context.get()));
}
class PluginsTest: public Test {
@@ -41,11 +83,10 @@ public:
MAKE_GLIB_TEST_FIXTURE(PluginsTest);
PluginsTest()
- : m_context(webkit_web_context_get_default())
- , m_mainLoop(g_main_loop_new(0, TRUE))
- , m_plugins(0)
+ : m_mainLoop(g_main_loop_new(nullptr, TRUE))
+ , m_plugins(nullptr)
{
- webkit_web_context_set_additional_plugins_directory(m_context, WEBKIT_TEST_PLUGIN_DIR);
+ webkit_web_context_set_additional_plugins_directory(m_webContext.get(), WEBKIT_TEST_PLUGIN_DIR);
}
~PluginsTest()
@@ -56,19 +97,18 @@ public:
static void getPluginsAsyncReadyCallback(GObject*, GAsyncResult* result, PluginsTest* test)
{
- test->m_plugins = webkit_web_context_get_plugins_finish(test->m_context, result, 0);
+ test->m_plugins = webkit_web_context_get_plugins_finish(test->m_webContext.get(), result, nullptr);
g_main_loop_quit(test->m_mainLoop);
}
GList* getPlugins()
{
g_list_free_full(m_plugins, g_object_unref);
- webkit_web_context_get_plugins(m_context, 0, reinterpret_cast<GAsyncReadyCallback>(getPluginsAsyncReadyCallback), this);
+ webkit_web_context_get_plugins(m_webContext.get(), nullptr, reinterpret_cast<GAsyncReadyCallback>(getPluginsAsyncReadyCallback), this);
g_main_loop_run(m_mainLoop);
return m_plugins;
}
- WebKitWebContext* m_context;
GMainLoop* m_mainLoop;
GList* m_plugins;
};
@@ -89,7 +129,9 @@ static void testWebContextGetPlugins(PluginsTest* test, gconstpointer)
}
g_assert(WEBKIT_IS_PLUGIN(testPlugin.get()));
- GUniquePtr<char> pluginPath(g_build_filename(WEBKIT_TEST_PLUGIN_DIR, "libTestNetscapePlugin.so", nullptr));
+ char normalizedPath[PATH_MAX];
+ g_assert(realpath(WEBKIT_TEST_PLUGIN_DIR, normalizedPath));
+ GUniquePtr<char> pluginPath(g_build_filename(normalizedPath, "libTestNetscapePlugIn.so", nullptr));
g_assert_cmpstr(webkit_plugin_get_path(testPlugin.get()), ==, pluginPath.get());
g_assert_cmpstr(webkit_plugin_get_description(testPlugin.get()), ==, "Simple Netscape® plug-in that handles test content for WebKit");
GList* mimeInfoList = webkit_plugin_get_mime_info_list(testPlugin.get());
@@ -116,7 +158,10 @@ static const char* kBarHTML = "<html><body>Bar</body></html>";
static const char* kEchoHTMLFormat = "<html><body>%s</body></html>";
static const char* errorDomain = "test";
static const int errorCode = 10;
-static const char* errorMessage = "Error message.";
+
+static const char* genericErrorMessage = "Error message.";
+static const char* beforeReceiveResponseErrorMessage = "Error before didReceiveResponse.";
+static const char* afterInitialChunkErrorMessage = "Error after reading the initial chunk.";
class URISchemeTest: public LoadTrackingTest {
public:
@@ -148,23 +193,38 @@ public:
g_assert(webkit_uri_scheme_request_get_web_view(request) == test->m_webView);
- GRefPtr<GInputStream> inputStream = adoptGRef(g_memory_input_stream_new());
- test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(inputStream.get()));
-
const char* scheme = webkit_uri_scheme_request_get_scheme(request);
g_assert(scheme);
g_assert(test->m_handlersMap.contains(String::fromUTF8(scheme)));
+ const URISchemeHandler& handler = test->m_handlersMap.get(String::fromUTF8(scheme));
+
+ GRefPtr<GInputStream> inputStream = adoptGRef(g_memory_input_stream_new());
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(inputStream.get()));
+
+ const gchar* requestPath = webkit_uri_scheme_request_get_path(request);
+
if (!g_strcmp0(scheme, "error")) {
- GUniquePtr<GError> error(g_error_new_literal(g_quark_from_string(errorDomain), errorCode, errorMessage));
- webkit_uri_scheme_request_finish_error(request, error.get());
+ if (!g_strcmp0(requestPath, "before-response")) {
+ GUniquePtr<GError> error(g_error_new_literal(g_quark_from_string(errorDomain), errorCode, beforeReceiveResponseErrorMessage));
+ // We call finish() and then finish_error() to make sure that not even
+ // the didReceiveResponse message is processed at the time of failing.
+ webkit_uri_scheme_request_finish(request, G_INPUT_STREAM(inputStream.get()), handler.replyLength, handler.mimeType.data());
+ webkit_uri_scheme_request_finish_error(request, error.get());
+ } else if (!g_strcmp0(requestPath, "after-first-chunk")) {
+ g_memory_input_stream_add_data(G_MEMORY_INPUT_STREAM(inputStream.get()), handler.reply.data(), handler.reply.length(), 0);
+ webkit_uri_scheme_request_finish(request, inputStream.get(), handler.replyLength, handler.mimeType.data());
+ // We need to wait until we reach the load-committed state before calling webkit_uri_scheme_request_finish_error(),
+ // so we rely on the test using finishOnCommittedAndWaitUntilLoadFinished() to actually call it from loadCommitted().
+ } else {
+ GUniquePtr<GError> error(g_error_new_literal(g_quark_from_string(errorDomain), errorCode, genericErrorMessage));
+ webkit_uri_scheme_request_finish_error(request, error.get());
+ }
return;
}
- const URISchemeHandler& handler = test->m_handlersMap.get(String::fromUTF8(scheme));
-
if (!g_strcmp0(scheme, "echo")) {
- char* replyHTML = g_strdup_printf(handler.reply.data(), webkit_uri_scheme_request_get_path(request));
+ char* replyHTML = g_strdup_printf(handler.reply.data(), requestPath);
g_memory_input_stream_add_data(G_MEMORY_INPUT_STREAM(inputStream.get()), replyHTML, strlen(replyHTML), g_free);
} else if (!g_strcmp0(scheme, "closed"))
g_input_stream_close(inputStream.get(), 0, 0);
@@ -177,13 +237,58 @@ public:
void registerURISchemeHandler(const char* scheme, const char* reply, int replyLength, const char* mimeType)
{
m_handlersMap.set(String::fromUTF8(scheme), URISchemeHandler(reply, replyLength, mimeType));
- webkit_web_context_register_uri_scheme(webkit_web_context_get_default(), scheme, uriSchemeRequestCallback, this, 0);
+ webkit_web_context_register_uri_scheme(m_webContext.get(), scheme, uriSchemeRequestCallback, this, 0);
+ }
+
+ void loadCommitted() override
+ {
+ if (m_finishOnCommitted) {
+ GUniquePtr<GError> error(g_error_new_literal(g_quark_from_string(errorDomain), errorCode, afterInitialChunkErrorMessage));
+ webkit_uri_scheme_request_finish_error(m_uriSchemeRequest.get(), error.get());
+ }
+
+ LoadTrackingTest::loadCommitted();
+ }
+
+ void finishOnCommittedAndWaitUntilLoadFinished()
+ {
+ m_finishOnCommitted = true;
+ waitUntilLoadFinished();
+ m_finishOnCommitted = false;
}
GRefPtr<WebKitURISchemeRequest> m_uriSchemeRequest;
HashMap<String, URISchemeHandler> m_handlersMap;
+ bool m_finishOnCommitted { false };
};
+String generateHTMLContent(unsigned contentLength)
+{
+ String baseString("abcdefghijklmnopqrstuvwxyz0123457890");
+ unsigned baseLength = baseString.length();
+
+ StringBuilder builder;
+ builder.append("<html><body>");
+
+ if (contentLength <= baseLength)
+ builder.append(baseString, 0, contentLength);
+ else {
+ unsigned currentLength = 0;
+ while (currentLength < contentLength) {
+ if ((currentLength + baseLength) <= contentLength)
+ builder.append(baseString);
+ else
+ builder.append(baseString, 0, contentLength - currentLength);
+
+ // Account for the 12 characters of the '<html><body>' prefix.
+ currentLength = builder.length() - 12;
+ }
+ }
+ builder.append("</body></html>");
+
+ return builder.toString();
+}
+
static void testWebContextURIScheme(URISchemeTest* test, gconstpointer)
{
test->registerURISchemeHandler("foo", kBarHTML, strlen(kBarHTML), "text/html");
@@ -203,6 +308,16 @@ static void testWebContextURIScheme(URISchemeTest* test, gconstpointer)
g_assert_cmpint(mainResourceDataSize, ==, strlen(echoHTML.get()));
g_assert(!strncmp(mainResourceData, echoHTML.get(), mainResourceDataSize));
+ test->loadURI("echo:with#fragment");
+ test->waitUntilLoadFinished();
+ g_assert_cmpstr(webkit_uri_scheme_request_get_path(test->m_uriSchemeRequest.get()), ==, "with");
+ g_assert_cmpstr(webkit_uri_scheme_request_get_uri(test->m_uriSchemeRequest.get()), ==, "echo:with#fragment");
+ echoHTML.reset(g_strdup_printf(kEchoHTMLFormat, webkit_uri_scheme_request_get_path(test->m_uriSchemeRequest.get())));
+ mainResourceDataSize = 0;
+ mainResourceData = test->mainResourceData(mainResourceDataSize);
+ g_assert_cmpint(mainResourceDataSize, ==, strlen(echoHTML.get()));
+ g_assert(!strncmp(mainResourceData, echoHTML.get(), mainResourceDataSize));
+
test->registerURISchemeHandler("nomime", kBarHTML, -1, 0);
test->m_loadEvents.clear();
test->loadURI("nomime:foo-bar");
@@ -216,14 +331,35 @@ static void testWebContextURIScheme(URISchemeTest* test, gconstpointer)
g_assert(!test->m_loadEvents.contains(LoadTrackingTest::ProvisionalLoadFailed));
g_assert(!test->m_loadEvents.contains(LoadTrackingTest::LoadFailed));
- test->registerURISchemeHandler("error", 0, 0, 0);
+ // Anything over 8192 bytes will get multiple calls to g_input_stream_read_async in
+ // WebKitURISchemeRequest when reading data, but we still need way more than that to
+ // ensure that we reach the load-committed state before failing, so we use an 8MB HTML.
+ String longHTMLContent = generateHTMLContent(8 * 1024 * 1024);
+ test->registerURISchemeHandler("error", longHTMLContent.utf8().data(), -1, "text/html");
test->m_loadEvents.clear();
test->loadURI("error:error");
test->waitUntilLoadFinished();
g_assert(test->m_loadEvents.contains(LoadTrackingTest::ProvisionalLoadFailed));
g_assert(test->m_loadFailed);
g_assert_error(test->m_error.get(), g_quark_from_string(errorDomain), errorCode);
- g_assert_cmpstr(test->m_error->message, ==, errorMessage);
+ g_assert_cmpstr(test->m_error->message, ==, genericErrorMessage);
+
+ test->m_loadEvents.clear();
+ test->loadURI("error:before-response");
+ test->waitUntilLoadFinished();
+ g_assert(test->m_loadEvents.contains(LoadTrackingTest::ProvisionalLoadFailed));
+ g_assert(test->m_loadFailed);
+ g_assert_error(test->m_error.get(), g_quark_from_string(errorDomain), errorCode);
+ g_assert_cmpstr(test->m_error->message, ==, beforeReceiveResponseErrorMessage);
+
+ test->m_loadEvents.clear();
+ test->loadURI("error:after-first-chunk");
+ test->finishOnCommittedAndWaitUntilLoadFinished();
+ g_assert(!test->m_loadEvents.contains(LoadTrackingTest::ProvisionalLoadFailed));
+ g_assert(test->m_loadEvents.contains(LoadTrackingTest::LoadFailed));
+ g_assert(test->m_loadFailed);
+ g_assert_error(test->m_error.get(), g_quark_from_string(errorDomain), errorCode);
+ g_assert_cmpstr(test->m_error->message, ==, afterInitialChunkErrorMessage);
test->registerURISchemeHandler("closed", 0, 0, 0);
test->m_loadEvents.clear();
@@ -236,7 +372,7 @@ static void testWebContextURIScheme(URISchemeTest* test, gconstpointer)
static void testWebContextSpellChecker(Test* test, gconstpointer)
{
- WebKitWebContext* webContext = webkit_web_context_get_default();
+ WebKitWebContext* webContext = test->m_webContext.get();
// Check what happens if no spell checking language has been set.
const gchar* const* currentLanguage = webkit_web_context_get_spell_checking_languages(webContext);
@@ -289,7 +425,7 @@ static void testWebContextSpellChecker(Test* test, gconstpointer)
static void testWebContextLanguages(WebViewTest* test, gconstpointer)
{
- static const char* expectedDefaultLanguage = "en";
+ static const char* expectedDefaultLanguage = "en-US";
test->loadURI(kServer->getURIForPath("/").data());
test->waitUntilLoadFinished();
size_t mainResourceDataSize = 0;
@@ -302,7 +438,7 @@ static void testWebContextLanguages(WebViewTest* test, gconstpointer)
g_ptr_array_add(languages.get(), const_cast<gpointer>(static_cast<const void*>("ES_es")));
g_ptr_array_add(languages.get(), const_cast<gpointer>(static_cast<const void*>("dE")));
g_ptr_array_add(languages.get(), 0);
- webkit_web_context_set_preferred_languages(webkit_web_context_get_default(), reinterpret_cast<const char* const*>(languages->pdata));
+ webkit_web_context_set_preferred_languages(test->m_webContext.get(), reinterpret_cast<const char* const*>(languages->pdata));
static const char* expectedLanguages = "en, es-es;q=0.90, de;q=0.80";
test->loadURI(kServer->getURIForPath("/").data());
@@ -311,6 +447,32 @@ static void testWebContextLanguages(WebViewTest* test, gconstpointer)
mainResourceData = test->mainResourceData(mainResourceDataSize);
g_assert_cmpuint(mainResourceDataSize, ==, strlen(expectedLanguages));
g_assert(!strncmp(mainResourceData, expectedLanguages, mainResourceDataSize));
+
+ // When using the C locale, en-US should be used as default.
+ const char* cLanguage[] = { "C", nullptr };
+ webkit_web_context_set_preferred_languages(test->m_webContext.get(), cLanguage);
+ GUniqueOutPtr<GError> error;
+ WebKitJavascriptResult* javascriptResult = test->runJavaScriptAndWaitUntilFinished("Intl.DateTimeFormat().resolvedOptions().locale", &error.outPtr());
+ g_assert(javascriptResult);
+ g_assert(!error);
+ GUniquePtr<char> locale(WebViewTest::javascriptResultToCString(javascriptResult));
+ g_assert_cmpstr(locale.get(), ==, expectedDefaultLanguage);
+
+ // When using the POSIX locale, en-US should be used as default.
+ const char* posixLanguage[] = { "POSIX", nullptr };
+ webkit_web_context_set_preferred_languages(test->m_webContext.get(), posixLanguage);
+ javascriptResult = test->runJavaScriptAndWaitUntilFinished("Intl.DateTimeFormat().resolvedOptions().locale", &error.outPtr());
+ g_assert(javascriptResult);
+ g_assert(!error);
+ locale.reset(WebViewTest::javascriptResultToCString(javascriptResult));
+ g_assert_cmpstr(locale.get(), ==, expectedDefaultLanguage);
+
+ // An invalid locale should throw an exception.
+ const char* invalidLanguage[] = { "A", nullptr };
+ webkit_web_context_set_preferred_languages(test->m_webContext.get(), invalidLanguage);
+ javascriptResult = test->runJavaScriptAndWaitUntilFinished("Intl.DateTimeFormat().resolvedOptions().locale", &error.outPtr());
+ g_assert(!javascriptResult);
+ g_assert_error(error.get(), WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED);
}
static void serverCallback(SoupServer* server, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, gpointer)
@@ -325,6 +487,16 @@ static void serverCallback(SoupServer* server, SoupMessage* message, const char*
soup_message_set_status(message, SOUP_STATUS_OK);
soup_message_body_append(message->response_body, SOUP_MEMORY_COPY, acceptLanguage, strlen(acceptLanguage));
soup_message_body_complete(message->response_body);
+ } else if (g_str_equal(path, "/empty")) {
+ const char* emptyHTML = "<html><body></body></html>";
+ soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, emptyHTML, strlen(emptyHTML));
+ soup_message_body_complete(message->response_body);
+ soup_message_set_status(message, SOUP_STATUS_OK);
+ } else if (g_str_equal(path, "/echoPort")) {
+ char* port = g_strdup_printf("%u", soup_server_get_port(server));
+ soup_message_body_append(message->response_body, SOUP_MEMORY_TAKE, port, strlen(port));
+ soup_message_body_complete(message->response_body);
+ soup_message_set_status(message, SOUP_STATUS_OK);
} else
soup_message_set_status(message, SOUP_STATUS_NOT_FOUND);
}
@@ -343,7 +515,7 @@ public:
};
SecurityPolicyTest()
- : m_manager(webkit_web_context_get_security_manager(webkit_web_context_get_default()))
+ : m_manager(webkit_web_context_get_security_manager(m_webContext.get()))
{
}
@@ -406,17 +578,205 @@ static void testWebContextSecurityPolicy(SecurityPolicyTest* test, gconstpointer
| SecurityPolicyTest::CORSEnabled | SecurityPolicyTest::EmptyDocument);
}
+static void consoleMessageReceivedCallback(WebKitUserContentManager*, WebKitJavascriptResult* message, WebKitJavascriptResult** result)
+{
+ g_assert(result);
+ g_assert(!*result);
+ *result = webkit_javascript_result_ref(message);
+}
+
+static void testWebContextSecurityFileXHR(WebViewTest* test, gconstpointer)
+{
+ GUniquePtr<char> fileURL(g_strdup_printf("file://%s/simple.html", Test::getResourcesDir(Test::WebKit2Resources).data()));
+ test->loadURI(fileURL.get());
+ test->waitUntilLoadFinished();
+
+ GUniquePtr<char> jsonURL(g_strdup_printf("file://%s/simple.json", Test::getResourcesDir().data()));
+ GUniquePtr<char> xhr(g_strdup_printf("var xhr = new XMLHttpRequest; xhr.open(\"GET\", \"%s\"); xhr.send();", jsonURL.get()));
+
+ WebKitJavascriptResult* consoleMessage = nullptr;
+ webkit_user_content_manager_register_script_message_handler(test->m_userContentManager.get(), "console");
+ g_signal_connect(test->m_userContentManager.get(), "script-message-received::console", G_CALLBACK(consoleMessageReceivedCallback), &consoleMessage);
+
+ // By default file access is not allowed, this will show a console message with a cross-origin error.
+ GUniqueOutPtr<GError> error;
+ WebKitJavascriptResult* javascriptResult = test->runJavaScriptAndWaitUntilFinished(xhr.get(), &error.outPtr());
+ g_assert(javascriptResult);
+ g_assert(!error);
+ g_assert(consoleMessage);
+ GUniquePtr<char> messageString(WebViewTest::javascriptResultToCString(consoleMessage));
+ GRefPtr<GVariant> variant = g_variant_parse(G_VARIANT_TYPE("(uusus)"), messageString.get(), nullptr, nullptr, nullptr);
+ g_assert(variant.get());
+ unsigned level;
+ const char* messageText;
+ g_variant_get(variant.get(), "(uu&su&s)", nullptr, &level, &messageText, nullptr, nullptr);
+ g_assert_cmpuint(level, ==, 3); // Console error message.
+ GUniquePtr<char> expectedErrorMessage(g_strdup_printf("XMLHttpRequest cannot load %s. Cross origin requests are only supported for HTTP.", jsonURL.get()));
+ g_assert_cmpstr(messageText, ==, expectedErrorMessage.get());
+ webkit_javascript_result_unref(consoleMessage);
+ consoleMessage = nullptr;
+ level = 0;
+ messageText = nullptr;
+ variant = nullptr;
+
+ // Allow file access from file URLs.
+ webkit_settings_set_allow_file_access_from_file_urls(webkit_web_view_get_settings(test->m_webView), TRUE);
+ test->loadURI(fileURL.get());
+ test->waitUntilLoadFinished();
+ javascriptResult = test->runJavaScriptAndWaitUntilFinished(xhr.get(), &error.outPtr());
+ g_assert(javascriptResult);
+ g_assert(!error);
+
+ // It isn't still possible to load file from an HTTP URL.
+ test->loadURI(kServer->getURIForPath("/").data());
+ test->waitUntilLoadFinished();
+ javascriptResult = test->runJavaScriptAndWaitUntilFinished(xhr.get(), &error.outPtr());
+ g_assert(javascriptResult);
+ g_assert(!error);
+ g_assert(consoleMessage);
+ variant = g_variant_parse(G_VARIANT_TYPE("(uusus)"), messageString.get(), nullptr, nullptr, nullptr);
+ g_assert(variant.get());
+ g_variant_get(variant.get(), "(uu&su&s)", nullptr, &level, &messageText, nullptr, nullptr);
+ g_assert_cmpuint(level, ==, 3); // Console error message.
+ g_assert_cmpstr(messageText, ==, expectedErrorMessage.get());
+ webkit_javascript_result_unref(consoleMessage);
+
+ g_signal_handlers_disconnect_matched(test->m_userContentManager.get(), G_SIGNAL_MATCH_DATA, 0, 0, nullptr, nullptr, &consoleMessage);
+ webkit_user_content_manager_unregister_script_message_handler(test->m_userContentManager.get(), "console");
+
+ webkit_settings_set_allow_file_access_from_file_urls(webkit_web_view_get_settings(test->m_webView), FALSE);
+}
+
+class ProxyTest : public WebViewTest {
+public:
+ MAKE_GLIB_TEST_FIXTURE(ProxyTest);
+
+ ProxyTest()
+ {
+ // This "proxy server" is actually just a different instance of the main
+ // test server (kServer), listening on a different port. Requests
+ // will not actually be proxied to kServer because proxyServer is not
+ // actually a proxy server. We're testing whether the proxy settings
+ // work, not whether we can write a soup proxy server.
+ m_proxyServer.run(serverCallback);
+ g_assert(m_proxyServer.baseURI());
+ }
+
+ CString loadURIAndGetMainResourceData(const char* uri)
+ {
+ loadURI(uri);
+ waitUntilLoadFinished();
+ size_t dataSize = 0;
+ const char* data = mainResourceData(dataSize);
+ return CString(data, dataSize);
+ }
+
+ GUniquePtr<char> proxyServerPortAsString()
+ {
+ GUniquePtr<char> port(g_strdup_printf("%u", soup_uri_get_port(m_proxyServer.baseURI())));
+ return port;
+ }
+
+ WebKitTestServer m_proxyServer;
+};
+
+static void ephemeralViewloadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent, WebViewTest* test)
+{
+ if (loadEvent != WEBKIT_LOAD_FINISHED)
+ return;
+ g_signal_handlers_disconnect_by_func(webView, reinterpret_cast<void*>(ephemeralViewloadChanged), test);
+ test->quitMainLoop();
+}
+
+static void testWebContextProxySettings(ProxyTest* test, gconstpointer)
+{
+ // Proxy URI is unset by default. Requests to kServer should be received by kServer.
+ GUniquePtr<char> serverPortAsString(g_strdup_printf("%u", soup_uri_get_port(kServer->baseURI())));
+ auto mainResourceData = test->loadURIAndGetMainResourceData(kServer->getURIForPath("/echoPort").data());
+ ASSERT_CMP_CSTRING(mainResourceData, ==, serverPortAsString.get());
+
+ // Set default proxy URI to point to proxyServer. Requests to kServer should be received by proxyServer instead.
+ GUniquePtr<char> proxyURI(soup_uri_to_string(test->m_proxyServer.baseURI(), FALSE));
+ WebKitNetworkProxySettings* settings = webkit_network_proxy_settings_new(proxyURI.get(), nullptr);
+ webkit_web_context_set_network_proxy_settings(test->m_webContext.get(), WEBKIT_NETWORK_PROXY_MODE_CUSTOM, settings);
+ GUniquePtr<char> proxyServerPortAsString = test->proxyServerPortAsString();
+ mainResourceData = test->loadURIAndGetMainResourceData(kServer->getURIForPath("/echoPort").data());
+ ASSERT_CMP_CSTRING(mainResourceData, ==, proxyServerPortAsString.get());
+ webkit_network_proxy_settings_free(settings);
+
+ // Proxy settings also affect ephemeral web views.
+ GRefPtr<WebKitWebView> webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW,
+ "web-context", test->m_webContext.get(),
+ "is-ephemeral", TRUE,
+ nullptr));
+ g_assert(webkit_web_view_is_ephemeral(webView.get()));
+ g_assert(!webkit_web_context_is_ephemeral(webkit_web_view_get_context(webView.get())));
+
+ g_signal_connect(webView.get(), "load-changed", G_CALLBACK(ephemeralViewloadChanged), test);
+ webkit_web_view_load_uri(webView.get(), kServer->getURIForPath("/echoPort").data());
+ g_main_loop_run(test->m_mainLoop);
+ WebKitWebResource* resource = webkit_web_view_get_main_resource(webView.get());
+ g_assert(WEBKIT_IS_WEB_RESOURCE(resource));
+ webkit_web_resource_get_data(resource, nullptr, [](GObject* object, GAsyncResult* result, gpointer userData) {
+ size_t dataSize;
+ GUniquePtr<char> data(reinterpret_cast<char*>(webkit_web_resource_get_data_finish(WEBKIT_WEB_RESOURCE(object), result, &dataSize, nullptr)));
+ g_assert(data);
+ auto* test = static_cast<ProxyTest*>(userData);
+ GUniquePtr<char> proxyServerPortAsString = test->proxyServerPortAsString();
+ ASSERT_CMP_CSTRING(CString(data.get(), dataSize), ==, proxyServerPortAsString.get());
+ test->quitMainLoop();
+ }, test);
+ g_main_loop_run(test->m_mainLoop);
+
+ // Remove the proxy. Requests to kServer should be received by kServer again.
+ webkit_web_context_set_network_proxy_settings(test->m_webContext.get(), WEBKIT_NETWORK_PROXY_MODE_NO_PROXY, nullptr);
+ mainResourceData = test->loadURIAndGetMainResourceData(kServer->getURIForPath("/echoPort").data());
+ ASSERT_CMP_CSTRING(mainResourceData, ==, serverPortAsString.get());
+
+ // Use a default proxy uri, but ignoring requests to localhost.
+ static const char* ignoreHosts[] = { "localhost", nullptr };
+ settings = webkit_network_proxy_settings_new(proxyURI.get(), ignoreHosts);
+ webkit_web_context_set_network_proxy_settings(test->m_webContext.get(), WEBKIT_NETWORK_PROXY_MODE_CUSTOM, settings);
+ mainResourceData = test->loadURIAndGetMainResourceData(kServer->getURIForPath("/echoPort").data());
+ ASSERT_CMP_CSTRING(mainResourceData, ==, proxyServerPortAsString.get());
+ GUniquePtr<char> localhostEchoPortURI(g_strdup_printf("http://localhost:%s/echoPort", serverPortAsString.get()));
+ mainResourceData = test->loadURIAndGetMainResourceData(localhostEchoPortURI.get());
+ ASSERT_CMP_CSTRING(mainResourceData, ==, serverPortAsString.get());
+ webkit_network_proxy_settings_free(settings);
+
+ // Remove the proxy again to ensure next test is not using any previous values.
+ webkit_web_context_set_network_proxy_settings(test->m_webContext.get(), WEBKIT_NETWORK_PROXY_MODE_NO_PROXY, nullptr);
+ mainResourceData = test->loadURIAndGetMainResourceData(kServer->getURIForPath("/echoPort").data());
+ ASSERT_CMP_CSTRING(mainResourceData, ==, serverPortAsString.get());
+
+ // Use scheme specific proxy instead of the default.
+ settings = webkit_network_proxy_settings_new(nullptr, nullptr);
+ webkit_network_proxy_settings_add_proxy_for_scheme(settings, "http", proxyURI.get());
+ webkit_web_context_set_network_proxy_settings(test->m_webContext.get(), WEBKIT_NETWORK_PROXY_MODE_CUSTOM, settings);
+ mainResourceData = test->loadURIAndGetMainResourceData(kServer->getURIForPath("/echoPort").data());
+ ASSERT_CMP_CSTRING(mainResourceData, ==, proxyServerPortAsString.get());
+ webkit_network_proxy_settings_free(settings);
+
+ // Reset to use the default resolver.
+ webkit_web_context_set_network_proxy_settings(test->m_webContext.get(), WEBKIT_NETWORK_PROXY_MODE_DEFAULT, nullptr);
+ mainResourceData = test->loadURIAndGetMainResourceData(kServer->getURIForPath("/echoPort").data());
+ ASSERT_CMP_CSTRING(mainResourceData, ==, serverPortAsString.get());
+}
+
void beforeAll()
{
kServer = new WebKitTestServer();
kServer->run(serverCallback);
Test::add("WebKitWebContext", "default-context", testWebContextDefault);
+ Test::add("WebKitWebContext", "ephemeral", testWebContextEphemeral);
PluginsTest::add("WebKitWebContext", "get-plugins", testWebContextGetPlugins);
URISchemeTest::add("WebKitWebContext", "uri-scheme", testWebContextURIScheme);
Test::add("WebKitWebContext", "spell-checker", testWebContextSpellChecker);
WebViewTest::add("WebKitWebContext", "languages", testWebContextLanguages);
SecurityPolicyTest::add("WebKitSecurityManager", "security-policy", testWebContextSecurityPolicy);
+ WebViewTest::add("WebKitSecurityManager", "file-xhr", testWebContextSecurityFileXHR);
+ ProxyTest::add("WebKitWebContext", "proxy", testWebContextProxySettings);
}
void afterAll()
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitWebView.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitWebView.cpp
index 334f8dafe..4e3d1d7e7 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitWebView.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitWebView.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2011 Igalia S.L.
+ * Copyright (C) 2014 Collabora Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -18,38 +19,153 @@
*/
#include "config.h"
+#include "WebKitTestServer.h"
#include "WebViewTest.h"
#include <JavaScriptCore/JSStringRef.h>
#include <JavaScriptCore/JSValueRef.h>
#include <glib/gstdio.h>
-#include <wtf/gobject/GRefPtr.h>
+#include <wtf/glib/GRefPtr.h>
-static void testWebViewDefaultContext(WebViewTest* test, gconstpointer)
+class IsPlayingAudioWebViewTest : public WebViewTest {
+public:
+ MAKE_GLIB_TEST_FIXTURE(IsPlayingAudioWebViewTest);
+
+ static void isPlayingAudioChanged(GObject*, GParamSpec*, IsPlayingAudioWebViewTest* test)
+ {
+ g_signal_handlers_disconnect_by_func(test->m_webView, reinterpret_cast<void*>(isPlayingAudioChanged), test);
+ g_main_loop_quit(test->m_mainLoop);
+ }
+
+ void waitUntilIsPlayingAudioChanged()
+ {
+ g_signal_connect(m_webView, "notify::is-playing-audio", G_CALLBACK(isPlayingAudioChanged), this);
+ g_main_loop_run(m_mainLoop);
+ }
+};
+
+static WebKitTestServer* gServer;
+
+static void testWebViewWebContext(WebViewTest* test, gconstpointer)
{
- g_assert(webkit_web_view_get_context(test->m_webView) == webkit_web_context_get_default());
+ g_assert(webkit_web_view_get_context(test->m_webView) == test->m_webContext.get());
+ g_assert(webkit_web_context_get_default() != test->m_webContext.get());
// Check that a web view created with g_object_new has the default context.
- GRefPtr<WebKitWebView> webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, NULL));
+ GRefPtr<WebKitWebView> webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, nullptr));
g_assert(webkit_web_view_get_context(webView.get()) == webkit_web_context_get_default());
+
+ // Check that a web view created with a related view has the related view context.
+ webView = WEBKIT_WEB_VIEW(webkit_web_view_new_with_related_view(test->m_webView));
+ g_assert(webkit_web_view_get_context(webView.get()) == test->m_webContext.get());
+
+ // Check that a web context given as construct parameter is ignored if a related view is also provided.
+ webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW,
+ "web-context", webkit_web_context_get_default(), "related-view", test->m_webView, nullptr));
+ g_assert(webkit_web_view_get_context(webView.get()) == test->m_webContext.get());
+}
+
+static void testWebViewWebContextLifetime(WebViewTest* test, gconstpointer)
+{
+ WebKitWebContext* webContext = webkit_web_context_new();
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webContext));
+
+ GtkWidget* webView = webkit_web_view_new_with_context(webContext);
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webView));
+
+ g_object_ref_sink(webView);
+ g_object_unref(webContext);
+
+ // Check that the web view still has a valid context.
+ WebKitWebContext* tmpContext = webkit_web_view_get_context(WEBKIT_WEB_VIEW(webView));
+ g_assert_true(WEBKIT_IS_WEB_CONTEXT(tmpContext));
+ g_object_unref(webView);
+
+ WebKitWebContext* webContext2 = webkit_web_context_new();
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webContext2));
+
+ GtkWidget* webView2 = webkit_web_view_new_with_context(webContext2);
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webView2));
+
+ g_object_ref_sink(webView2);
+ g_object_unref(webView2);
+
+ // Check that the context is still valid.
+ g_assert_true(WEBKIT_IS_WEB_CONTEXT(webContext2));
+ g_object_unref(webContext2);
+}
+
+static void ephemeralViewloadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent, WebViewTest* test)
+{
+ if (loadEvent != WEBKIT_LOAD_FINISHED)
+ return;
+ g_signal_handlers_disconnect_by_func(webView, reinterpret_cast<void*>(ephemeralViewloadChanged), test);
+ test->quitMainLoop();
+}
+
+static void testWebViewEphemeral(WebViewTest* test, gconstpointer)
+{
+ g_assert(!webkit_web_view_is_ephemeral(test->m_webView));
+ g_assert(!webkit_web_context_is_ephemeral(webkit_web_view_get_context(test->m_webView)));
+ auto* manager = webkit_web_context_get_website_data_manager(test->m_webContext.get());
+ g_assert(!webkit_website_data_manager_is_ephemeral(manager));
+ g_assert(webkit_web_view_get_website_data_manager(test->m_webView) == manager);
+ webkit_website_data_manager_clear(manager, WEBKIT_WEBSITE_DATA_DISK_CACHE, 0, nullptr, [](GObject* manager, GAsyncResult* result, gpointer userData) {
+ webkit_website_data_manager_clear_finish(WEBKIT_WEBSITE_DATA_MANAGER(manager), result, nullptr);
+ static_cast<WebViewTest*>(userData)->quitMainLoop();
+ }, test);
+ g_main_loop_run(test->m_mainLoop);
+
+ // A WebView on a non ephemeral context can be ephemeral.
+ GRefPtr<WebKitWebView> webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW,
+ "web-context", webkit_web_view_get_context(test->m_webView),
+ "is-ephemeral", TRUE,
+ nullptr));
+ g_assert(webkit_web_view_is_ephemeral(webView.get()));
+ g_assert(!webkit_web_context_is_ephemeral(webkit_web_view_get_context(webView.get())));
+ g_assert(webkit_web_view_get_website_data_manager(webView.get()) != manager);
+
+ g_signal_connect(webView.get(), "load-changed", G_CALLBACK(ephemeralViewloadChanged), test);
+ webkit_web_view_load_uri(webView.get(), gServer->getURIForPath("/").data());
+ g_main_loop_run(test->m_mainLoop);
+
+ // Disk cache delays the storing of initial resources for 1 second to avoid
+ // affecting early page load. So, wait 1 second here to make sure resources
+ // have already been stored.
+ test->wait(1);
+
+ webkit_website_data_manager_fetch(manager, WEBKIT_WEBSITE_DATA_DISK_CACHE, nullptr, [](GObject* manager, GAsyncResult* result, gpointer userData) {
+ auto* test = static_cast<WebViewTest*>(userData);
+ g_assert(!webkit_website_data_manager_fetch_finish(WEBKIT_WEBSITE_DATA_MANAGER(manager), result, nullptr));
+ test->quitMainLoop();
+ }, test);
+ g_main_loop_run(test->m_mainLoop);
}
static void testWebViewCustomCharset(WebViewTest* test, gconstpointer)
{
+ test->loadURI(gServer->getURIForPath("/").data());
+ test->waitUntilLoadFinished();
g_assert(!webkit_web_view_get_custom_charset(test->m_webView));
webkit_web_view_set_custom_charset(test->m_webView, "utf8");
+ // Changing the charset reloads the page, so wait until reloaded.
+ test->waitUntilLoadFinished();
g_assert_cmpstr(webkit_web_view_get_custom_charset(test->m_webView), ==, "utf8");
- // Go back to the default charset.
- webkit_web_view_set_custom_charset(test->m_webView, 0);
+
+ // Go back to the default charset and wait until reloaded.
+ webkit_web_view_set_custom_charset(test->m_webView, nullptr);
+ test->waitUntilLoadFinished();
g_assert(!webkit_web_view_get_custom_charset(test->m_webView));
}
static void testWebViewSettings(WebViewTest* test, gconstpointer)
{
WebKitSettings* defaultSettings = webkit_web_view_get_settings(test->m_webView);
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(defaultSettings));
g_assert(defaultSettings);
g_assert(webkit_settings_get_enable_javascript(defaultSettings));
GRefPtr<WebKitSettings> newSettings = adoptGRef(webkit_settings_new());
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(newSettings.get()));
g_object_set(G_OBJECT(newSettings.get()), "enable-javascript", FALSE, NULL);
webkit_web_view_set_settings(test->m_webView, newSettings.get());
@@ -63,10 +179,15 @@ static void testWebViewSettings(WebViewTest* test, gconstpointer)
g_assert(webkit_web_view_get_settings(WEBKIT_WEB_VIEW(webView2.get())) == settings);
GRefPtr<WebKitSettings> newSettings2 = adoptGRef(webkit_settings_new());
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(newSettings2.get()));
webkit_web_view_set_settings(WEBKIT_WEB_VIEW(webView2.get()), newSettings2.get());
settings = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(webView2.get()));
g_assert(settings == newSettings2.get());
g_assert(webkit_settings_get_enable_javascript(settings));
+
+ GRefPtr<GtkWidget> webView3 = webkit_web_view_new_with_settings(newSettings2.get());
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webView3.get()));
+ g_assert(webkit_web_view_get_settings(WEBKIT_WEB_VIEW(webView3.get())) == newSettings2.get());
}
static void testWebViewZoomLevel(WebViewTest* test, gconstpointer)
@@ -407,7 +528,7 @@ static void testWebViewSave(SaveWebViewTest* test, gconstpointer)
gchar buffer[512] = { 0 };
gssize readBytes = 0;
gssize totalBytesFromStream = 0;
- while (readBytes = g_input_stream_read(test->m_inputStream.get(), &buffer, 512, 0, &error.outPtr())) {
+ while ((readBytes = g_input_stream_read(test->m_inputStream.get(), &buffer, 512, 0, &error.outPtr()))) {
g_assert(!error);
totalBytesFromStream += readBytes;
}
@@ -417,28 +538,7 @@ static void testWebViewSave(SaveWebViewTest* test, gconstpointer)
g_assert_cmpint(g_file_info_get_size(fileInfo.get()), ==, totalBytesFromStream);
}
-static void testWebViewMode(WebViewTest* test, gconstpointer)
-{
- static const char* indexHTML = "<html><body><p>Test Web View Mode</p></body></html>";
-
- // Web mode.
- g_assert_cmpuint(webkit_web_view_get_view_mode(test->m_webView), ==, WEBKIT_VIEW_MODE_WEB);
- test->loadHtml(indexHTML, 0);
- test->waitUntilLoadFinished();
- WebKitJavascriptResult* javascriptResult = test->runJavaScriptAndWaitUntilFinished("window.document.body.textContent;", 0);
- GUniquePtr<char> valueString(WebViewTest::javascriptResultToCString(javascriptResult));
- g_assert_cmpstr(valueString.get(), ==, "Test Web View Mode");
-
- // Source mode.
- webkit_web_view_set_view_mode(test->m_webView, WEBKIT_VIEW_MODE_SOURCE);
- test->loadHtml(indexHTML, 0);
- test->waitUntilLoadFinished();
- javascriptResult = test->runJavaScriptAndWaitUntilFinished("window.document.body.textContent;", 0);
- valueString.reset(WebViewTest::javascriptResultToCString(javascriptResult));
- g_assert_cmpstr(valueString.get(), ==, indexHTML);
-}
-
-// To test page visibility API. Currently only 'visible' and 'hidden' states are implemented fully in WebCore.
+// To test page visibility API. Currently only 'visible', 'hidden' and 'prerender' states are implemented fully in WebCore.
// See also http://www.w3.org/TR/2011/WD-page-visibility-20110602/ and https://developers.google.com/chrome/whitepapers/pagevisibility
static void testWebViewPageVisibility(WebViewTest* test, gconstpointer)
{
@@ -453,7 +553,7 @@ static void testWebViewPageVisibility(WebViewTest* test, gconstpointer)
"</body></html>",
0);
- // Wait untill the page is loaded. Initial visibility should be 'hidden'.
+ // Wait until the page is loaded. Initial visibility should be 'prerender'.
test->waitUntilLoadFinished();
GUniqueOutPtr<GError> error;
@@ -461,7 +561,7 @@ static void testWebViewPageVisibility(WebViewTest* test, gconstpointer)
g_assert(javascriptResult);
g_assert(!error.get());
GUniquePtr<char> valueString(WebViewTest::javascriptResultToCString(javascriptResult));
- g_assert_cmpstr(valueString.get(), ==, "hidden");
+ g_assert_cmpstr(valueString.get(), ==, "prerender");
javascriptResult = test->runJavaScriptAndWaitUntilFinished("document.hidden;", &error.outPtr());
g_assert(javascriptResult);
@@ -564,15 +664,404 @@ static void testWebViewSnapshot(SnapshotWebViewTest* test, gconstpointer)
g_assert_cmpint(cairo_image_surface_get_width(surface1), ==, cairo_image_surface_get_width(surface2));
g_assert_cmpint(cairo_image_surface_get_height(surface1), ==, cairo_image_surface_get_height(surface2));
g_assert(!Test::cairoSurfacesEqual(surface1, surface2));
+
+ // Get a snpashot with a transparent background, the result must be different.
+ surface2 = test->getSnapshotAndWaitUntilReady(WEBKIT_SNAPSHOT_REGION_VISIBLE, WEBKIT_SNAPSHOT_OPTIONS_TRANSPARENT_BACKGROUND);
+ g_assert_cmpuint(cairo_surface_get_type(surface2), ==, CAIRO_SURFACE_TYPE_IMAGE);
+ g_assert_cmpint(cairo_image_surface_get_width(surface1), ==, cairo_image_surface_get_width(surface2));
+ g_assert_cmpint(cairo_image_surface_get_height(surface1), ==, cairo_image_surface_get_height(surface2));
+ g_assert(!Test::cairoSurfacesEqual(surface1, surface2));
cairo_surface_destroy(surface1);
// Test that cancellation works.
g_assert(test->getSnapshotAndCancel());
}
+class NotificationWebViewTest: public WebViewTest {
+public:
+ MAKE_GLIB_TEST_FIXTURE_WITH_SETUP_TEARDOWN(NotificationWebViewTest, setup, teardown);
+
+ static void setup()
+ {
+ WebViewTest::shouldInitializeWebViewInConstructor = false;
+ }
+
+ static void teardown()
+ {
+ WebViewTest::shouldInitializeWebViewInConstructor = true;
+ }
+
+ enum NotificationEvent {
+ None,
+ Permission,
+ Shown,
+ Clicked,
+ OnClicked,
+ Closed,
+ OnClosed,
+ };
+
+ static gboolean permissionRequestCallback(WebKitWebView*, WebKitPermissionRequest *request, NotificationWebViewTest* test)
+ {
+ g_assert(WEBKIT_IS_NOTIFICATION_PERMISSION_REQUEST(request));
+ g_assert(test->m_isExpectingPermissionRequest);
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(request));
+
+ test->m_event = Permission;
+
+ webkit_permission_request_allow(request);
+
+ g_main_loop_quit(test->m_mainLoop);
+
+ return TRUE;
+ }
+
+ static gboolean notificationClosedCallback(WebKitNotification* notification, NotificationWebViewTest* test)
+ {
+ g_assert(test->m_notification == notification);
+ test->m_notification = nullptr;
+ test->m_event = Closed;
+ if (g_main_loop_is_running(test->m_mainLoop))
+ g_main_loop_quit(test->m_mainLoop);
+ return TRUE;
+ }
+
+ static gboolean notificationClickedCallback(WebKitNotification* notification, NotificationWebViewTest* test)
+ {
+ g_assert(test->m_notification == notification);
+ test->m_event = Clicked;
+ return TRUE;
+ }
+
+ static gboolean showNotificationCallback(WebKitWebView*, WebKitNotification* notification, NotificationWebViewTest* test)
+ {
+ g_assert(!test->m_notification);
+ test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(notification));
+ test->m_notification = notification;
+ g_signal_connect(notification, "closed", G_CALLBACK(notificationClosedCallback), test);
+ g_signal_connect(notification, "clicked", G_CALLBACK(notificationClickedCallback), test);
+ test->m_event = Shown;
+ g_main_loop_quit(test->m_mainLoop);
+ return TRUE;
+ }
+
+ static void notificationsMessageReceivedCallback(WebKitUserContentManager* userContentManager, WebKitJavascriptResult* javascriptResult, NotificationWebViewTest* test)
+ {
+ GUniquePtr<char> valueString(WebViewTest::javascriptResultToCString(javascriptResult));
+
+ if (g_str_equal(valueString.get(), "clicked"))
+ test->m_event = OnClicked;
+ else if (g_str_equal(valueString.get(), "closed"))
+ test->m_event = OnClosed;
+
+ g_main_loop_quit(test->m_mainLoop);
+ }
+
+ void initialize()
+ {
+ initializeWebView();
+ g_signal_connect(m_webView, "permission-request", G_CALLBACK(permissionRequestCallback), this);
+ g_signal_connect(m_webView, "show-notification", G_CALLBACK(showNotificationCallback), this);
+ webkit_user_content_manager_register_script_message_handler(m_userContentManager.get(), "notifications");
+ g_signal_connect(m_userContentManager.get(), "script-message-received::notifications", G_CALLBACK(notificationsMessageReceivedCallback), this);
+ }
+
+ ~NotificationWebViewTest()
+ {
+ g_signal_handlers_disconnect_matched(m_webView, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
+ g_signal_handlers_disconnect_matched(m_userContentManager.get(), G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
+ webkit_user_content_manager_unregister_script_message_handler(m_userContentManager.get(), "notifications");
+ }
+
+ bool hasPermission()
+ {
+ auto* result = runJavaScriptAndWaitUntilFinished("Notification.permission;", nullptr);
+ g_assert(result);
+ GUniquePtr<char> value(javascriptResultToCString(result));
+ return !g_strcmp0(value.get(), "granted");
+ }
+
+ void requestPermissionAndWaitUntilGiven()
+ {
+ m_event = None;
+ m_isExpectingPermissionRequest = true;
+ webkit_web_view_run_javascript(m_webView, "Notification.requestPermission();", nullptr, nullptr, nullptr);
+ g_main_loop_run(m_mainLoop);
+ }
+
+ void requestNotificationAndWaitUntilShown(const char* title, const char* body)
+ {
+ m_event = None;
+
+ GUniquePtr<char> jscode(g_strdup_printf("n = new Notification('%s', { body: '%s'});", title, body));
+ webkit_web_view_run_javascript(m_webView, jscode.get(), nullptr, nullptr, nullptr);
+
+ g_main_loop_run(m_mainLoop);
+ }
+
+ void requestNotificationAndWaitUntilShown(const char* title, const char* body, const char* tag)
+ {
+ m_event = None;
+
+ GUniquePtr<char> jscode(g_strdup_printf("n = new Notification('%s', { body: '%s', tag: '%s'});", title, body, tag));
+ webkit_web_view_run_javascript(m_webView, jscode.get(), nullptr, nullptr, nullptr);
+
+ g_main_loop_run(m_mainLoop);
+ }
+
+ void clickNotificationAndWaitUntilClicked()
+ {
+ m_event = None;
+ runJavaScriptAndWaitUntilFinished("n.onclick = function() { window.webkit.messageHandlers.notifications.postMessage('clicked'); }", nullptr);
+ webkit_notification_clicked(m_notification);
+ g_assert(m_event == Clicked);
+ g_main_loop_run(m_mainLoop);
+ }
+
+ void closeNotificationAndWaitUntilClosed()
+ {
+ m_event = None;
+ webkit_web_view_run_javascript(m_webView, "n.close()", nullptr, nullptr, nullptr);
+ g_main_loop_run(m_mainLoop);
+ }
+
+ void closeNotificationAndWaitUntilOnClosed()
+ {
+ g_assert(m_notification);
+ m_event = None;
+ runJavaScriptAndWaitUntilFinished("n.onclose = function() { window.webkit.messageHandlers.notifications.postMessage('closed'); }", nullptr);
+ webkit_notification_close(m_notification);
+ g_assert(m_event == Closed);
+ g_main_loop_run(m_mainLoop);
+ }
+
+ NotificationEvent m_event { None };
+ WebKitNotification* m_notification { nullptr };
+ bool m_isExpectingPermissionRequest { false };
+ bool m_hasPermission { false };
+};
+
+static void testWebViewNotification(NotificationWebViewTest* test, gconstpointer)
+{
+ test->initialize();
+
+ // Notifications don't work with local or special schemes.
+ test->loadURI(gServer->getURIForPath("/").data());
+ test->waitUntilLoadFinished();
+ g_assert(!test->hasPermission());
+
+ test->requestPermissionAndWaitUntilGiven();
+ g_assert(test->m_event == NotificationWebViewTest::Permission);
+ g_assert(test->hasPermission());
+
+ static const char* title = "This is a notification";
+ static const char* body = "This is the body.";
+ static const char* tag = "This is the tag.";
+ test->requestNotificationAndWaitUntilShown(title, body, tag);
+
+ g_assert(test->m_event == NotificationWebViewTest::Shown);
+ g_assert(test->m_notification);
+ g_assert_cmpstr(webkit_notification_get_title(test->m_notification), ==, title);
+ g_assert_cmpstr(webkit_notification_get_body(test->m_notification), ==, body);
+ g_assert_cmpstr(webkit_notification_get_tag(test->m_notification), ==, tag);
+
+ test->clickNotificationAndWaitUntilClicked();
+ g_assert(test->m_event == NotificationWebViewTest::OnClicked);
+
+ test->closeNotificationAndWaitUntilClosed();
+ g_assert(test->m_event == NotificationWebViewTest::Closed);
+
+ test->requestNotificationAndWaitUntilShown(title, body);
+ g_assert(test->m_event == NotificationWebViewTest::Shown);
+ g_assert_cmpstr(webkit_notification_get_tag(test->m_notification), ==, nullptr);
+
+ test->closeNotificationAndWaitUntilOnClosed();
+ g_assert(test->m_event == NotificationWebViewTest::OnClosed);
+
+ // The first notification should be closed automatically because the tag is
+ // the same. It will crash in showNotificationCallback on failure.
+ test->requestNotificationAndWaitUntilShown(title, body, tag);
+ test->requestNotificationAndWaitUntilShown(title, body, tag);
+ g_assert(test->m_event == NotificationWebViewTest::Shown);
+
+ // Notification should be closed when navigating to a different webpage.
+ test->loadURI(gServer->getURIForPath("/").data());
+ test->waitUntilLoadFinished();
+ g_assert(test->m_event == NotificationWebViewTest::Closed);
+}
+
+static void setInitialNotificationPermissionsAllowedCallback(WebKitWebContext* context, NotificationWebViewTest* test)
+{
+ GUniquePtr<char> baseURI(soup_uri_to_string(gServer->baseURI(), FALSE));
+ GList* allowedOrigins = g_list_prepend(nullptr, webkit_security_origin_new_for_uri(baseURI.get()));
+ webkit_web_context_initialize_notification_permissions(test->m_webContext.get(), allowedOrigins, nullptr);
+ g_list_free_full(allowedOrigins, reinterpret_cast<GDestroyNotify>(webkit_security_origin_unref));
+}
+
+static void setInitialNotificationPermissionsDisallowedCallback(WebKitWebContext* context, NotificationWebViewTest* test)
+{
+ GUniquePtr<char> baseURI(soup_uri_to_string(gServer->baseURI(), FALSE));
+ GList* disallowedOrigins = g_list_prepend(nullptr, webkit_security_origin_new_for_uri(baseURI.get()));
+ webkit_web_context_initialize_notification_permissions(test->m_webContext.get(), nullptr, disallowedOrigins);
+ g_list_free_full(disallowedOrigins, reinterpret_cast<GDestroyNotify>(webkit_security_origin_unref));
+}
+
+static void testWebViewNotificationInitialPermissionAllowed(NotificationWebViewTest* test, gconstpointer)
+{
+ g_signal_connect(test->m_webContext.get(), "initialize-notification-permissions", G_CALLBACK(setInitialNotificationPermissionsAllowedCallback), test);
+ test->initialize();
+
+ test->loadURI(gServer->getURIForPath("/").data());
+ test->waitUntilLoadFinished();
+ g_assert(test->hasPermission());
+
+ test->requestNotificationAndWaitUntilShown("This is a notification", "This is the body.");
+ g_assert(test->m_event == NotificationWebViewTest::Shown);
+}
+
+static void testWebViewNotificationInitialPermissionDisallowed(NotificationWebViewTest* test, gconstpointer)
+{
+ g_signal_connect(test->m_webContext.get(), "initialize-notification-permissions", G_CALLBACK(setInitialNotificationPermissionsDisallowedCallback), test);
+ test->initialize();
+
+ test->loadURI(gServer->getURIForPath("/").data());
+ test->waitUntilLoadFinished();
+ g_assert(!test->hasPermission());
+}
+
+static void testWebViewIsPlayingAudio(IsPlayingAudioWebViewTest* test, gconstpointer)
+{
+ // The web view must be realized for the video to start playback and
+ // trigger changes in WebKitWebView::is-playing-audio.
+ test->showInWindowAndWaitUntilMapped(GTK_WINDOW_TOPLEVEL);
+
+ // Initially, web views should always report no audio being played.
+ g_assert(!webkit_web_view_is_playing_audio(test->m_webView));
+
+ GUniquePtr<char> resourcePath(g_build_filename(Test::getResourcesDir(Test::WebKit2Resources).data(), "file-with-video.html", nullptr));
+ GUniquePtr<char> resourceURL(g_filename_to_uri(resourcePath.get(), nullptr, nullptr));
+ webkit_web_view_load_uri(test->m_webView, resourceURL.get());
+ test->waitUntilLoadFinished();
+ g_assert(!webkit_web_view_is_playing_audio(test->m_webView));
+
+ test->runJavaScriptAndWaitUntilFinished("playVideo();", nullptr);
+ if (!webkit_web_view_is_playing_audio(test->m_webView))
+ test->waitUntilIsPlayingAudioChanged();
+ g_assert(webkit_web_view_is_playing_audio(test->m_webView));
+
+ // Pause the video, and check again.
+ test->runJavaScriptAndWaitUntilFinished("document.getElementById('test-video').pause();", nullptr);
+ if (webkit_web_view_is_playing_audio(test->m_webView))
+ test->waitUntilIsPlayingAudioChanged();
+ g_assert(!webkit_web_view_is_playing_audio(test->m_webView));
+}
+
+static void testWebViewBackgroundColor(WebViewTest* test, gconstpointer)
+{
+ // White is the default background.
+ GdkRGBA rgba;
+ webkit_web_view_get_background_color(test->m_webView, &rgba);
+ g_assert_cmpfloat(rgba.red, ==, 1);
+ g_assert_cmpfloat(rgba.green, ==, 1);
+ g_assert_cmpfloat(rgba.blue, ==, 1);
+ g_assert_cmpfloat(rgba.alpha, ==, 1);
+
+ // Set a different (semi-transparent red).
+ rgba.red = 1;
+ rgba.green = 0;
+ rgba.blue = 0;
+ rgba.alpha = 0.5;
+ webkit_web_view_set_background_color(test->m_webView, &rgba);
+ g_assert_cmpfloat(rgba.red, ==, 1);
+ g_assert_cmpfloat(rgba.green, ==, 0);
+ g_assert_cmpfloat(rgba.blue, ==, 0);
+ g_assert_cmpfloat(rgba.alpha, ==, 0.5);
+
+ // The actual rendering can't be tested using unit tests, use
+ // MiniBrowser --bg-color="<color-value>" for manually testing this API.
+}
+
+static void testWebViewPreferredSize(WebViewTest* test, gconstpointer)
+{
+ test->loadHtml("<html style='width: 325px; height: 615px'></html>", nullptr);
+ test->waitUntilLoadFinished();
+ test->showInWindowAndWaitUntilMapped();
+ GtkRequisition minimunSize, naturalSize;
+ gtk_widget_get_preferred_size(GTK_WIDGET(test->m_webView), &minimunSize, &naturalSize);
+ g_assert_cmpint(minimunSize.width, ==, 0);
+ g_assert_cmpint(minimunSize.height, ==, 0);
+ g_assert_cmpint(naturalSize.width, ==, 325);
+ g_assert_cmpint(naturalSize.height, ==, 615);
+}
+
+class WebViewTitleTest: public WebViewTest {
+public:
+ MAKE_GLIB_TEST_FIXTURE(WebViewTitleTest);
+
+ static void titleChangedCallback(WebKitWebView* view, GParamSpec*, WebViewTitleTest* test)
+ {
+ test->m_webViewTitles.append(webkit_web_view_get_title(view));
+ }
+
+ WebViewTitleTest()
+ {
+ g_signal_connect(m_webView, "notify::title", G_CALLBACK(titleChangedCallback), this);
+ }
+
+ Vector<CString> m_webViewTitles;
+};
+
+static void testWebViewTitleChange(WebViewTitleTest* test, gconstpointer)
+{
+ g_assert_cmpint(test->m_webViewTitles.size(), ==, 0);
+
+ test->loadHtml("<head><title>Page Title</title></head>", nullptr);
+ test->waitUntilLoadFinished();
+ g_assert_cmpint(test->m_webViewTitles.size(), ==, 1);
+ g_assert_cmpstr(test->m_webViewTitles[0].data(), ==, "Page Title");
+
+ test->loadHtml("<head><title>Another Page Title</title></head>", nullptr);
+ test->waitUntilLoadFinished();
+ g_assert_cmpint(test->m_webViewTitles.size(), ==, 3);
+ /* Page title should be immediately unset when loading a new page. */
+ g_assert_cmpstr(test->m_webViewTitles[1].data(), ==, "");
+ g_assert_cmpstr(test->m_webViewTitles[2].data(), ==, "Another Page Title");
+
+ test->loadHtml("<p>This page has no title!</p>", nullptr);
+ test->waitUntilLoadFinished();
+ g_assert_cmpint(test->m_webViewTitles.size(), ==, 4);
+ g_assert_cmpstr(test->m_webViewTitles[3].data(), ==, "");
+
+ test->loadHtml("<script>document.title = 'one'; document.title = 'two'; document.title = 'three';</script>", nullptr);
+ test->waitUntilLoadFinished();
+ g_assert_cmpint(test->m_webViewTitles.size(), ==, 7);
+ g_assert_cmpstr(test->m_webViewTitles[4].data(), ==, "one");
+ g_assert_cmpstr(test->m_webViewTitles[5].data(), ==, "two");
+ g_assert_cmpstr(test->m_webViewTitles[6].data(), ==, "three");
+}
+
+static void serverCallback(SoupServer* server, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, gpointer)
+{
+ if (message->method != SOUP_METHOD_GET) {
+ soup_message_set_status(message, SOUP_STATUS_NOT_IMPLEMENTED);
+ return;
+ }
+
+ if (g_str_equal(path, "/")) {
+ soup_message_set_status(message, SOUP_STATUS_OK);
+ soup_message_body_complete(message->response_body);
+ } else
+ soup_message_set_status(message, SOUP_STATUS_NOT_FOUND);
+}
+
void beforeAll()
{
- WebViewTest::add("WebKitWebView", "default-context", testWebViewDefaultContext);
+ gServer = new WebKitTestServer();
+ gServer->run(serverCallback);
+
+ WebViewTest::add("WebKitWebView", "web-context", testWebViewWebContext);
+ WebViewTest::add("WebKitWebView", "web-context-lifetime", testWebViewWebContextLifetime);
+ WebViewTest::add("WebKitWebView", "ephemeral", testWebViewEphemeral);
WebViewTest::add("WebKitWebView", "custom-charset", testWebViewCustomCharset);
WebViewTest::add("WebKitWebView", "settings", testWebViewSettings);
WebViewTest::add("WebKitWebView", "zoom-level", testWebViewZoomLevel);
@@ -581,9 +1070,15 @@ void beforeAll()
WebViewTest::add("WebKitWebView", "can-show-mime-type", testWebViewCanShowMIMEType);
FormClientTest::add("WebKitWebView", "submit-form", testWebViewSubmitForm);
SaveWebViewTest::add("WebKitWebView", "save", testWebViewSave);
- WebViewTest::add("WebKitWebView", "view-mode", testWebViewMode);
SnapshotWebViewTest::add("WebKitWebView", "snapshot", testWebViewSnapshot);
WebViewTest::add("WebKitWebView", "page-visibility", testWebViewPageVisibility);
+ NotificationWebViewTest::add("WebKitWebView", "notification", testWebViewNotification);
+ NotificationWebViewTest::add("WebKitWebView", "notification-initial-permission-allowed", testWebViewNotificationInitialPermissionAllowed);
+ NotificationWebViewTest::add("WebKitWebView", "notification-initial-permission-disallowed", testWebViewNotificationInitialPermissionDisallowed);
+ IsPlayingAudioWebViewTest::add("WebKitWebView", "is-playing-audio", testWebViewIsPlayingAudio);
+ WebViewTest::add("WebKitWebView", "background-color", testWebViewBackgroundColor);
+ WebViewTest::add("WebKitWebView", "preferred-size", testWebViewPreferredSize);
+ WebViewTitleTest::add("WebKitWebView", "title-change", testWebViewTitleChange);
}
void afterAll()
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitWebViewGroup.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitWebViewGroup.cpp
deleted file mode 100644
index 448abd2fe..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitWebViewGroup.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (C) 2013 Igalia S.L.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2,1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-
-#include "WebKitTestServer.h"
-#include "WebViewTest.h"
-#include <cstdarg>
-#include <gtk/gtk.h>
-#include <webkit2/webkit2.h>
-#include <wtf/gobject/GRefPtr.h>
-
-static WebKitTestServer* kServer;
-
-// These are all here so that they can be changed easily, if necessary.
-static const char* kStyleSheetHTML = "<html><div id=\"styledElement\">Sweet stylez!</div></html>";
-static const char* kInjectedStyleSheet = "#styledElement { font-weight: bold; }";
-static const char* kStyleSheetTestScript = "getComputedStyle(document.getElementById('styledElement'))['font-weight']";
-static const char* kStyleSheetTestScriptResult = "bold";
-
-static void testWebViewGroupDefault(Test* test, gconstpointer)
-{
- // Default group is shared by all WebViews by default.
- GRefPtr<WebKitWebView> webView1 = WEBKIT_WEB_VIEW(webkit_web_view_new());
- GRefPtr<WebKitWebView> webView2 = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_assert(webkit_web_view_get_group(webView1.get()) == webkit_web_view_get_group(webView2.get()));
-
- // Settings are shared by all web view in the same group.
- g_assert(webkit_web_view_get_settings(webView1.get()) == webkit_web_view_get_settings(webView2.get()));
- g_assert(webkit_web_view_get_settings(webView1.get()) == webkit_web_view_group_get_settings(webkit_web_view_get_group(webView2.get())));
-}
-
-static void testWebViewGroupNewGroup(Test* test, gconstpointer)
-{
- // Passing 0 as group name generates the name automatically.
- GRefPtr<WebKitWebViewGroup> viewGroup1 = adoptGRef(webkit_web_view_group_new(0));
- test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(viewGroup1.get()));
- g_assert(webkit_web_view_group_get_name(viewGroup1.get()));
-
- // New group with a given name.
- GRefPtr<WebKitWebViewGroup> viewGroup2 = adoptGRef(webkit_web_view_group_new("TestGroup2"));
- test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(viewGroup2.get()));
- g_assert_cmpstr(webkit_web_view_group_get_name(viewGroup2.get()), ==, "TestGroup2");
- g_assert_cmpstr(webkit_web_view_group_get_name(viewGroup2.get()), !=, webkit_web_view_group_get_name(viewGroup1.get()));
-
- // Every group has its own settings.
- g_assert(webkit_web_view_group_get_settings(viewGroup1.get()) != webkit_web_view_group_get_settings(viewGroup2.get()));
-}
-
-static void testWebViewNewWithGroup(Test* test, gconstpointer)
-{
- GRefPtr<WebKitWebViewGroup> viewGroup1 = adoptGRef(webkit_web_view_group_new("TestGroup1"));
- test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(viewGroup1.get()));
- GRefPtr<WebKitWebView> webView1 = WEBKIT_WEB_VIEW(webkit_web_view_new_with_group(viewGroup1.get()));
- g_assert(webkit_web_view_get_group(webView1.get()) == viewGroup1.get());
-
- GRefPtr<WebKitWebView> webView2 = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_assert(webkit_web_view_get_group(webView2.get()) != viewGroup1.get());
-
- // Settings should be different for views in different groups.
- g_assert(webkit_web_view_get_settings(webView1.get()) != webkit_web_view_get_settings(webView2.get()));
-}
-
-static void testWebViewGroupSettings(Test* test, gconstpointer)
-{
- GRefPtr<WebKitWebViewGroup> viewGroup1 = adoptGRef(webkit_web_view_group_new("TestGroup1"));
- test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(viewGroup1.get()));
- GRefPtr<WebKitSettings> newSettings = adoptGRef(webkit_settings_new_with_settings("enable-javascript", FALSE, nullptr));
- test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(newSettings.get()));
- webkit_web_view_group_set_settings(viewGroup1.get(), newSettings.get());
- g_assert(webkit_web_view_group_get_settings(viewGroup1.get()) == newSettings.get());
-
- GRefPtr<WebKitWebView> webView1 = WEBKIT_WEB_VIEW(webkit_web_view_new_with_group(viewGroup1.get()));
- GRefPtr<WebKitWebView> webView2 = WEBKIT_WEB_VIEW(webkit_web_view_new());
- WebKitSettings* webView1Settings = webkit_web_view_get_settings(webView1.get());
- WebKitSettings* webView2Settings = webkit_web_view_get_settings(webView2.get());
- g_assert(webView1Settings != webView2Settings);
- g_assert(webkit_settings_get_enable_javascript(webView1Settings) != webkit_settings_get_enable_javascript(webView2Settings));
-
- webkit_web_view_set_settings(webView1.get(), webView2Settings);
- g_assert(webkit_web_view_get_settings(webView1.get()) == webView2Settings);
- g_assert(webkit_web_view_group_get_settings(webkit_web_view_get_group(webView1.get())) == webView2Settings);
-}
-
-static bool isStyleSheetInjectedForURLAtPath(WebViewTest* test, const char* path)
-{
- test->loadURI(kServer->getURIForPath(path).data());
- test->waitUntilLoadFinished();
-
- GUniqueOutPtr<GError> error;
- WebKitJavascriptResult* javascriptResult = test->runJavaScriptAndWaitUntilFinished(kStyleSheetTestScript, &error.outPtr());
- g_assert(javascriptResult);
- g_assert(!error.get());
-
- GUniquePtr<char> resultString(WebViewTest::javascriptResultToCString(javascriptResult));
- return !g_strcmp0(resultString.get(), kStyleSheetTestScriptResult);
-}
-
-static void fillURLListFromPaths(char** list, const char* path, ...)
-{
- va_list argumentList;
- va_start(argumentList, path);
-
- int i = 0;
- while (path) {
- // FIXME: We must use a wildcard for the host here until http://wkbug.com/112476 is fixed.
- // Until that time patterns with port numbers in them will not properly match URLs with port numbers.
- list[i++] = g_strdup_printf("http://*/%s*", path);
- path = va_arg(argumentList, const char*);
- }
-}
-
-static void removeOldInjectedStyleSheetsAndResetLists(WebKitWebViewGroup* group, char** whitelist, char** blacklist)
-{
- webkit_web_view_group_remove_all_user_style_sheets(group);
-
- while (*whitelist) {
- g_free(*whitelist);
- *whitelist = 0;
- whitelist++;
- }
-
- while (*blacklist) {
- g_free(*blacklist);
- *blacklist = 0;
- blacklist++;
- }
-}
-
-static void testWebViewGroupInjectedStyleSheet(WebViewTest* test, gconstpointer)
-{
- WebKitWebViewGroup* group = webkit_web_view_get_group(test->m_webView);
- char* whitelist[3] = { 0, 0, 0 };
- char* blacklist[3] = { 0, 0, 0 };
-
- removeOldInjectedStyleSheetsAndResetLists(group, whitelist, blacklist);
-
- // Without a whitelist or a blacklist all URLs should have the injected style sheet.
- static const char* randomPath = "somerandompath";
- g_assert(!isStyleSheetInjectedForURLAtPath(test, randomPath));
- webkit_web_view_group_add_user_style_sheet(group, kInjectedStyleSheet, 0, 0, 0, WEBKIT_INJECTED_CONTENT_FRAMES_ALL);
- g_assert(isStyleSheetInjectedForURLAtPath(test, randomPath));
-
- removeOldInjectedStyleSheetsAndResetLists(group, whitelist, blacklist);
-
- fillURLListFromPaths(blacklist, randomPath, 0);
- webkit_web_view_group_add_user_style_sheet(group, kInjectedStyleSheet, 0, 0, blacklist, WEBKIT_INJECTED_CONTENT_FRAMES_ALL);
- g_assert(!isStyleSheetInjectedForURLAtPath(test, randomPath));
- g_assert(isStyleSheetInjectedForURLAtPath(test, "someotherrandompath"));
-
- removeOldInjectedStyleSheetsAndResetLists(group, whitelist, blacklist);
-
- static const char* inTheWhiteList = "inthewhitelist";
- static const char* notInWhitelist = "notinthewhitelist";
- static const char* inTheWhiteListAndBlackList = "inthewhitelistandblacklist";
-
- fillURLListFromPaths(whitelist, inTheWhiteList, inTheWhiteListAndBlackList, 0);
- fillURLListFromPaths(blacklist, inTheWhiteListAndBlackList, 0);
- webkit_web_view_group_add_user_style_sheet(group, kInjectedStyleSheet, 0, whitelist, blacklist, WEBKIT_INJECTED_CONTENT_FRAMES_ALL);
- g_assert(isStyleSheetInjectedForURLAtPath(test, inTheWhiteList));
- g_assert(!isStyleSheetInjectedForURLAtPath(test, inTheWhiteListAndBlackList));
- g_assert(!isStyleSheetInjectedForURLAtPath(test, notInWhitelist));
-
- // It's important to clean up the environment before other tests.
- removeOldInjectedStyleSheetsAndResetLists(group, whitelist, blacklist);
-}
-
-static void serverCallback(SoupServer* server, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, gpointer)
-{
- soup_message_set_status(message, SOUP_STATUS_OK);
- soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, kStyleSheetHTML, strlen(kStyleSheetHTML));
- soup_message_body_complete(message->response_body);
-}
-
-void beforeAll()
-{
- kServer = new WebKitTestServer();
- kServer->run(serverCallback);
-
- Test::add("WebKitWebViewGroup", "default-group", testWebViewGroupDefault);
- Test::add("WebKitWebViewGroup", "new-group", testWebViewGroupNewGroup);
- Test::add("WebKitWebView", "new-with-group", testWebViewNewWithGroup);
- Test::add("WebKitWebViewGroup", "settings", testWebViewGroupSettings);
- WebViewTest::add("WebKitWebViewGroup", "injected-style-sheet", testWebViewGroupInjectedStyleSheet);
-}
-
-void afterAll()
-{
- delete kServer;
-}
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebViewEditor.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebViewEditor.cpp
index 9e69bfa48..00c02aed2 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebViewEditor.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebViewEditor.cpp
@@ -19,7 +19,7 @@
#include "config.h"
#include "WebViewTest.h"
-#include <wtf/gobject/GRefPtr.h>
+#include <wtf/glib/GRefPtr.h>
class EditorTest: public WebViewTest {
public:
@@ -32,6 +32,7 @@ public:
: m_clipboard(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD))
, m_canExecuteEditingCommand(false)
, m_triesCount(0)
+ , m_editorState(nullptr)
{
gtk_clipboard_clear(m_clipboard);
}
@@ -73,25 +74,71 @@ public:
g_main_loop_run(m_mainLoop);
}
+ gchar* cutSelection()
+ {
+ g_assert(canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_CUT));
+ g_assert(canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_PASTE));
+
+ webkit_web_view_execute_editing_command(m_webView, WEBKIT_EDITING_COMMAND_CUT);
+ // There's no way to know when the selection has been cut to
+ // the clipboard, so use a timeout source to query the clipboard.
+ m_triesCount = 0;
+ g_timeout_add(kClipboardWaitTimeout, reinterpret_cast<GSourceFunc>(waitForClipboardText), this);
+ g_main_loop_run(m_mainLoop);
+
+ return gtk_clipboard_wait_for_text(m_clipboard);
+ }
+
+ WebKitEditorState* editorState()
+ {
+ if (m_editorState)
+ return m_editorState;
+
+ m_editorState = webkit_web_view_get_editor_state(m_webView);
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(m_editorState));
+ return m_editorState;
+ }
+
+ static void quitMainLoopInCallback(EditorTest* test)
+ {
+ g_main_loop_quit(test->m_mainLoop);
+ }
+
+ unsigned typingAttributes()
+ {
+ return webkit_editor_state_get_typing_attributes(editorState());
+ }
+
+ unsigned waitUntilTypingAttributesChanged()
+ {
+ unsigned long handlerID = g_signal_connect_swapped(editorState(), "notify::typing-attributes", G_CALLBACK(quitMainLoopInCallback), this);
+ g_main_loop_run(m_mainLoop);
+ g_signal_handler_disconnect(m_editorState, handlerID);
+ return typingAttributes();
+ }
+
GtkClipboard* m_clipboard;
bool m_canExecuteEditingCommand;
size_t m_triesCount;
+ WebKitEditorState* m_editorState;
};
+static const char* selectedSpanHTMLFormat =
+ "<html><body contentEditable=\"%s\">"
+ "<span id=\"mainspan\">All work and no play <span id=\"subspan\">make Jack a dull</span> boy.</span>"
+ "<script>document.getSelection().removeAllRanges();\n"
+ "document.getSelection().selectAllChildren(document.getElementById('subspan'));\n"
+ "</script></body></html>";
+
static void testWebViewEditorCutCopyPasteNonEditable(EditorTest* test, gconstpointer)
{
- static const char* selectedSpanHTML = "<html><body contentEditable=\"false\">"
- "<span id=\"mainspan\">All work and no play <span id=\"subspan\">make Jack a dull</span> boy.</span>"
- "<script>document.getSelection().collapse();\n"
- "document.getSelection().selectAllChildren(document.getElementById('subspan'));\n"
- "</script></body></html>";
-
// Nothing loaded yet.
g_assert(!test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_CUT));
g_assert(!test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_COPY));
g_assert(!test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_PASTE));
- test->loadHtml(selectedSpanHTML, 0);
+ GUniquePtr<char> selectedSpanHTML(g_strdup_printf(selectedSpanHTMLFormat, "false"));
+ test->loadHtml(selectedSpanHTML.get(), nullptr);
test->waitUntilLoadFinished();
g_assert(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_COPY));
@@ -107,18 +154,17 @@ static void testWebViewEditorCutCopyPasteNonEditable(EditorTest* test, gconstpoi
static void testWebViewEditorCutCopyPasteEditable(EditorTest* test, gconstpointer)
{
- static const char* selectedSpanHTML = "<html><body contentEditable=\"true\">"
- "<span id=\"mainspan\">All work and no play <span>make Jack a dull</span> boy.</span>"
- "<script>document.getSelection().collapse();\n"
- "document.getSelection().selectAllChildren(document.getElementById('mainspan'));\n"
- "</script></body></html>";
-
// Nothing loaded yet.
g_assert(!test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_CUT));
g_assert(!test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_COPY));
g_assert(!test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_PASTE));
- test->loadHtml(selectedSpanHTML, 0);
+ g_assert(!test->isEditable());
+ test->setEditable(true);
+ g_assert(test->isEditable());
+
+ GUniquePtr<char> selectedSpanHTML(g_strdup_printf(selectedSpanHTMLFormat, "false"));
+ test->loadHtml(selectedSpanHTML.get(), nullptr);
test->waitUntilLoadFinished();
// There's a selection.
@@ -128,20 +174,15 @@ static void testWebViewEditorCutCopyPasteEditable(EditorTest* test, gconstpointe
test->copyClipboard();
GUniquePtr<char> clipboardText(gtk_clipboard_wait_for_text(test->m_clipboard));
- g_assert_cmpstr(clipboardText.get(), ==, "All work and no play make Jack a dull boy.");
+ g_assert_cmpstr(clipboardText.get(), ==, "make Jack a dull");
}
static void testWebViewEditorSelectAllNonEditable(EditorTest* test, gconstpointer)
{
- static const char* selectedSpanHTML = "<html><body contentEditable=\"false\">"
- "<span id=\"mainspan\">All work and no play <span id=\"subspan\">make Jack a dull</span> boy.</span>"
- "<script>document.getSelection().collapse();\n"
- "document.getSelection().selectAllChildren(document.getElementById('subspan'));\n"
- "</script></body></html>";
-
g_assert(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_SELECT_ALL));
- test->loadHtml(selectedSpanHTML, 0);
+ GUniquePtr<char> selectedSpanHTML(g_strdup_printf(selectedSpanHTMLFormat, "false"));
+ test->loadHtml(selectedSpanHTML.get(), nullptr);
test->waitUntilLoadFinished();
g_assert(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_SELECT_ALL));
@@ -162,15 +203,14 @@ static void testWebViewEditorSelectAllNonEditable(EditorTest* test, gconstpointe
static void testWebViewEditorSelectAllEditable(EditorTest* test, gconstpointer)
{
- static const char* selectedSpanHTML = "<html><body contentEditable=\"true\">"
- "<span id=\"mainspan\">All work and no play <span id=\"subspan\">make Jack a dull</span> boy.</span>"
- "<script>document.getSelection().collapse();\n"
- "document.getSelection().selectAllChildren(document.getElementById('subspan'));\n"
- "</script></body></html>";
-
g_assert(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_SELECT_ALL));
- test->loadHtml(selectedSpanHTML, 0);
+ g_assert(!test->isEditable());
+ test->setEditable(true);
+ g_assert(test->isEditable());
+
+ GUniquePtr<char> selectedSpanHTML(g_strdup_printf(selectedSpanHTMLFormat, "false"));
+ test->loadHtml(selectedSpanHTML.get(), nullptr);
test->waitUntilLoadFinished();
g_assert(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_SELECT_ALL));
@@ -189,12 +229,240 @@ static void testWebViewEditorSelectAllEditable(EditorTest* test, gconstpointer)
g_assert_cmpstr(clipboardText.get(), ==, "All work and no play make Jack a dull boy.");
}
+static void loadContentsAndTryToCutSelection(EditorTest* test, bool contentEditable)
+{
+ // View is not editable by default.
+ g_assert(!test->isEditable());
+
+ GUniquePtr<char> selectedSpanHTML(g_strdup_printf(selectedSpanHTMLFormat, contentEditable ? "true" : "false"));
+ test->loadHtml(selectedSpanHTML.get(), nullptr);
+ test->waitUntilLoadFinished();
+
+ g_assert(!test->isEditable());
+ test->setEditable(true);
+ g_assert(test->isEditable());
+
+ // Cut the selection to the clipboard to see if the view is indeed editable.
+ GUniquePtr<char> clipboardText(test->cutSelection());
+ g_assert_cmpstr(clipboardText.get(), ==, "make Jack a dull");
+
+ // Reset the editable for next test.
+ test->setEditable(false);
+ g_assert(!test->isEditable());
+}
+
+static void testWebViewEditorNonEditable(EditorTest* test)
+{
+ GUniquePtr<char> selectedSpanHTML(g_strdup_printf(selectedSpanHTMLFormat, "false"));
+ test->loadHtml(selectedSpanHTML.get(), nullptr);
+ test->waitUntilLoadFinished();
+
+ g_assert(!test->isEditable());
+ test->setEditable(true);
+ g_assert(test->isEditable());
+ test->setEditable(false);
+ g_assert(!test->isEditable());
+
+ // Check if view is indeed non-editable.
+ g_assert(!test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_CUT));
+ g_assert(!test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_PASTE));
+}
+
+static void testWebViewEditorEditable(EditorTest* test, gconstpointer)
+{
+ testWebViewEditorNonEditable(test);
+
+ // Reset the editable for next test.
+ test->setEditable(false);
+ g_assert(!test->isEditable());
+
+ loadContentsAndTryToCutSelection(test, true);
+
+ // Reset the editable for next test.
+ test->setEditable(false);
+ g_assert(!test->isEditable());
+
+ loadContentsAndTryToCutSelection(test, false);
+}
+
+static void testWebViewEditorEditorStateTypingAttributes(EditorTest* test, gconstpointer)
+{
+ static const char* typingAttributesHTML =
+ "<html><body>"
+ "normal <b>bold </b><i>italic </i><u>underline </u><strike>strike </strike>"
+ "<b><i>boldanditalic </i></b>"
+ "</body></html>";
+
+ test->loadHtml(typingAttributesHTML, nullptr);
+ test->waitUntilLoadFinished();
+ test->setEditable(true);
+
+ unsigned typingAttributes = test->typingAttributes();
+ g_assert_cmpuint(typingAttributes, ==, WEBKIT_EDITOR_TYPING_ATTRIBUTE_NONE);
+
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveWordForward");
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveForward");
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveForward");
+ typingAttributes = test->waitUntilTypingAttributesChanged();
+ g_assert(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_BOLD);
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_ITALIC));
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_UNDERLINE));
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_STRIKETHROUGH));
+
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveWordForward");
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveForward");
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveForward");
+ typingAttributes = test->waitUntilTypingAttributesChanged();
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_BOLD));
+ g_assert(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_ITALIC);
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_UNDERLINE));
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_STRIKETHROUGH));
+
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveWordForward");
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveForward");
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveForward");
+ typingAttributes = test->waitUntilTypingAttributesChanged();
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_BOLD));
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_ITALIC));
+ g_assert(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_UNDERLINE);
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_STRIKETHROUGH));
+
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveWordForward");
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveForward");
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveForward");
+ typingAttributes = test->waitUntilTypingAttributesChanged();
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_BOLD));
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_ITALIC));
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_UNDERLINE));
+ g_assert(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_STRIKETHROUGH);
+
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveWordForward");
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveForward");
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveForward");
+ typingAttributes = test->waitUntilTypingAttributesChanged();
+ g_assert(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_BOLD);
+ g_assert(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_ITALIC);
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_UNDERLINE));
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_STRIKETHROUGH));
+
+ // Selections.
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveToBeginningOfDocument");
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveWordForwardAndModifySelection");
+ typingAttributes = test->waitUntilTypingAttributesChanged();
+ g_assert_cmpuint(typingAttributes, ==, WEBKIT_EDITOR_TYPING_ATTRIBUTE_NONE);
+
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveForward");
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveForward");
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveWordForwardAndModifySelection");
+ typingAttributes = test->waitUntilTypingAttributesChanged();
+ g_assert(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_BOLD);
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_ITALIC));
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_UNDERLINE));
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_STRIKETHROUGH));
+
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveForward");
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveForward");
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveWordForwardAndModifySelection");
+ typingAttributes = test->waitUntilTypingAttributesChanged();
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_BOLD));
+ g_assert(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_ITALIC);
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_UNDERLINE));
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_STRIKETHROUGH));
+
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveForward");
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveForward");
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveWordForwardAndModifySelection");
+ typingAttributes = test->waitUntilTypingAttributesChanged();
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_BOLD));
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_ITALIC));
+ g_assert(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_UNDERLINE);
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_STRIKETHROUGH));
+
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveForward");
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveForward");
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveWordForwardAndModifySelection");
+ typingAttributes = test->waitUntilTypingAttributesChanged();
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_BOLD));
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_ITALIC));
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_UNDERLINE));
+ g_assert(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_STRIKETHROUGH);
+
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveForward");
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveForward");
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveWordForwardAndModifySelection");
+ typingAttributes = test->waitUntilTypingAttributesChanged();
+ g_assert(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_BOLD);
+ g_assert(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_ITALIC);
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_UNDERLINE));
+ g_assert(!(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_STRIKETHROUGH));
+
+ webkit_web_view_execute_editing_command(test->m_webView, "SelectAll");
+ typingAttributes = test->waitUntilTypingAttributesChanged();
+ g_assert_cmpuint(typingAttributes, ==, WEBKIT_EDITOR_TYPING_ATTRIBUTE_NONE);
+}
+
+static void testWebViewEditorInsertImage(EditorTest* test, gconstpointer)
+{
+ test->loadHtml("<html><body></body></html>", "file:///");
+ test->waitUntilLoadFinished();
+ test->setEditable(true);
+
+ GUniquePtr<char> imagePath(g_build_filename(Test::getResourcesDir().data(), "blank.ico", nullptr));
+ GUniquePtr<char> imageURI(g_filename_to_uri(imagePath.get(), nullptr, nullptr));
+ webkit_web_view_execute_editing_command_with_argument(test->m_webView, WEBKIT_EDITING_COMMAND_INSERT_IMAGE, imageURI.get());
+ GUniqueOutPtr<GError> error;
+ WebKitJavascriptResult* javascriptResult = test->runJavaScriptAndWaitUntilFinished("document.getElementsByTagName('IMG')[0].src", &error.outPtr());
+ g_assert(javascriptResult);
+ g_assert(!error);
+ GUniquePtr<char> resultString(WebViewTest::javascriptResultToCString(javascriptResult));
+ g_assert_cmpstr(resultString.get(), ==, imageURI.get());
+}
+
+static void testWebViewEditorCreateLink(EditorTest* test, gconstpointer)
+{
+ test->loadHtml("<html><body onload=\"document.getSelection().selectAllChildren(document.body);\">webkitgtk.org</body></html>", nullptr);
+ test->waitUntilLoadFinished();
+ test->setEditable(true);
+
+ static const char* webkitGTKURL = "http://www.webkitgtk.org/";
+ webkit_web_view_execute_editing_command_with_argument(test->m_webView, WEBKIT_EDITING_COMMAND_CREATE_LINK, webkitGTKURL);
+ GUniqueOutPtr<GError> error;
+ WebKitJavascriptResult* javascriptResult = test->runJavaScriptAndWaitUntilFinished("document.getElementsByTagName('A')[0].href;", &error.outPtr());
+ g_assert(javascriptResult);
+ g_assert(!error);
+ GUniquePtr<char> resultString(WebViewTest::javascriptResultToCString(javascriptResult));
+ g_assert_cmpstr(resultString.get(), ==, webkitGTKURL);
+ javascriptResult = test->runJavaScriptAndWaitUntilFinished("document.getElementsByTagName('A')[0].innerText;", &error.outPtr());
+ g_assert(javascriptResult);
+ g_assert(!error);
+ resultString.reset(WebViewTest::javascriptResultToCString(javascriptResult));
+ g_assert_cmpstr(resultString.get(), ==, "webkitgtk.org");
+
+ // When there isn't text selected, the URL is used as link text.
+ webkit_web_view_execute_editing_command(test->m_webView, "MoveToEndOfLine");
+ webkit_web_view_execute_editing_command_with_argument(test->m_webView, WEBKIT_EDITING_COMMAND_CREATE_LINK, webkitGTKURL);
+ javascriptResult = test->runJavaScriptAndWaitUntilFinished("document.getElementsByTagName('A')[1].href;", &error.outPtr());
+ g_assert(javascriptResult);
+ g_assert(!error);
+ resultString.reset(WebViewTest::javascriptResultToCString(javascriptResult));
+ g_assert_cmpstr(resultString.get(), ==, webkitGTKURL);
+ javascriptResult = test->runJavaScriptAndWaitUntilFinished("document.getElementsByTagName('A')[1].innerText;", &error.outPtr());
+ g_assert(javascriptResult);
+ g_assert(!error);
+ resultString.reset(WebViewTest::javascriptResultToCString(javascriptResult));
+ g_assert_cmpstr(resultString.get(), ==, webkitGTKURL);
+}
+
void beforeAll()
{
+ EditorTest::add("WebKitWebView", "editable/editable", testWebViewEditorEditable);
EditorTest::add("WebKitWebView", "cut-copy-paste/non-editable", testWebViewEditorCutCopyPasteNonEditable);
EditorTest::add("WebKitWebView", "cut-copy-paste/editable", testWebViewEditorCutCopyPasteEditable);
EditorTest::add("WebKitWebView", "select-all/non-editable", testWebViewEditorSelectAllNonEditable);
EditorTest::add("WebKitWebView", "select-all/editable", testWebViewEditorSelectAllEditable);
+ EditorTest::add("WebKitWebView", "editor-state/typing-attributes", testWebViewEditorEditorStateTypingAttributes);
+ EditorTest::add("WebKitWebView", "insert/image", testWebViewEditorInsertImage);
+ EditorTest::add("WebKitWebView", "insert/link", testWebViewEditorCreateLink);
}
void afterAll()
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebsiteData.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebsiteData.cpp
new file mode 100644
index 000000000..4959e838e
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebsiteData.cpp
@@ -0,0 +1,537 @@
+/*
+ * Copyright (C) 2017 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2,1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include "WebKitTestServer.h"
+#include "WebViewTest.h"
+
+static WebKitTestServer* kServer;
+
+static void serverCallback(SoupServer* server, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, gpointer)
+{
+ if (message->method != SOUP_METHOD_GET) {
+ soup_message_set_status(message, SOUP_STATUS_NOT_IMPLEMENTED);
+ return;
+ }
+
+ if (g_str_equal(path, "/empty")) {
+ const char* emptyHTML = "<html><body></body></html>";
+ soup_message_headers_replace(message->response_headers, "Set-Cookie", "foo=bar; Max-Age=60");
+ soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, emptyHTML, strlen(emptyHTML));
+ soup_message_body_complete(message->response_body);
+ soup_message_set_status(message, SOUP_STATUS_OK);
+ } else if (g_str_equal(path, "/appcache")) {
+ const char* appcacheHTML = "<html manifest=appcache.manifest><body></body></html>";
+ soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, appcacheHTML, strlen(appcacheHTML));
+ soup_message_body_complete(message->response_body);
+ soup_message_set_status(message, SOUP_STATUS_OK);
+ } else if (g_str_equal(path, "/appcache.manifest")) {
+ const char* appcacheManifest = "CACHE MANIFEST\nCACHE:\nappcache/foo.txt\n";
+ soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, appcacheManifest, strlen(appcacheManifest));
+ soup_message_body_complete(message->response_body);
+ soup_message_set_status(message, SOUP_STATUS_OK);
+ } else if (g_str_equal(path, "/appcache/foo.txt")) {
+ soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, "foo", 3);
+ soup_message_body_complete(message->response_body);
+ soup_message_set_status(message, SOUP_STATUS_OK);
+ } else if (g_str_equal(path, "/sessionstorage")) {
+ const char* sessionStorageHTML = "<html><body onload=\"sessionStorage.foo = 'bar';\"></body></html>";
+ soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, sessionStorageHTML, strlen(sessionStorageHTML));
+ soup_message_body_complete(message->response_body);
+ soup_message_set_status(message, SOUP_STATUS_OK);
+ } else if (g_str_equal(path, "/localstorage")) {
+ const char* localStorageHTML = "<html><body onload=\"localStorage.foo = 'bar';\"></body></html>";
+ soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, localStorageHTML, strlen(localStorageHTML));
+ soup_message_body_complete(message->response_body);
+ soup_message_set_status(message, SOUP_STATUS_OK);
+ } else
+ soup_message_set_status(message, SOUP_STATUS_NOT_FOUND);
+}
+
+class WebsiteDataTest : public WebViewTest {
+public:
+ MAKE_GLIB_TEST_FIXTURE(WebsiteDataTest);
+
+
+ WebsiteDataTest()
+ : m_manager(webkit_web_context_get_website_data_manager(webkit_web_view_get_context(m_webView)))
+ {
+ g_assert(WEBKIT_IS_WEBSITE_DATA_MANAGER(m_manager));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(m_manager));
+ // WebsiteDataStore creates a new WebProcessPool when used before any secondary process has been created.
+ // Ensure we have a web process by always loading about:blank here.
+ loadURI("about:blank");
+ waitUntilLoadFinished();
+ }
+
+ ~WebsiteDataTest()
+ {
+ g_list_free_full(m_dataList, reinterpret_cast<GDestroyNotify>(webkit_website_data_unref));
+ }
+
+ GList* fetch(WebKitWebsiteDataTypes types)
+ {
+ if (m_dataList) {
+ g_list_free_full(m_dataList, reinterpret_cast<GDestroyNotify>(webkit_website_data_unref));
+ m_dataList = nullptr;
+ }
+ webkit_website_data_manager_fetch(m_manager, types, nullptr, [](GObject*, GAsyncResult* result, gpointer userData) {
+ WebsiteDataTest* test = static_cast<WebsiteDataTest*>(userData);
+ test->m_dataList = webkit_website_data_manager_fetch_finish(test->m_manager, result, nullptr);
+ test->quitMainLoop();
+ }, this);
+ g_main_loop_run(m_mainLoop);
+ return m_dataList;
+ }
+
+ void remove(WebKitWebsiteDataTypes types, GList* dataList)
+ {
+ webkit_website_data_manager_remove(m_manager, types, dataList, nullptr, [](GObject*, GAsyncResult* result, gpointer userData) {
+ WebsiteDataTest* test = static_cast<WebsiteDataTest*>(userData);
+ g_assert(webkit_website_data_manager_remove_finish(test->m_manager, result, nullptr));
+ test->quitMainLoop();
+ }, this);
+ g_main_loop_run(m_mainLoop);
+ }
+
+ void clear(WebKitWebsiteDataTypes types, GTimeSpan timeSpan)
+ {
+ webkit_website_data_manager_clear(m_manager, types, timeSpan, nullptr, [](GObject*, GAsyncResult* result, gpointer userData) {
+ WebsiteDataTest* test = static_cast<WebsiteDataTest*>(userData);
+ g_assert(webkit_website_data_manager_clear_finish(test->m_manager, result, nullptr));
+ test->quitMainLoop();
+ }, this);
+ g_main_loop_run(m_mainLoop);
+ }
+
+ WebKitWebsiteDataManager* m_manager;
+ GList* m_dataList { nullptr };
+};
+
+static void testWebsiteDataConfiguration(WebsiteDataTest* test, gconstpointer)
+{
+ // Base directories are not used by TestMain.
+ g_assert(!webkit_website_data_manager_get_base_data_directory(test->m_manager));
+ g_assert(!webkit_website_data_manager_get_base_cache_directory(test->m_manager));
+
+ GUniquePtr<char> localStorageDirectory(g_build_filename(Test::dataDirectory(), "local-storage", nullptr));
+ g_assert_cmpstr(localStorageDirectory.get(), ==, webkit_website_data_manager_get_local_storage_directory(test->m_manager));
+ g_assert(g_file_test(localStorageDirectory.get(), G_FILE_TEST_IS_DIR));
+
+ test->loadURI(kServer->getURIForPath("/empty").data());
+ test->waitUntilLoadFinished();
+ test->runJavaScriptAndWaitUntilFinished("window.indexedDB.open('TestDatabase');", nullptr);
+ GUniquePtr<char> indexedDBDirectory(g_build_filename(Test::dataDirectory(), "indexeddb", nullptr));
+ g_assert_cmpstr(indexedDBDirectory.get(), ==, webkit_website_data_manager_get_indexeddb_directory(test->m_manager));
+ g_assert(g_file_test(indexedDBDirectory.get(), G_FILE_TEST_IS_DIR));
+
+ GUniquePtr<char> webSQLDirectory(g_build_filename(Test::dataDirectory(), "websql", nullptr));
+ g_assert_cmpstr(webSQLDirectory.get(), ==, webkit_website_data_manager_get_websql_directory(test->m_manager));
+ test->runJavaScriptAndWaitUntilFinished("db = openDatabase(\"TestDatabase\", \"1.0\", \"TestDatabase\", 1);", nullptr);
+ g_assert(g_file_test(webSQLDirectory.get(), G_FILE_TEST_IS_DIR));
+
+ test->loadURI(kServer->getURIForPath("/appcache").data());
+ test->waitUntilLoadFinished();
+ GUniquePtr<char> applicationCacheDirectory(g_build_filename(Test::dataDirectory(), "appcache", nullptr));
+ g_assert_cmpstr(applicationCacheDirectory.get(), ==, webkit_website_data_manager_get_offline_application_cache_directory(test->m_manager));
+ GUniquePtr<char> applicationCacheDatabase(g_build_filename(applicationCacheDirectory.get(), "ApplicationCache.db", nullptr));
+ unsigned triesCount = 4;
+ while (!g_file_test(applicationCacheDatabase.get(), G_FILE_TEST_IS_REGULAR) && --triesCount)
+ test->wait(0.25);
+ g_assert(triesCount);
+
+ GUniquePtr<char> diskCacheDirectory(g_build_filename(Test::dataDirectory(), "disk-cache", nullptr));
+ g_assert_cmpstr(diskCacheDirectory.get(), ==, webkit_website_data_manager_get_disk_cache_directory(test->m_manager));
+ g_assert(g_file_test(diskCacheDirectory.get(), G_FILE_TEST_IS_DIR));
+
+ // Clear all persistent caches, since the data dir is common to all test cases.
+ static const WebKitWebsiteDataTypes persistentCaches = static_cast<WebKitWebsiteDataTypes>(WEBKIT_WEBSITE_DATA_DISK_CACHE | WEBKIT_WEBSITE_DATA_LOCAL_STORAGE
+ | WEBKIT_WEBSITE_DATA_WEBSQL_DATABASES | WEBKIT_WEBSITE_DATA_INDEXEDDB_DATABASES | WEBKIT_WEBSITE_DATA_OFFLINE_APPLICATION_CACHE);
+ test->clear(persistentCaches, 0);
+ g_assert(!test->fetch(persistentCaches));
+
+ // The default context should have a different manager with different configuration.
+ WebKitWebsiteDataManager* defaultManager = webkit_web_context_get_website_data_manager(webkit_web_context_get_default());
+ g_assert(WEBKIT_IS_WEBSITE_DATA_MANAGER(defaultManager));
+ g_assert(test->m_manager != defaultManager);
+ g_assert_cmpstr(webkit_website_data_manager_get_local_storage_directory(test->m_manager), !=, webkit_website_data_manager_get_local_storage_directory(defaultManager));
+ g_assert_cmpstr(webkit_website_data_manager_get_indexeddb_directory(test->m_manager), !=, webkit_website_data_manager_get_indexeddb_directory(defaultManager));
+ g_assert_cmpstr(webkit_website_data_manager_get_disk_cache_directory(test->m_manager), !=, webkit_website_data_manager_get_disk_cache_directory(defaultManager));
+ g_assert_cmpstr(webkit_website_data_manager_get_offline_application_cache_directory(test->m_manager), !=, webkit_website_data_manager_get_offline_application_cache_directory(defaultManager));
+ g_assert_cmpstr(webkit_website_data_manager_get_websql_directory(test->m_manager), !=, webkit_website_data_manager_get_websql_directory(defaultManager));
+
+ // Using Test::dataDirectory() we get the default configuration but for a differrent prefix.
+ GRefPtr<WebKitWebsiteDataManager> baseDataManager = adoptGRef(webkit_website_data_manager_new("base-data-directory", Test::dataDirectory(), "base-cache-directory", Test::dataDirectory(), nullptr));
+ g_assert(WEBKIT_IS_WEBSITE_DATA_MANAGER(baseDataManager.get()));
+
+ localStorageDirectory.reset(g_build_filename(Test::dataDirectory(), "localstorage", nullptr));
+ g_assert_cmpstr(webkit_website_data_manager_get_local_storage_directory(baseDataManager.get()), ==, localStorageDirectory.get());
+
+ indexedDBDirectory.reset(g_build_filename(Test::dataDirectory(), "databases", "indexeddb", nullptr));
+ g_assert_cmpstr(webkit_website_data_manager_get_indexeddb_directory(baseDataManager.get()), ==, indexedDBDirectory.get());
+
+ applicationCacheDirectory.reset(g_build_filename(Test::dataDirectory(), "applications", nullptr));
+ g_assert_cmpstr(webkit_website_data_manager_get_offline_application_cache_directory(baseDataManager.get()), ==, applicationCacheDirectory.get());
+
+ webSQLDirectory.reset(g_build_filename(Test::dataDirectory(), "databases", nullptr));
+ g_assert_cmpstr(webkit_website_data_manager_get_websql_directory(baseDataManager.get()), ==, webSQLDirectory.get());
+
+ g_assert_cmpstr(webkit_website_data_manager_get_disk_cache_directory(baseDataManager.get()), ==, Test::dataDirectory());
+
+ // Any specific configuration provided takes precedence over base dirs.
+ indexedDBDirectory.reset(g_build_filename(Test::dataDirectory(), "mycustomindexeddb", nullptr));
+ applicationCacheDirectory.reset(g_build_filename(Test::dataDirectory(), "mycustomappcache", nullptr));
+ baseDataManager = adoptGRef(webkit_website_data_manager_new("base-data-directory", Test::dataDirectory(), "base-cache-directory", Test::dataDirectory(),
+ "indexeddb-directory", indexedDBDirectory.get(), "offline-application-cache-directory", applicationCacheDirectory.get(), nullptr));
+ g_assert_cmpstr(webkit_website_data_manager_get_indexeddb_directory(baseDataManager.get()), ==, indexedDBDirectory.get());
+ g_assert_cmpstr(webkit_website_data_manager_get_offline_application_cache_directory(baseDataManager.get()), ==, applicationCacheDirectory.get());
+ // The result should be the same as previous manager.
+ g_assert_cmpstr(webkit_website_data_manager_get_local_storage_directory(baseDataManager.get()), ==, localStorageDirectory.get());
+ g_assert_cmpstr(webkit_website_data_manager_get_websql_directory(baseDataManager.get()), ==, webSQLDirectory.get());
+ g_assert_cmpstr(webkit_website_data_manager_get_disk_cache_directory(baseDataManager.get()), ==, Test::dataDirectory());
+}
+
+static void ephemeralViewloadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent, WebViewTest* test)
+{
+ if (loadEvent != WEBKIT_LOAD_FINISHED)
+ return;
+ g_signal_handlers_disconnect_by_func(webView, reinterpret_cast<void*>(ephemeralViewloadChanged), test);
+ test->quitMainLoop();
+}
+
+static void testWebsiteDataEphemeral(WebViewTest* test, gconstpointer)
+{
+ GRefPtr<WebKitWebsiteDataManager> manager = adoptGRef(webkit_website_data_manager_new_ephemeral());
+ g_assert(webkit_website_data_manager_is_ephemeral(manager.get()));
+ g_assert(!webkit_website_data_manager_get_base_data_directory(manager.get()));
+ g_assert(!webkit_website_data_manager_get_base_cache_directory(manager.get()));
+ g_assert(!webkit_website_data_manager_get_local_storage_directory(manager.get()));
+ g_assert(!webkit_website_data_manager_get_disk_cache_directory(manager.get()));
+ g_assert(!webkit_website_data_manager_get_offline_application_cache_directory(manager.get()));
+ g_assert(!webkit_website_data_manager_get_indexeddb_directory(manager.get()));
+ g_assert(!webkit_website_data_manager_get_websql_directory(manager.get()));
+
+ // Configuration is ignored when is-ephemeral is used.
+ manager = adoptGRef(WEBKIT_WEBSITE_DATA_MANAGER(g_object_new(WEBKIT_TYPE_WEBSITE_DATA_MANAGER, "base-data-directory", Test::dataDirectory(), "is-ephemeral", TRUE, nullptr)));
+ g_assert(webkit_website_data_manager_is_ephemeral(manager.get()));
+ g_assert(!webkit_website_data_manager_get_base_data_directory(manager.get()));
+
+ // Non persistent data can be queried in an ephemeral manager.
+ GRefPtr<WebKitWebContext> webContext = adoptGRef(webkit_web_context_new_with_website_data_manager(manager.get()));
+ g_assert(webkit_web_context_is_ephemeral(webContext.get()));
+ GRefPtr<WebKitWebView> webView = WEBKIT_WEB_VIEW(webkit_web_view_new_with_context(webContext.get()));
+ g_assert(webkit_web_view_is_ephemeral(webView.get()));
+ g_assert(webkit_web_view_get_website_data_manager(webView.get()) == manager.get());
+
+ g_signal_connect(webView.get(), "load-changed", G_CALLBACK(ephemeralViewloadChanged), test);
+ webkit_web_view_load_uri(webView.get(), kServer->getURIForPath("/empty").data());
+ g_main_loop_run(test->m_mainLoop);
+
+ webkit_website_data_manager_fetch(manager.get(), WEBKIT_WEBSITE_DATA_MEMORY_CACHE, nullptr, [](GObject* manager, GAsyncResult* result, gpointer userData) {
+ auto* test = static_cast<WebViewTest*>(userData);
+ GList* dataList = webkit_website_data_manager_fetch_finish(WEBKIT_WEBSITE_DATA_MANAGER(manager), result, nullptr);
+ g_assert(dataList);
+ g_assert_cmpuint(g_list_length(dataList), ==, 1);
+ WebKitWebsiteData* data = static_cast<WebKitWebsiteData*>(dataList->data);
+ g_assert(data);
+ WebKitSecurityOrigin* origin = webkit_security_origin_new_for_uri(kServer->getURIForPath("/").data());
+ g_assert_cmpstr(webkit_website_data_get_name(data), ==, webkit_security_origin_get_host(origin));
+ webkit_security_origin_unref(origin);
+ g_list_free_full(dataList, reinterpret_cast<GDestroyNotify>(webkit_website_data_unref));
+ test->quitMainLoop();
+ }, test);
+ g_main_loop_run(test->m_mainLoop);
+}
+
+static void testWebsiteDataCache(WebsiteDataTest* test, gconstpointer)
+{
+ static const WebKitWebsiteDataTypes cacheTypes = static_cast<WebKitWebsiteDataTypes>(WEBKIT_WEBSITE_DATA_MEMORY_CACHE | WEBKIT_WEBSITE_DATA_DISK_CACHE);
+ GList* dataList = test->fetch(cacheTypes);
+ g_assert(!dataList);
+
+ test->loadURI(kServer->getURIForPath("/empty").data());
+ test->waitUntilLoadFinished();
+
+ // Disk cache delays the storing of initial resources for 1 second to avoid
+ // affecting early page load. So, wait 1 second here to make sure resources
+ // have already been stored.
+ test->wait(1);
+
+ dataList = test->fetch(cacheTypes);
+ g_assert(dataList);
+ g_assert_cmpuint(g_list_length(dataList), ==, 1);
+ WebKitWebsiteData* data = static_cast<WebKitWebsiteData*>(dataList->data);
+ g_assert(data);
+ WebKitSecurityOrigin* origin = webkit_security_origin_new_for_uri(kServer->getURIForPath("/").data());
+ g_assert_cmpstr(webkit_website_data_get_name(data), ==, webkit_security_origin_get_host(origin));
+ webkit_security_origin_unref(origin);
+ g_assert_cmpuint(webkit_website_data_get_types(data), ==, cacheTypes);
+ // Memory cache size is unknown.
+ g_assert_cmpuint(webkit_website_data_get_size(data, WEBKIT_WEBSITE_DATA_MEMORY_CACHE), ==, 0);
+ g_assert_cmpuint(webkit_website_data_get_size(data, WEBKIT_WEBSITE_DATA_DISK_CACHE), >, 0);
+
+ // Try again but only getting disk cache.
+ dataList = test->fetch(WEBKIT_WEBSITE_DATA_DISK_CACHE);
+ g_assert(dataList);
+ g_assert_cmpuint(g_list_length(dataList), ==, 1);
+ data = static_cast<WebKitWebsiteData*>(dataList->data);
+ g_assert(data);
+ g_assert(webkit_website_data_get_types(data) & WEBKIT_WEBSITE_DATA_DISK_CACHE);
+ g_assert(!(webkit_website_data_get_types(data) & WEBKIT_WEBSITE_DATA_MEMORY_CACHE));
+
+ GUniquePtr<char> fileURL(g_strdup_printf("file://%s/simple.html", Test::getResourcesDir(Test::WebKit2Resources).data()));
+ test->loadURI(fileURL.get());
+ test->waitUntilLoadFinished();
+
+ fileURL.reset(g_strdup_printf("file://%s/simple2.html", Test::getResourcesDir(Test::WebKit2Resources).data()));
+ test->loadURI(fileURL.get());
+ test->waitUntilLoadFinished();
+
+ // Local files are grouped.
+ dataList = test->fetch(cacheTypes);
+ g_assert(dataList);
+ g_assert_cmpuint(g_list_length(dataList), ==, 2);
+ GList* itemList = g_list_find_custom(dataList, nullptr, [](gconstpointer item, gconstpointer) -> int {
+ WebKitWebsiteData* data = static_cast<WebKitWebsiteData*>(const_cast<gpointer>(item));
+ return g_strcmp0(webkit_website_data_get_name(data), "Local files");
+ });
+ g_assert(itemList);
+ data = static_cast<WebKitWebsiteData*>(itemList->data);
+ g_assert(data);
+ g_assert(webkit_website_data_get_types(data) & WEBKIT_WEBSITE_DATA_MEMORY_CACHE);
+ // Local files are never stored in disk cache.
+ g_assert(!(webkit_website_data_get_types(data) & WEBKIT_WEBSITE_DATA_DISK_CACHE));
+
+ // Clear data modified since the last microsecond should not clear anything.
+ // Use disk-cache because memory cache ignores the modified since.
+ test->clear(WEBKIT_WEBSITE_DATA_DISK_CACHE, 1);
+ dataList = test->fetch(cacheTypes);
+ g_assert(dataList);
+ g_assert_cmpuint(g_list_length(dataList), ==, 2);
+
+ // Remove memory cache only for local files.
+ itemList = g_list_find_custom(dataList, nullptr, [](gconstpointer item, gconstpointer) -> int {
+ WebKitWebsiteData* data = static_cast<WebKitWebsiteData*>(const_cast<gpointer>(item));
+ return g_strcmp0(webkit_website_data_get_name(data), "Local files");
+ });
+ g_assert(itemList);
+ GList removeList = { itemList->data, nullptr, nullptr };
+ test->remove(WEBKIT_WEBSITE_DATA_MEMORY_CACHE, &removeList);
+ dataList = test->fetch(cacheTypes);
+ g_assert(dataList);
+ g_assert_cmpuint(g_list_length(dataList), ==, 1);
+ data = static_cast<WebKitWebsiteData*>(dataList->data);
+ g_assert(webkit_website_data_get_types(data) & WEBKIT_WEBSITE_DATA_DISK_CACHE);
+
+ // Clear all.
+ test->clear(cacheTypes, 0);
+ dataList = test->fetch(cacheTypes);
+ g_assert(!dataList);
+}
+
+static void testWebsiteDataStorage(WebsiteDataTest* test, gconstpointer)
+{
+ static const WebKitWebsiteDataTypes storageTypes = static_cast<WebKitWebsiteDataTypes>(WEBKIT_WEBSITE_DATA_SESSION_STORAGE | WEBKIT_WEBSITE_DATA_LOCAL_STORAGE);
+ GList* dataList = test->fetch(storageTypes);
+ g_assert(!dataList);
+
+ test->loadURI(kServer->getURIForPath("/sessionstorage").data());
+ test->waitUntilLoadFinished();
+
+ test->loadURI(kServer->getURIForPath("/localstorage").data());
+ test->waitUntilLoadFinished();
+
+ // Local storage uses a 1 second timer to update the database.
+ test->wait(1);
+
+ dataList = test->fetch(storageTypes);
+ g_assert(dataList);
+ g_assert_cmpuint(g_list_length(dataList), ==, 1);
+ WebKitWebsiteData* data = static_cast<WebKitWebsiteData*>(dataList->data);
+ g_assert(data);
+ WebKitSecurityOrigin* origin = webkit_security_origin_new_for_uri(kServer->getURIForPath("/").data());
+ g_assert_cmpstr(webkit_website_data_get_name(data), ==, webkit_security_origin_get_host(origin));
+ webkit_security_origin_unref(origin);
+ g_assert_cmpuint(webkit_website_data_get_types(data), ==, storageTypes);
+ // Storage sizes are unknown.
+ g_assert_cmpuint(webkit_website_data_get_size(data, WEBKIT_WEBSITE_DATA_SESSION_STORAGE), ==, 0);
+ g_assert_cmpuint(webkit_website_data_get_size(data, WEBKIT_WEBSITE_DATA_LOCAL_STORAGE), ==, 0);
+
+ // Get also cached data, and clear it.
+ static const WebKitWebsiteDataTypes cacheAndStorageTypes = static_cast<WebKitWebsiteDataTypes>(storageTypes | WEBKIT_WEBSITE_DATA_MEMORY_CACHE | WEBKIT_WEBSITE_DATA_DISK_CACHE);
+ dataList = test->fetch(cacheAndStorageTypes);
+ g_assert(dataList);
+ g_assert_cmpuint(g_list_length(dataList), ==, 1);
+ data = static_cast<WebKitWebsiteData*>(dataList->data);
+ g_assert(data);
+ g_assert_cmpuint(webkit_website_data_get_types(data), ==, cacheAndStorageTypes);
+ test->clear(static_cast<WebKitWebsiteDataTypes>(WEBKIT_WEBSITE_DATA_MEMORY_CACHE | WEBKIT_WEBSITE_DATA_DISK_CACHE), 0);
+
+ // Get all types again, but only storage is retrieved now.
+ dataList = test->fetch(cacheAndStorageTypes);
+ g_assert(dataList);
+ g_assert_cmpuint(g_list_length(dataList), ==, 1);
+ data = static_cast<WebKitWebsiteData*>(dataList->data);
+ g_assert(data);
+ g_assert_cmpuint(webkit_website_data_get_types(data), ==, storageTypes);
+
+ // Remove the session storage.
+ GList removeList = { data, nullptr, nullptr };
+ test->remove(WEBKIT_WEBSITE_DATA_SESSION_STORAGE, &removeList);
+ dataList = test->fetch(storageTypes);
+ g_assert(dataList);
+ g_assert_cmpuint(g_list_length(dataList), ==, 1);
+ data = static_cast<WebKitWebsiteData*>(dataList->data);
+ g_assert(!(webkit_website_data_get_types(data) & WEBKIT_WEBSITE_DATA_SESSION_STORAGE));
+ g_assert(webkit_website_data_get_types(data) & WEBKIT_WEBSITE_DATA_LOCAL_STORAGE);
+
+ // Clear all.
+ test->clear(cacheAndStorageTypes, 0);
+ dataList = test->fetch(cacheAndStorageTypes);
+ g_assert(!dataList);
+}
+
+static void testWebsiteDataDatabases(WebsiteDataTest* test, gconstpointer)
+{
+ static const WebKitWebsiteDataTypes databaseTypes = static_cast<WebKitWebsiteDataTypes>(WEBKIT_WEBSITE_DATA_WEBSQL_DATABASES | WEBKIT_WEBSITE_DATA_INDEXEDDB_DATABASES);
+ GList* dataList = test->fetch(databaseTypes);
+ g_assert(!dataList);
+
+ test->loadURI(kServer->getURIForPath("/empty").data());
+ test->waitUntilLoadFinished();
+ test->runJavaScriptAndWaitUntilFinished("window.indexedDB.open('TestDatabase');", nullptr);
+
+ dataList = test->fetch(databaseTypes);
+ g_assert(dataList);
+ g_assert_cmpuint(g_list_length(dataList), ==, 1);
+ WebKitWebsiteData* data = static_cast<WebKitWebsiteData*>(dataList->data);
+ g_assert(data);
+ WebKitSecurityOrigin* origin = webkit_security_origin_new_for_uri(kServer->getURIForPath("/").data());
+ g_assert_cmpstr(webkit_website_data_get_name(data), ==, webkit_security_origin_get_host(origin));
+ webkit_security_origin_unref(origin);
+ g_assert_cmpuint(webkit_website_data_get_types(data), ==, WEBKIT_WEBSITE_DATA_INDEXEDDB_DATABASES);
+ // Database sizes are unknown.
+ g_assert_cmpuint(webkit_website_data_get_size(data, WEBKIT_WEBSITE_DATA_INDEXEDDB_DATABASES), ==, 0);
+
+ test->runJavaScriptAndWaitUntilFinished("db = openDatabase(\"TestDatabase\", \"1.0\", \"TestDatabase\", 1);", nullptr);
+ dataList = test->fetch(databaseTypes);
+ g_assert(dataList);
+ g_assert_cmpuint(g_list_length(dataList), ==, 1);
+ data = static_cast<WebKitWebsiteData*>(dataList->data);
+ g_assert(data);
+ g_assert_cmpuint(webkit_website_data_get_types(data), ==, databaseTypes);
+ // Database sizes are unknown.
+ g_assert_cmpuint(webkit_website_data_get_size(data, WEBKIT_WEBSITE_DATA_INDEXEDDB_DATABASES), ==, 0);
+ g_assert_cmpuint(webkit_website_data_get_size(data, WEBKIT_WEBSITE_DATA_WEBSQL_DATABASES), ==, 0);
+
+ // Remove all databases at once.
+ GList removeList = { data, nullptr, nullptr };
+ test->remove(databaseTypes, &removeList);
+ dataList = test->fetch(databaseTypes);
+ g_assert(!dataList);
+
+ // Clear all.
+ static const WebKitWebsiteDataTypes cacheAndDatabaseTypes = static_cast<WebKitWebsiteDataTypes>(databaseTypes | WEBKIT_WEBSITE_DATA_MEMORY_CACHE | WEBKIT_WEBSITE_DATA_DISK_CACHE);
+ test->clear(cacheAndDatabaseTypes, 0);
+ dataList = test->fetch(cacheAndDatabaseTypes);
+ g_assert(!dataList);
+}
+
+static void testWebsiteDataAppcache(WebsiteDataTest* test, gconstpointer)
+{
+ GList* dataList = test->fetch(WEBKIT_WEBSITE_DATA_OFFLINE_APPLICATION_CACHE);
+ g_assert(!dataList);
+
+ test->loadURI(kServer->getURIForPath("/appcache").data());
+ test->waitUntilLoadFinished();
+
+ test->wait(1);
+ dataList = test->fetch(WEBKIT_WEBSITE_DATA_OFFLINE_APPLICATION_CACHE);
+ g_assert(dataList);
+ g_assert_cmpuint(g_list_length(dataList), ==, 1);
+ WebKitWebsiteData* data = static_cast<WebKitWebsiteData*>(dataList->data);
+ g_assert(data);
+ WebKitSecurityOrigin* origin = webkit_security_origin_new_for_uri(kServer->getURIForPath("/").data());
+ g_assert_cmpstr(webkit_website_data_get_name(data), ==, webkit_security_origin_get_host(origin));
+ webkit_security_origin_unref(origin);
+ g_assert_cmpuint(webkit_website_data_get_types(data), ==, WEBKIT_WEBSITE_DATA_OFFLINE_APPLICATION_CACHE);
+ // Appcache size is unknown.
+ g_assert_cmpuint(webkit_website_data_get_size(data, WEBKIT_WEBSITE_DATA_OFFLINE_APPLICATION_CACHE), ==, 0);
+
+ GList removeList = { data, nullptr, nullptr };
+ test->remove(WEBKIT_WEBSITE_DATA_OFFLINE_APPLICATION_CACHE, &removeList);
+ dataList = test->fetch(WEBKIT_WEBSITE_DATA_OFFLINE_APPLICATION_CACHE);
+ g_assert(!dataList);
+
+ // Clear all.
+ static const WebKitWebsiteDataTypes cacheAndAppcacheTypes = static_cast<WebKitWebsiteDataTypes>(WEBKIT_WEBSITE_DATA_OFFLINE_APPLICATION_CACHE | WEBKIT_WEBSITE_DATA_MEMORY_CACHE | WEBKIT_WEBSITE_DATA_DISK_CACHE);
+ test->clear(cacheAndAppcacheTypes, 0);
+ dataList = test->fetch(cacheAndAppcacheTypes);
+ g_assert(!dataList);
+}
+
+static void testWebsiteDataCookies(WebsiteDataTest* test, gconstpointer)
+{
+ GList* dataList = test->fetch(WEBKIT_WEBSITE_DATA_COOKIES);
+ g_assert(!dataList);
+
+ test->loadURI(kServer->getURIForPath("/empty").data());
+ test->waitUntilLoadFinished();
+
+ dataList = test->fetch(WEBKIT_WEBSITE_DATA_COOKIES);
+ g_assert(dataList);
+ g_assert_cmpuint(g_list_length(dataList), ==, 1);
+ WebKitWebsiteData* data = static_cast<WebKitWebsiteData*>(dataList->data);
+ g_assert(data);
+ g_assert_cmpstr(webkit_website_data_get_name(data), ==, "127.0.0.1");
+ g_assert_cmpuint(webkit_website_data_get_types(data), ==, WEBKIT_WEBSITE_DATA_COOKIES);
+ // Cookies size is unknown.
+ g_assert_cmpuint(webkit_website_data_get_size(data, WEBKIT_WEBSITE_DATA_COOKIES), ==, 0);
+
+ GList removeList = { data, nullptr, nullptr };
+ test->remove(WEBKIT_WEBSITE_DATA_COOKIES, &removeList);
+ dataList = test->fetch(WEBKIT_WEBSITE_DATA_COOKIES);
+ g_assert(!dataList);
+
+ // Clear all.
+ static const WebKitWebsiteDataTypes cacheAndCookieTypes = static_cast<WebKitWebsiteDataTypes>(WEBKIT_WEBSITE_DATA_COOKIES | WEBKIT_WEBSITE_DATA_MEMORY_CACHE | WEBKIT_WEBSITE_DATA_DISK_CACHE);
+ test->clear(cacheAndCookieTypes, 0);
+ dataList = test->fetch(cacheAndCookieTypes);
+ g_assert(!dataList);
+}
+
+void beforeAll()
+{
+ kServer = new WebKitTestServer();
+ kServer->run(serverCallback);
+
+ WebsiteDataTest::add("WebKitWebsiteData", "configuration", testWebsiteDataConfiguration);
+ WebViewTest::add("WebKitWebsiteData", "ephemeral", testWebsiteDataEphemeral);
+ WebsiteDataTest::add("WebKitWebsiteData", "cache", testWebsiteDataCache);
+ WebsiteDataTest::add("WebKitWebsiteData", "storage", testWebsiteDataStorage);
+ WebsiteDataTest::add("WebKitWebsiteData", "databases", testWebsiteDataDatabases);
+ WebsiteDataTest::add("WebKitWebsiteData", "appcache", testWebsiteDataAppcache);
+ WebsiteDataTest::add("WebKitWebsiteData", "cookies", testWebsiteDataCookies);
+}
+
+void afterAll()
+{
+ delete kServer;
+}
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebExtensionTest.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebExtensionTest.cpp
index 757532f7a..f632bc371 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebExtensionTest.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebExtensionTest.cpp
@@ -22,15 +22,14 @@
#include <JavaScriptCore/JSContextRef.h>
#include <JavaScriptCore/JSRetainPtr.h>
#include <gio/gio.h>
+#include <gst/gst.h>
#include <stdlib.h>
#include <string.h>
#include <webkit2/webkit-web-extension.h>
#include <wtf/Deque.h>
-#include <wtf/OwnPtr.h>
-#include <wtf/PassOwnPtr.h>
#include <wtf/ProcessID.h>
-#include <wtf/gobject/GRefPtr.h>
-#include <wtf/gobject/GUniquePtr.h>
+#include <wtf/glib/GRefPtr.h>
+#include <wtf/glib/GUniquePtr.h>
#include <wtf/text/CString.h>
static const char introspectionXML[] =
@@ -46,25 +45,26 @@ static const char introspectionXML[] =
" <arg type='t' name='pageID' direction='in'/>"
" <arg type='s' name='script' direction='in'/>"
" </method>"
- " <method name='GetInitializationUserData'>"
- " <arg type='s' name='userData' direction='out'/>"
- " </method>"
" <method name='GetProcessIdentifier'>"
" <arg type='u' name='identifier' direction='out'/>"
" </method>"
+ " <method name='RemoveAVPluginsFromGSTRegistry'>"
+ " </method>"
" <signal name='DocumentLoaded'/>"
+ " <signal name='FormControlsAssociated'>"
+ " <arg type='s' name='formIds' direction='out'/>"
+ " </signal>"
" <signal name='URIChanged'>"
" <arg type='s' name='uri' direction='out'/>"
" </signal>"
" </interface>"
"</node>";
-static GRefPtr<GVariant> initializationUserData;
-
typedef enum {
DocumentLoadedSignal,
URIChangedSignal,
+ FormControlsAssociatedSignal,
} DelayedSignalType;
struct DelayedSignal {
@@ -73,17 +73,17 @@ struct DelayedSignal {
{
}
- DelayedSignal(DelayedSignalType type, const char* uri)
+ DelayedSignal(DelayedSignalType type, const char* str)
: type(type)
- , uri(uri)
+ , str(str)
{
}
DelayedSignalType type;
- CString uri;
+ CString str;
};
-Deque<OwnPtr<DelayedSignal>> delayedSignalsQueue;
+Deque<DelayedSignal> delayedSignalsQueue;
static void emitDocumentLoaded(GDBusConnection* connection)
{
@@ -98,13 +98,17 @@ static void emitDocumentLoaded(GDBusConnection* connection)
g_assert(ok);
}
-static void documentLoadedCallback(WebKitWebPage*, WebKitWebExtension* extension)
+static void documentLoadedCallback(WebKitWebPage* webPage, WebKitWebExtension* extension)
{
+ WebKitDOMDocument* document = webkit_web_page_get_dom_document(webPage);
+ GRefPtr<WebKitDOMDOMWindow> window = adoptGRef(webkit_dom_document_get_default_view(document));
+ webkit_dom_dom_window_webkit_message_handlers_post_message(window.get(), "dom", "DocumentLoaded");
+
gpointer data = g_object_get_data(G_OBJECT(extension), "dbus-connection");
if (data)
emitDocumentLoaded(G_DBUS_CONNECTION(data));
else
- delayedSignalsQueue.append(adoptPtr(new DelayedSignal(DocumentLoadedSignal)));
+ delayedSignalsQueue.append(DelayedSignal(DocumentLoadedSignal));
}
static void emitURIChanged(GDBusConnection* connection, const char* uri)
@@ -126,11 +130,12 @@ static void uriChangedCallback(WebKitWebPage* webPage, GParamSpec* pspec, WebKit
if (data)
emitURIChanged(G_DBUS_CONNECTION(data), webkit_web_page_get_uri(webPage));
else
- delayedSignalsQueue.append(adoptPtr(new DelayedSignal(URIChangedSignal, webkit_web_page_get_uri(webPage))));
+ delayedSignalsQueue.append(DelayedSignal(URIChangedSignal, webkit_web_page_get_uri(webPage)));
}
static gboolean sendRequestCallback(WebKitWebPage*, WebKitURIRequest* request, WebKitURIResponse* redirectResponse, gpointer)
{
+ gboolean returnValue = FALSE;
const char* requestURI = webkit_uri_request_get_uri(request);
g_assert(requestURI);
@@ -153,17 +158,128 @@ static gboolean sendRequestCallback(WebKitWebPage*, WebKitURIRequest* request, W
SoupMessageHeaders* headers = webkit_uri_request_get_http_headers(request);
g_assert(headers);
soup_message_headers_append(headers, "DNT", "1");
+ } else if (g_str_has_suffix(requestURI, "/normal-change-request")) {
+ GUniquePtr<char> prefix(g_strndup(requestURI, strlen(requestURI) - strlen("/normal-change-request")));
+ GUniquePtr<char> newURI(g_strdup_printf("%s/request-changed%s", prefix.get(), redirectResponse ? "-on-redirect" : ""));
+ webkit_uri_request_set_uri(request, newURI.get());
+ } else if (g_str_has_suffix(requestURI, "/http-get-method")) {
+ g_assert_cmpstr(webkit_uri_request_get_http_method(request), ==, "GET");
+ g_assert(webkit_uri_request_get_http_method(request) == SOUP_METHOD_GET);
+ } else if (g_str_has_suffix(requestURI, "/http-post-method")) {
+ g_assert_cmpstr(webkit_uri_request_get_http_method(request), ==, "POST");
+ g_assert(webkit_uri_request_get_http_method(request) == SOUP_METHOD_POST);
+ returnValue = TRUE;
} else if (g_str_has_suffix(requestURI, "/cancel-this.js"))
+ returnValue = TRUE;
+
+ return returnValue;
+}
+
+static GVariant* serializeContextMenu(WebKitContextMenu* menu)
+{
+ GVariantBuilder builder;
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
+ GList* items = webkit_context_menu_get_items(menu);
+ for (GList* it = items; it; it = g_list_next(it))
+ g_variant_builder_add(&builder, "u", webkit_context_menu_item_get_stock_action(WEBKIT_CONTEXT_MENU_ITEM(it->data)));
+ return g_variant_builder_end(&builder);
+}
+
+static GVariant* serializeNode(WebKitDOMNode* node)
+{
+ GVariantBuilder builder;
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_add(&builder, "{sv}", "Name", g_variant_new_take_string(webkit_dom_node_get_node_name(node)));
+ g_variant_builder_add(&builder, "{sv}", "Type", g_variant_new_uint32(webkit_dom_node_get_node_type(node)));
+ g_variant_builder_add(&builder, "{sv}", "Contents", g_variant_new_take_string(webkit_dom_node_get_text_content(node)));
+ WebKitDOMNode* parent = webkit_dom_node_get_parent_node(node);
+ g_variant_builder_add(&builder, "{sv}", "Parent", parent ? g_variant_new_take_string(webkit_dom_node_get_node_name(parent)) : g_variant_new_string("ROOT"));
+ return g_variant_builder_end(&builder);
+}
+
+static gboolean contextMenuCallback(WebKitWebPage* page, WebKitContextMenu* menu, WebKitWebHitTestResult* hitTestResult, gpointer)
+{
+ const char* pageURI = webkit_web_page_get_uri(page);
+ if (!g_strcmp0(pageURI, "ContextMenuTestDefault")) {
+ webkit_context_menu_set_user_data(menu, serializeContextMenu(menu));
+ return FALSE;
+ }
+
+ if (!g_strcmp0(pageURI, "ContextMenuTestCustom")) {
+ // Remove Back and Forward, and add Inspector action.
+ webkit_context_menu_remove(menu, webkit_context_menu_first(menu));
+ webkit_context_menu_remove(menu, webkit_context_menu_first(menu));
+ webkit_context_menu_append(menu, webkit_context_menu_item_new_separator());
+ webkit_context_menu_append(menu, webkit_context_menu_item_new_from_stock_action(WEBKIT_CONTEXT_MENU_ACTION_INSPECT_ELEMENT));
+ webkit_context_menu_set_user_data(menu, serializeContextMenu(menu));
+ return TRUE;
+ }
+
+ if (!g_strcmp0(pageURI, "ContextMenuTestClear")) {
+ webkit_context_menu_remove_all(menu);
+ return TRUE;
+ }
+
+ if (!g_strcmp0(pageURI, "ContextMenuTestNode")) {
+ WebKitDOMNode* node = webkit_web_hit_test_result_get_node(hitTestResult);
+ g_assert(WEBKIT_DOM_IS_NODE(node));
+ webkit_context_menu_set_user_data(menu, serializeNode(node));
return TRUE;
+ }
return FALSE;
}
+static void consoleMessageSentCallback(WebKitWebPage* webPage, WebKitConsoleMessage* consoleMessage)
+{
+ g_assert(consoleMessage);
+ GRefPtr<GVariant> variant = g_variant_new("(uusus)", webkit_console_message_get_source(consoleMessage),
+ webkit_console_message_get_level(consoleMessage), webkit_console_message_get_text(consoleMessage),
+ webkit_console_message_get_line(consoleMessage), webkit_console_message_get_source_id(consoleMessage));
+ GUniquePtr<char> messageString(g_variant_print(variant.get(), FALSE));
+ GRefPtr<WebKitDOMDOMWindow> window = adoptGRef(webkit_dom_document_get_default_view(webkit_web_page_get_dom_document(webPage)));
+ g_assert(WEBKIT_DOM_IS_DOM_WINDOW(window.get()));
+ webkit_dom_dom_window_webkit_message_handlers_post_message(window.get(), "console", messageString.get());
+}
+
+
+static void emitFormControlsAssociated(GDBusConnection* connection, const char* formIds)
+{
+ bool ok = g_dbus_connection_emit_signal(
+ connection,
+ nullptr,
+ "/org/webkit/gtk/WebExtensionTest",
+ "org.webkit.gtk.WebExtensionTest",
+ "FormControlsAssociated",
+ g_variant_new("(s)", formIds),
+ nullptr);
+ g_assert(ok);
+}
+
+static void formControlsAssociatedCallback(WebKitWebPage* webPage, GPtrArray* formElements, WebKitWebExtension* extension)
+{
+ GString* formIdsBuilder = g_string_new(nullptr);
+ for (int i = 0; i < formElements->len; ++i) {
+ g_assert(WEBKIT_DOM_IS_ELEMENT(g_ptr_array_index(formElements, i)));
+ auto domElement = WEBKIT_DOM_ELEMENT(g_ptr_array_index(formElements, i));
+ g_string_append(formIdsBuilder, webkit_dom_element_get_id(domElement));
+ }
+ GUniquePtr<char> formIds(g_string_free(formIdsBuilder, FALSE));
+ gpointer data = g_object_get_data(G_OBJECT(extension), "dbus-connection");
+ if (data)
+ emitFormControlsAssociated(G_DBUS_CONNECTION(data), formIds.get());
+ else
+ delayedSignalsQueue.append(DelayedSignal(FormControlsAssociatedSignal, formIds.get()));
+}
+
static void pageCreatedCallback(WebKitWebExtension* extension, WebKitWebPage* webPage, gpointer)
{
g_signal_connect(webPage, "document-loaded", G_CALLBACK(documentLoadedCallback), extension);
g_signal_connect(webPage, "notify::uri", G_CALLBACK(uriChangedCallback), extension);
- g_signal_connect(webPage, "send-request", G_CALLBACK(sendRequestCallback), 0);
+ g_signal_connect(webPage, "send-request", G_CALLBACK(sendRequestCallback), nullptr);
+ g_signal_connect(webPage, "context-menu", G_CALLBACK(contextMenuCallback), nullptr);
+ g_signal_connect(webPage, "console-message-sent", G_CALLBACK(consoleMessageSentCallback), nullptr);
+ g_signal_connect(webPage, "form-controls-associated", G_CALLBACK(formControlsAssociatedCallback), extension);
}
static JSValueRef echoCallback(JSContextRef jsContext, JSObjectRef, JSObjectRef, size_t argumentCount, const JSValueRef arguments[], JSValueRef*)
@@ -233,14 +349,20 @@ static void methodCallCallback(GDBusConnection* connection, const char* sender,
g_dbus_method_invocation_return_value(invocation, 0);
} else if (!g_strcmp0(methodName, "AbortProcess")) {
abort();
- } else if (!g_strcmp0(methodName, "GetInitializationUserData")) {
- g_assert(initializationUserData);
- g_assert(g_variant_is_of_type(initializationUserData.get(), G_VARIANT_TYPE_STRING));
- g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)",
- g_variant_get_string(initializationUserData.get(), nullptr)));
} else if (!g_strcmp0(methodName, "GetProcessIdentifier")) {
g_dbus_method_invocation_return_value(invocation,
g_variant_new("(u)", static_cast<guint32>(getCurrentProcessID())));
+ } else if (!g_strcmp0(methodName, "RemoveAVPluginsFromGSTRegistry")) {
+ gst_init(nullptr, nullptr);
+ static const char* avPlugins[] = { "libav", "omx", "vaapi", nullptr };
+ GstRegistry* registry = gst_registry_get();
+ for (unsigned i = 0; avPlugins[i]; ++i) {
+ if (GstPlugin* plugin = gst_registry_find_plugin(registry, avPlugins[i])) {
+ gst_registry_remove_plugin(registry, plugin);
+ gst_object_unref(plugin);
+ }
+ }
+ g_dbus_method_invocation_return_value(invocation, nullptr);
}
}
@@ -268,38 +390,41 @@ static void busAcquiredCallback(GDBusConnection* connection, const char* name, g
g_object_set_data(G_OBJECT(userData), "dbus-connection", connection);
while (delayedSignalsQueue.size()) {
- OwnPtr<DelayedSignal> delayedSignal = delayedSignalsQueue.takeFirst();
- switch (delayedSignal->type) {
+ DelayedSignal delayedSignal = delayedSignalsQueue.takeFirst();
+ switch (delayedSignal.type) {
case DocumentLoadedSignal:
emitDocumentLoaded(connection);
break;
case URIChangedSignal:
- emitURIChanged(connection, delayedSignal->uri.data());
+ emitURIChanged(connection, delayedSignal.str.data());
+ break;
+ case FormControlsAssociatedSignal:
+ emitFormControlsAssociated(connection, delayedSignal.str.data());
break;
}
}
}
-static GUniquePtr<char> makeBusName(GVariant* userData)
+static void registerGResource(void)
{
- // When the web extension is used by TestMultiprocess, an uint32
- // identifier is passed as user data. It uniquely identifies
- // the web process, and the UI side expects it added as suffix to
- // the bus name.
- if (userData && g_variant_is_of_type(userData, G_VARIANT_TYPE_UINT32))
- return GUniquePtr<char>(g_strdup_printf("org.webkit.gtk.WebExtensionTest%u", g_variant_get_uint32(userData)));
-
- return GUniquePtr<char>(g_strdup("org.webkit.gtk.WebExtensionTest"));
+ GUniquePtr<char> resourcesPath(g_build_filename(WEBKIT_EXEC_PATH, "TestWebKitAPI", "WebKit2Gtk", "resources", "webkit2gtk-tests-resources.gresource", nullptr));
+ GResource* resource = g_resource_load(resourcesPath.get(), nullptr);
+ g_assert(resource);
+
+ g_resources_register(resource);
+ g_resource_unref(resource);
}
extern "C" void webkit_web_extension_initialize_with_user_data(WebKitWebExtension* extension, GVariant* userData)
{
- initializationUserData = userData;
-
g_signal_connect(extension, "page-created", G_CALLBACK(pageCreatedCallback), extension);
g_signal_connect(webkit_script_world_get_default(), "window-object-cleared", G_CALLBACK(windowObjectCleared), 0);
- GUniquePtr<char> busName(makeBusName(userData));
+ registerGResource();
+
+ g_assert(userData);
+ g_assert(g_variant_is_of_type(userData, G_VARIANT_TYPE_UINT32));
+ GUniquePtr<char> busName(g_strdup_printf("org.webkit.gtk.WebExtensionTest%u", g_variant_get_uint32(userData)));
g_bus_own_name(
G_BUS_TYPE_SESSION,
busName.get(),
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebProcessTest.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebProcessTest.cpp
index 09d0785aa..bc058693d 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebProcessTest.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebProcessTest.cpp
@@ -22,8 +22,11 @@
#include <JavaScriptCore/JSRetainPtr.h>
#include <gio/gio.h>
+#include <wtf/HashSet.h>
#include <wtf/NeverDestroyed.h>
-#include <wtf/gobject/GUniquePtr.h>
+#include <wtf/glib/GUniquePtr.h>
+
+static HashSet<GObject*> s_watchedObjects;
typedef HashMap<String, std::function<std::unique_ptr<WebProcessTest> ()>> TestsMap;
static TestsMap& testsMap()
@@ -34,7 +37,15 @@ static TestsMap& testsMap()
void WebProcessTest::add(const String& testName, std::function<std::unique_ptr<WebProcessTest> ()> closure)
{
- testsMap().add(testName, std::move(closure));
+ testsMap().add(testName, WTFMove(closure));
+}
+
+void WebProcessTest::assertObjectIsDeletedWhenTestFinishes(GObject* object)
+{
+ s_watchedObjects.add(object);
+ g_object_weak_ref(object, [](gpointer, GObject* finalizedObject) {
+ s_watchedObjects.remove(finalizedObject);
+ }, nullptr);
}
std::unique_ptr<WebProcessTest> WebProcessTest::create(const String& testName)
@@ -53,6 +64,14 @@ static JSValueRef runTest(JSContextRef context, JSObjectRef function, JSObjectRe
WebKitWebPage* webPage = WEBKIT_WEB_PAGE(JSObjectGetPrivate(thisObject));
g_assert(WEBKIT_IS_WEB_PAGE(webPage));
+ // Test /WebKitDOMNode/dom-cache is an exception, because it's called 3 times, so
+ // the WebPage is destroyed after the third time.
+ if (g_str_equal(testPath.get(), "WebKitDOMNode/dom-cache")) {
+ static unsigned domCacheTestRunCount = 0;
+ if (++domCacheTestRunCount == 3)
+ WebProcessTest::assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webPage));
+ } else
+ WebProcessTest::assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webPage));
std::unique_ptr<WebProcessTest> test = WebProcessTest::create(String::fromUTF8(testPath.get()));
return JSValueMakeBoolean(context, test->runTest(g_strrstr(testPath.get(), "/") + 1, webPage));
@@ -67,6 +86,16 @@ static const JSStaticFunction webProcessTestRunnerStaticFunctions[] =
static void webProcessTestRunnerFinalize(JSObjectRef object)
{
g_object_unref(JSObjectGetPrivate(object));
+
+ if (s_watchedObjects.isEmpty())
+ return;
+
+ g_print("Leaked objects in WebProcess:");
+ for (const auto object : s_watchedObjects)
+ g_print(" %s(%p)", g_type_name_from_instance(reinterpret_cast<GTypeInstance*>(object)), object);
+ g_print("\n");
+
+ g_assert(s_watchedObjects.isEmpty());
}
static void windowObjectClearedCallback(WebKitScriptWorld* world, WebKitWebPage* webPage, WebKitFrame* frame, WebKitWebExtension* extension)
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebProcessTest.h b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebProcessTest.h
index fb4dd5d33..3715eb91e 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebProcessTest.h
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebProcessTest.h
@@ -19,7 +19,7 @@
#include <webkit2/webkit-web-extension.h>
#include <wtf/HashMap.h>
-#include <wtf/gobject/GRefPtr.h>
+#include <wtf/glib/GRefPtr.h>
#include <wtf/text/StringHash.h>
#include <wtf/text/WTFString.h>
@@ -28,6 +28,8 @@ public:
virtual ~WebProcessTest() { }
virtual bool runTest(const char* testName, WebKitWebPage*) = 0;
+ static void assertObjectIsDeletedWhenTestFinishes(GObject*);
+
static void add(const String& testName, std::function<std::unique_ptr<WebProcessTest> ()>);
static std::unique_ptr<WebProcessTest> create(const String& testName);
};
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/blank.ico b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/blank.ico
new file mode 100644
index 000000000..ea848b991
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/blank.ico
Binary files differ
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/boring.html b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/boring.html
new file mode 100644
index 000000000..c0eeb49ee
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/boring.html
@@ -0,0 +1 @@
+<p>This is a boring HTML file.</p>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/link-title.js b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/link-title.js
new file mode 100644
index 000000000..2c824da38
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/link-title.js
@@ -0,0 +1 @@
+window.document.getElementById('WebKitLink').title;
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/silence.mpg b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/silence.mpg
new file mode 100644
index 000000000..b6bbf2088
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/silence.mpg
Binary files differ
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/simple.json b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/simple.json
new file mode 100644
index 000000000..76519fa8c
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/simple.json
@@ -0,0 +1 @@
+{"key": "value"}
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/test-cert.pem b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/test-cert.pem
new file mode 100644
index 000000000..b34301f25
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/test-cert.pem
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIIB9jCCAV+gAwIBAgIJALeuXBo+vwz9MA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
+BAMMCTEyNy4wLjAuMTAeFw0xMjA3MTIxMjQ4MjRaFw0yMjA3MTAxMjQ4MjRaMBQx
+EjAQBgNVBAMMCTEyNy4wLjAuMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
+0TUzOQxHBIKDD2mkuq+tU92mQvDZg73B0G+Nhr2T2G6MbcLqIwjg1QYtBZWJ83tZ
+xMMEfiweHLF85Z9ohavAgxJlKG7YmvZO79KkFpmjV2W5CVRm0eYMPnzmxNCoaYqo
+DLl0zsH6KZOLPKu/fX4eDX9XpAP1f83hWB1UFBmHKN8CAwEAAaNQME4wHQYDVR0O
+BBYEFDHv5ZQ1BdmhzTsDUEoY55EXyUdKMB8GA1UdIwQYMBaAFDHv5ZQ1BdmhzTsD
+UEoY55EXyUdKMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAh3qMBx7v
+jSodMf3OyTqTLE7deLnmnCeBVpgzxRZEoizcGqYcjiqO27i5N5Z6KVQsnITnLiyC
+mUtuR5KnF69uTKUw4m/ugZe5whjig5Mq2l410KVK6EeG4tdLlfXR+wi4U5K4KjP6
+p4nchQUXLa2zcbJn+VBexJn6/9wdhr+DUGY=
+-----END CERTIFICATE-----
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/test-key.pem b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/test-key.pem
new file mode 100644
index 000000000..9036222ce
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/test-key.pem
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANE1MzkMRwSCgw9p
+pLqvrVPdpkLw2YO9wdBvjYa9k9hujG3C6iMI4NUGLQWVifN7WcTDBH4sHhyxfOWf
+aIWrwIMSZShu2Jr2Tu/SpBaZo1dluQlUZtHmDD585sTQqGmKqAy5dM7B+imTizyr
+v31+Hg1/V6QD9X/N4VgdVBQZhyjfAgMBAAECgYB2QwOUsRsIMprRwJ9tJNfvO7G7
+z5i1/zOrlxPC4jHMPBnIBlICwgcOhLI4oOLdr5H8R12n0VqoT7DRwP396iwlJipF
+iO1heDMn/8z8LPGwkCK/+ck04rMDksxWIdMwYKBXt9ahnJ/xRLzQ1/3AJiAGnoe5
+/QLXQweofd4mmfsjKQJBAO2CwT7uMP6nMjXgtVMJq5QP8UbeCS1sEOPJJbHuDxJB
+/HePQHBjq4kzG6CL4oO7T+5fDv4g+fIIHzuXerZ0imsCQQDhfmiTIc9OucEIfg6/
+ms0JiKSmWc+qoiOCtrILuQvFoNwJRciQANqeJs6wpaDvevSUvBLGfG/7b3HvaE5X
+iqBdAkBEQIvp2qcHtuJN60oQF7pPrRknxUyb2e8sljQX4pJAK+gyL19ULMAxiBdL
+Vod8VYqNtJFpY+6Pp9fZ1xjzb6ALAkEA4JzrDAw0lQXA+3WduUw4ixOadr2ldyG0
+36KebcDwsfZO18m0Q4UmPz0Gy7zgN0wxzuochaw0W6+iPUiYKOlEXQJBAMWQrPlu
+rrinoZS2f8doJ9BNNUa+RNpMug6UXc55qoUJlyiXEh+tu4AaMOtxuGIyC0sAcuw6
+XdAPVPXKd7Mne70=
+-----END PRIVATE KEY-----
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/track.ogg b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/track.ogg
new file mode 100644
index 000000000..c569c8f40
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/track.ogg
Binary files differ
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/webkit2gtk-tests.gresource.xml b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/webkit2gtk-tests.gresource.xml
new file mode 100644
index 000000000..87bc50158
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/webkit2gtk-tests.gresource.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/org/webkit/webkit2gtk/tests/">
+ <file alias="boring.html">Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/boring.html</file>
+ <file alias="link-title.js">Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/link-title.js</file>
+ </gresource>
+</gresources>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2ObjC/CustomProtocolsInvalidScheme_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2ObjC/CustomProtocolsInvalidScheme_Bundle.cpp
new file mode 100644
index 000000000..279ddd268
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2ObjC/CustomProtocolsInvalidScheme_Bundle.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "InjectedBundleTest.h"
+#include <WebKit/WKBundlePage.h>
+
+namespace TestWebKitAPI {
+
+static WKBundlePagePolicyAction decidePolicyForNavigationAction(WKBundlePageRef, WKBundleFrameRef, WKBundleNavigationActionRef, WKURLRequestRef request, WKTypeRef*, const void*)
+{
+ if (WKBundlePageCanHandleRequest(request))
+ return WKBundlePagePolicyActionUse;
+ return WKBundlePagePolicyActionPassThrough;
+}
+
+class CustomProtocolInvalidSchemeTest : public InjectedBundleTest {
+public:
+ CustomProtocolInvalidSchemeTest(const std::string& identifier)
+ : InjectedBundleTest(identifier)
+ {
+ }
+
+private:
+ void didCreatePage(WKBundleRef, WKBundlePageRef bundlePage) override
+ {
+ WKBundlePagePolicyClientV0 policyClient;
+ memset(&policyClient, 0, sizeof(policyClient));
+
+ policyClient.base.version = 0;
+ policyClient.decidePolicyForNavigationAction = decidePolicyForNavigationAction;
+
+ WKBundlePageSetPolicyClient(bundlePage, &policyClient.base);
+ }
+};
+
+static InjectedBundleTest::Register<CustomProtocolInvalidSchemeTest> registrar("CustomProtocolInvalidSchemeTest");
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2ObjC/PreventImageLoadWithAutoResizing_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2ObjC/PreventImageLoadWithAutoResizing_Bundle.cpp
new file mode 100644
index 000000000..dde94407a
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2ObjC/PreventImageLoadWithAutoResizing_Bundle.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_HAVE_C_SPI
+
+#include "InjectedBundleTest.h"
+#include "PlatformUtilities.h"
+#include "Test.h"
+
+#include <WebKit/WKBundlePage.h>
+
+#include <wtf/Assertions.h>
+
+namespace TestWebKitAPI {
+
+class DenyWillSendRequestTest : public InjectedBundleTest {
+public:
+ DenyWillSendRequestTest(const std::string& identifier)
+ : InjectedBundleTest(identifier)
+ {
+ }
+
+ static WKURLRequestRef willSendRequestForFrame(WKBundlePageRef, WKBundleFrameRef frame, uint64_t resourceIdentifier, WKURLRequestRef request, WKURLResponseRef redirectResponse, const void *clientInfo)
+ {
+ return 0;
+ }
+
+ virtual void didCreatePage(WKBundleRef bundle, WKBundlePageRef page)
+ {
+ WKBundlePageResourceLoadClientV0 resourceLoadClient;
+ memset(&resourceLoadClient, 0, sizeof(resourceLoadClient));
+
+ resourceLoadClient.base.version = 0;
+ resourceLoadClient.willSendRequestForFrame = willSendRequestForFrame;
+
+ WKBundlePageSetResourceLoadClient(page, &resourceLoadClient.base);
+
+ }
+};
+
+static InjectedBundleTest::Register<DenyWillSendRequestTest> registrar("DenyWillSendRequestTest");
+
+} // namespace TestWebKitAPI
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/test_utils.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/test_utils.c
deleted file mode 100644
index 6bb645d0d..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/test_utils.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2010 Arno Renevier
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "test_utils.h"
-
-#include <glib.h>
-#include <glib/gstdio.h>
-
-int testutils_relative_chdir(const gchar *targetFilename, const gchar *executablePath)
-{
- /* user can set location of the webkit repository directory if it differs from build directory */
- const gchar *repoPath = g_getenv("WEBKITREPODIR");
- if (repoPath) {
- if (g_chdir(repoPath))
- return -1;
- } else if (g_chdir(g_path_get_dirname(executablePath)))
- return -1;
-
- while (!g_file_test(targetFilename, G_FILE_TEST_EXISTS)) {
- gchar *pathName;
- if (g_chdir(".."))
- return -1;
- g_assert(!g_str_equal((pathName = g_get_current_dir()), "/"));
- g_free(pathName);
- }
-
- gchar *dirName = g_path_get_dirname(targetFilename);
- if (g_chdir(dirName)) {
- g_free(dirName);
- return -1;
- }
-
- g_free(dirName);
- return 0;
-}
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testatk.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testatk.c
deleted file mode 100644
index 2a2db6146..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testatk.c
+++ /dev/null
@@ -1,1476 +0,0 @@
-/*
- * Copyright (C) 2009 Igalia S.L.
- * Copyright (C) 2013 Samsung Electronics. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include <errno.h>
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <gtk/gtk.h>
-#include <locale.h>
-#include <unistd.h>
-#include <webkit/webkit.h>
-
-static const char* centeredContents = "<html><body><p style='text-align: center;'>Short line</p><p style='text-align: center;'>Long-size line with some foo bar baz content</p><p style='text-align: center;'>Short line</p><p style='text-align: center;'>This is a multi-line paragraph<br />where the first line<br />is the biggest one</p></body></html>";
-
-static const char* contents = "<html><body><p>This is a test. This is the second sentence. And this the third.</p></body></html>";
-
-static const char* contentsInTableWithHeaders = "<html><body><table><tr><th>foo</th><th>bar</th><th colspan='2'>baz</th></tr><tr><th>qux</th><td>1</td><td>2</td><td>3</td></tr><tr><th rowspan='2'>quux</th><td>4</td><td>5</td><td>6</td></tr><tr><td>6</td><td>7</td><td>8</td></tr><tr><th>corge</th><td>9</td><td>10</td><td>11</td></tr></table><table><tr><td>1</td><td>2</td></tr><tr><td>3</td><td>4</td></tr></table></body></html>";
-
-static const char* contentsWithExtraneousWhiteSpaces = "<html><head><body><p>This\n paragraph\n is\n borked!</p></body></html>";
-
-static const char* comboBoxSelector = "<html><body><select><option selected value='foo'>foo</option><option value='bar'>bar</option></select></body></html>";
-
-static const char* embeddedObjects = "<html><body><p>Choose: <input value='foo' type='checkbox'/>foo <input value='bar' type='checkbox'/>bar (pick one)</p><p>Choose: <select name='foo'><option>bar</option><option>baz</option></select> (pick one)</p><p><input name='foobarbutton' value='foobar' type='button'/></p></body></html>";
-
-static const char* formWithTextInputs = "<html><body><form><input type='text' name='entry' /><input type='password' name='passwordEntry' /></form></body></html>";
-
-static const char* hypertextAndHyperlinks = "<html><body><p>A paragraph with no links at all</p><p><a href='http://foo.bar.baz/'>A line</a> with <a href='http://bar.baz.foo/'>a link in the middle</a> as well as at the beginning and <a href='http://baz.foo.bar/'>at the end</a></p><ol><li>List item with a <span><a href='http://foo.bar.baz/'>link inside a span node</a></span></li></ol></body></html>";
-
-static const char* layoutAndDataTables = "<html><body><table><tr><th>Odd</th><th>Even</th></tr><tr><td>1</td><td>2</td></tr></table><table><tr><td>foo</td><td>bar</td></tr></table></body></html>";
-
-static const char* linksWithInlineImages = "<html><head><style>a.http:before {content: url(no-image.png);}</style><body><p><a class='http' href='foo'>foo</a> bar baz</p><p>foo <a class='http' href='bar'>bar</a> baz</p><p>foo bar <a class='http' href='baz'>baz</a></p></body></html>";
-
-static const char* listsOfItems = "<html><body><ul><li>text only</li><li><a href='foo'>link only</a></li><li>text and a <a href='bar'>link</a></li></ul><ol><li>text only</li><li><a href='foo'>link only</a></li><li>text and a <a href='bar'>link</a></li></ol></body></html>";
-
-static const char* textForCaretBrowsing = "<html><body><h1>A text header</h1><p>A paragraph <a href='http://foo.bar.baz/'>with a link</a> in the middle</p><ol><li>A list item</li><li><span style='display:block;'>Block span in a list item</span><span>Inline span in a list item</span></li><li><a href='foo'><span style='display:block;'>Block span in a link in a list item</span><span>Inline span in a link in a list item</span></a></li></ol><select><option selected value='foo'>An option in a combo box</option></select><input type='text' name='foo' value='foo bar baz' /><table><tr><td>a table cell</td><td></td><td><a href='foo'><span style='display:block;'>Block span in a link in a table cell</span><span>Inline span in a link in a table cell</span></a></td><td><span style='display:block;'>Block span in a table cell</span><span>Inline span in a table cell</span></td></tr></table><h4><a href='foo'><span style='display:block;'>Block span in a link in a heading</span><span>Inline span in a link in a heading</span></h4><h4><span style='display:block;'>Block span in a heading</span><span>Inline span in a heading</span></h4></body></html>";
-
-static const char* textForSelections = "<html><body><p>A paragraph with plain text</p><p>A paragraph with <a href='http://webkit.org'>a link</a> in the middle</p><ol><li>A list item</li></ol><select></body></html>";
-
-static const char* textWithAttributes = "<html><head><style>.st1 {font-family: monospace; color:rgb(120,121,122);} .st2 {text-decoration:underline; background-color:rgb(80,81,82);}</style></head><body><p style=\"font-size:14; text-align:right;\">This is the <i>first</i><b> sentence of this text.</b></p><p class=\"st1\">This sentence should have an style applied <span class=\"st2\">and this part should have another one</span>.</p><p>x<sub>1</sub><sup>2</sup>=x<sub>2</sub><sup>3</sup></p><p style=\"text-align:center;\">This sentence is the <strike>last</strike> one.</p></body></html>";
-
-static AtkObject* getWebAreaObject(WebKitWebView* webView)
-{
- /* Manually spin the main context to make sure the accessible
- objects are properly created before continuing. */
- while (g_main_context_pending(0))
- g_main_context_iteration(0, TRUE);
-
- AtkObject* rootObject = gtk_widget_get_accessible(GTK_WIDGET(webView));
- if (!rootObject)
- return NULL;
-
- AtkObject* webAreaObject = atk_object_ref_accessible_child(rootObject, 0);
- if (!webAreaObject)
- return NULL;
-
- /* We don't need the extra ref here. */
- g_object_unref(webAreaObject);
-
- return webAreaObject;
-}
-
-static gchar* textCaretMovedResult = 0;
-
-static void textCaretMovedCallback(AtkText* text, gint pos, gpointer data)
-{
- g_assert(ATK_IS_TEXT(text));
-
- g_free(textCaretMovedResult);
- AtkRole role = atk_object_get_role(ATK_OBJECT(text));
- textCaretMovedResult = g_strdup_printf("|%s|%d|", atk_role_get_name(role), pos);
-}
-
-static void testWebkitAtkCaretOffsets()
-{
- WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(webView);
- GtkAllocation allocation = { 0, 0, 800, 600 };
- gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
- webkit_web_view_load_string(webView, textForCaretBrowsing, 0, 0, 0);
-
- AtkObject* object = getWebAreaObject(webView);
- g_assert(object);
-
- AtkObject* header = atk_object_ref_accessible_child(object, 0);
- g_assert(ATK_IS_TEXT(header));
- g_signal_connect(header, "text-caret-moved", G_CALLBACK(textCaretMovedCallback), 0);
-
- /* It should be possible to place the caret inside a header. */
- gboolean result = atk_text_set_caret_offset(ATK_TEXT(header), 5);
- g_assert_cmpint(result, ==, TRUE);
- gint offset = atk_text_get_caret_offset(ATK_TEXT(header));
- g_assert_cmpint(offset, ==, 5);
- g_assert_cmpstr(textCaretMovedResult, ==, "|heading|5|");
-
- AtkObject* paragraph = atk_object_ref_accessible_child(object, 1);
- g_assert(ATK_IS_TEXT(paragraph));
- g_signal_connect(paragraph, "text-caret-moved", G_CALLBACK(textCaretMovedCallback), 0);
-
- /* It should be possible to place the caret inside a paragraph and a link. */
- result = atk_text_set_caret_offset(ATK_TEXT(paragraph), 5);
- g_assert_cmpint(result, ==, TRUE);
- offset = atk_text_get_caret_offset(ATK_TEXT(paragraph));
- g_assert_cmpint(offset, ==, 5);
- g_assert_cmpstr(textCaretMovedResult, ==, "|paragraph|5|");
-
- result = atk_text_set_caret_offset(ATK_TEXT(paragraph), 20);
- g_assert_cmpint(result, ==, TRUE);
- offset = atk_text_get_caret_offset(ATK_TEXT(paragraph));
- g_assert_cmpint(offset, ==, 20);
- g_assert_cmpstr(textCaretMovedResult, ==, "|paragraph|20|");
-
- result = atk_text_set_caret_offset(ATK_TEXT(paragraph), 30);
- g_assert_cmpint(result, ==, TRUE);
- offset = atk_text_get_caret_offset(ATK_TEXT(paragraph));
- g_assert_cmpint(offset, ==, 30);
- g_assert_cmpstr(textCaretMovedResult, ==, "|paragraph|30|");
-
- AtkObject* link = atk_object_ref_accessible_child(paragraph, 0);
- g_assert(ATK_IS_TEXT(link));
-
- result = atk_text_set_caret_offset(ATK_TEXT(link), 5);
- g_assert_cmpint(result, ==, TRUE);
- offset = atk_text_get_caret_offset(ATK_TEXT(link));
- g_assert_cmpint(offset, ==, 5);
- /* Positions inside links are reported relative to the paragraph. */
- g_assert_cmpstr(textCaretMovedResult, ==, "|paragraph|17|");
-
- AtkObject* list = atk_object_ref_accessible_child(object, 2);
- g_assert(ATK_OBJECT(list));
- g_assert(atk_object_get_role(list) == ATK_ROLE_LIST);
- g_assert_cmpint(atk_object_get_n_accessible_children(list), ==, 3);
-
- AtkObject* listItem = atk_object_ref_accessible_child(list, 0);
- listItem = atk_object_ref_accessible_child(list, 2);
- g_assert(ATK_IS_TEXT(listItem));
-
- /* It's not possible to place the caret inside an item's marker. */
- result = atk_text_set_caret_offset(ATK_TEXT(listItem), 1);
- g_assert_cmpint(result, ==, FALSE);
-
- /* It should be possible to place the caret inside an item's text. */
- result = atk_text_set_caret_offset(ATK_TEXT(listItem), 5);
- g_assert_cmpint(result, ==, TRUE);
- offset = atk_text_get_caret_offset(ATK_TEXT(listItem));
- g_assert_cmpint(offset, ==, 5);
-
- AtkObject* panel = atk_object_ref_accessible_child(object, 3);
- g_assert(ATK_IS_OBJECT(panel));
- g_assert(atk_object_get_role(panel) == ATK_ROLE_PANEL);
-
- AtkObject* comboBox = atk_object_ref_accessible_child(panel, 0);
- g_assert(ATK_IS_OBJECT(comboBox));
- g_assert(atk_object_get_role(comboBox) == ATK_ROLE_COMBO_BOX);
-
- AtkObject* menuPopup = atk_object_ref_accessible_child(comboBox, 0);
- g_assert(ATK_IS_OBJECT(menuPopup));
- g_assert(atk_object_get_role(menuPopup) == ATK_ROLE_MENU);
-
- AtkObject* comboBoxOption = atk_object_ref_accessible_child(menuPopup, 0);
- g_assert(ATK_IS_OBJECT(comboBoxOption));
- g_assert(atk_object_get_role(comboBoxOption) == ATK_ROLE_MENU_ITEM);
-
- /* It's not possible to place the caret inside an option for a combobox. */
- result = atk_text_set_caret_offset(ATK_TEXT(comboBoxOption), 1);
- g_assert_cmpint(result, ==, FALSE);
-
- AtkObject* textEntry = atk_object_ref_accessible_child(panel, 1);
- g_assert(ATK_IS_OBJECT(textEntry));
- g_assert(atk_object_get_role(textEntry) == ATK_ROLE_ENTRY);
-
- result = atk_text_set_caret_offset(ATK_TEXT(textEntry), 5);
- g_assert_cmpint(result, ==, TRUE);
- offset = atk_text_get_caret_offset(ATK_TEXT(textEntry));
- g_assert_cmpint(offset, ==, 5);
-
- AtkObject* table = atk_object_ref_accessible_child(object, 4);
- g_assert(ATK_IS_OBJECT(table));
- g_assert(atk_object_get_role(table) == ATK_ROLE_TABLE);
- g_assert_cmpint(atk_object_get_n_accessible_children(table), ==, 4);
-
- AtkObject* tableCell = atk_object_ref_accessible_child(table, 0);
- g_assert(atk_object_get_role(tableCell) == ATK_ROLE_TABLE_CELL);
- result = atk_text_set_caret_offset(ATK_TEXT(tableCell), 2);
- g_assert_cmpint(result, ==, TRUE);
- offset = atk_text_get_caret_offset(ATK_TEXT(tableCell));
- g_assert_cmpint(offset, ==, 2);
-
- g_free(textCaretMovedResult);
-
- g_object_unref(paragraph);
- g_object_unref(link);
- g_object_unref(list);
- g_object_unref(listItem);
- g_object_unref(panel);
- g_object_unref(comboBox);
- g_object_unref(menuPopup);
- g_object_unref(comboBoxOption);
- g_object_unref(textEntry);
- g_object_unref(table);
- g_object_unref(tableCell);
- g_object_unref(webView);
-}
-
-static void testWebkitAtkCaretOffsetsAndExtranousWhiteSpaces()
-{
- WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(webView);
- GtkAllocation allocation = { 0, 0, 800, 600 };
- gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
- webkit_web_view_load_string(webView, contentsWithExtraneousWhiteSpaces, 0, 0, 0);
-
- /* Enable caret browsing. */
- WebKitWebSettings* settings = webkit_web_view_get_settings(webView);
- g_object_set(G_OBJECT(settings), "enable-caret-browsing", TRUE, NULL);
-
- /* Get to the inner AtkText object. */
- AtkObject* object = getWebAreaObject(webView);
- g_assert(object);
- object = atk_object_ref_accessible_child(object, 0);
- g_assert(object);
-
- AtkText* textObject = ATK_TEXT(object);
- g_assert(ATK_IS_TEXT(textObject));
-
- gint characterCount = atk_text_get_character_count(textObject);
- g_assert_cmpint(characterCount, ==, 25);
-
- gboolean result = atk_text_set_caret_offset(textObject, characterCount - 1);
- g_assert_cmpint(result, ==, TRUE);
-
- gint caretOffset = atk_text_get_caret_offset(textObject);
- g_assert_cmpint(caretOffset, ==, characterCount - 1);
-
- result = atk_text_set_caret_offset(textObject, characterCount);
- g_assert_cmpint(result, ==, TRUE);
-
- caretOffset = atk_text_get_caret_offset(textObject);
- g_assert_cmpint(caretOffset, ==, characterCount);
-
- g_object_unref(object);
- g_object_unref(webView);
-}
-
-static void testWebkitAtkComboBox()
-{
- WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(webView);
- GtkAllocation allocation = { 0, 0, 800, 600 };
- gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
- webkit_web_view_load_string(webView, comboBoxSelector, 0, 0, 0);
-
- AtkObject* object = getWebAreaObject(webView);
- g_assert(object);
-
- AtkObject* formObject = atk_object_ref_accessible_child(object, 0);
- g_assert(formObject);
-
- AtkObject* comboBox = atk_object_ref_accessible_child(formObject, 0);
- g_assert(ATK_IS_OBJECT(comboBox));
-
- AtkObject* menuPopup = atk_object_ref_accessible_child(comboBox, 0);
- g_assert(ATK_IS_OBJECT(menuPopup));
-
- AtkObject* item1 = atk_object_ref_accessible_child(menuPopup, 0);
- g_assert(ATK_IS_OBJECT(item1));
-
- AtkObject* item2 = atk_object_ref_accessible_child(menuPopup, 1);
- g_assert(ATK_IS_OBJECT(item2));
-
- /* Check roles. */
- g_assert(atk_object_get_role(comboBox) == ATK_ROLE_COMBO_BOX);
- g_assert(atk_object_get_role(menuPopup) == ATK_ROLE_MENU);
- g_assert(atk_object_get_role(item1) == ATK_ROLE_MENU_ITEM);
- g_assert(atk_object_get_role(item2) == ATK_ROLE_MENU_ITEM);
-
- /* Check the implementation of the AtkSelection interface. */
- g_assert(ATK_IS_SELECTION(comboBox));
- AtkSelection* atkSelection = ATK_SELECTION(comboBox);
- g_assert_cmpint(atk_selection_get_selection_count(atkSelection), ==, 1);
- g_assert(atk_selection_is_child_selected(atkSelection, 0));
- g_assert(!atk_selection_is_child_selected(atkSelection, 1));
- AtkObject* selectedItem = atk_selection_ref_selection(atkSelection, 0);
- g_assert(selectedItem == item1);
- g_object_unref(selectedItem);
-
- /* Check that the menu popup has 0 links and doesn't crash from checking. */
- gint nLinks = atk_hypertext_get_n_links(ATK_HYPERTEXT(menuPopup));
- g_assert_cmpint(nLinks, ==, 0);
-
- /* Check the implementations of the AtkAction interface. */
- g_assert(ATK_IS_ACTION(comboBox));
- AtkAction* atkAction = ATK_ACTION(comboBox);
- g_assert_cmpint(atk_action_get_n_actions(atkAction), ==, 1);
- g_assert(atk_action_do_action(atkAction, 0));
-
- g_assert(ATK_IS_ACTION(menuPopup));
- atkAction = ATK_ACTION(menuPopup);
- g_assert_cmpint(atk_action_get_n_actions(atkAction), ==, 1);
- g_assert(atk_action_do_action(atkAction, 0));
-
- g_assert(ATK_IS_ACTION(item1));
- atkAction = ATK_ACTION(item1);
- g_assert_cmpint(atk_action_get_n_actions(atkAction), ==, 1);
- g_assert(atk_action_do_action(atkAction, 0));
-
- g_assert(ATK_IS_ACTION(item2));
- atkAction = ATK_ACTION(item2);
- g_assert_cmpint(atk_action_get_n_actions(atkAction), ==, 1);
- g_assert(atk_action_do_action(atkAction, 0));
-
- /* After selecting the second item, selection should have changed. */
- g_assert_cmpint(atk_selection_get_selection_count(atkSelection), ==, 1);
- g_assert(!atk_selection_is_child_selected(atkSelection, 0));
- g_assert(atk_selection_is_child_selected(atkSelection, 1));
- selectedItem = atk_selection_ref_selection(atkSelection, 0);
- g_assert(selectedItem == item2);
- g_object_unref(selectedItem);
-
- g_object_unref(formObject);
- g_object_unref(comboBox);
- g_object_unref(menuPopup);
- g_object_unref(item1);
- g_object_unref(item2);
- g_object_unref(webView);
-}
-
-static gchar* loadingEventsResult = 0;
-
-static void updateLoadingEventsResult(const gchar* signalName)
-{
- g_assert(signalName);
-
- gchar* previousResult = loadingEventsResult;
- loadingEventsResult = g_strdup_printf("%s|%s", previousResult, signalName);
- g_free(previousResult);
-}
-
-static gboolean documentLoadingEventCallback(GSignalInvocationHint *signalHint, guint numParamValues, const GValue *paramValues, gpointer data)
-{
- // At least we should receive the instance emitting the signal.
- if (numParamValues < 1)
- return TRUE;
-
- GSignalQuery signal_query;
- g_signal_query(signalHint->signal_id, &signal_query);
-
- updateLoadingEventsResult(signal_query.signal_name);
- return TRUE;
-}
-
-static void testWebkitAtkDocumentLoadingEvents()
-{
- WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(webView);
- GtkAllocation allocation = { 0, 0, 800, 600 };
- gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
-
- /* Connect globally to see those events during a future load. */
- guint loadCompleteListenerId = atk_add_global_event_listener(documentLoadingEventCallback, "ATK:AtkDocument:load-complete");
-
- /* Do the load, so we can see those events happening. */
- loadingEventsResult = g_strdup("");
- webkit_web_view_load_string(webView, contents, 0, 0, 0);
-
- /* Trigger the creation of the full accessibility hierarchy by
- asking for the webArea object, so we can listen to events. */
- getWebAreaObject(webView);
-
- atk_remove_global_event_listener(loadCompleteListenerId);
-
- g_assert_cmpstr(loadingEventsResult, ==, "|load-complete");
-
- g_free(loadingEventsResult);
- g_object_unref(webView);
-}
-
-static void testWebkitAtkEmbeddedObjects()
-{
- WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(webView);
- GtkAllocation allocation = { 0, 0, 800, 600 };
- gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
- webkit_web_view_load_string(webView, embeddedObjects, 0, 0, 0);
-
- AtkObject* object = getWebAreaObject(webView);
- g_assert(object);
-
- AtkText* paragraph1 = ATK_TEXT(atk_object_ref_accessible_child(object, 0));
- g_assert(ATK_IS_TEXT(paragraph1));
- g_assert(ATK_IS_HYPERTEXT(paragraph1));
-
- gint nLinks = atk_hypertext_get_n_links(ATK_HYPERTEXT(paragraph1));
- g_assert_cmpint(nLinks, ==, 2);
-
- AtkHyperlink* hLink = atk_hypertext_get_link(ATK_HYPERTEXT(paragraph1), 0);
- g_assert(ATK_HYPERLINK(hLink));
- AtkObject* hLinkObject = atk_hyperlink_get_object(hLink, 0);
- g_assert(ATK_OBJECT(hLinkObject));
- g_assert(atk_object_get_role(hLinkObject) == ATK_ROLE_CHECK_BOX);
- g_assert_cmpint(atk_hyperlink_get_start_index(hLink), ==, 8);
- g_assert_cmpint(atk_hyperlink_get_end_index(hLink), ==, 9);
- g_assert_cmpint(atk_hyperlink_get_n_anchors(hLink), ==, 1);
- g_assert_cmpstr(atk_hyperlink_get_uri(hLink, 0), ==, 0);
-
- AtkText* paragraph2 = ATK_TEXT(atk_object_ref_accessible_child(object, 1));
- g_assert(ATK_IS_HYPERTEXT(paragraph2));
-
- nLinks = atk_hypertext_get_n_links(ATK_HYPERTEXT(paragraph2));
- g_assert_cmpint(nLinks, ==, 1);
-
- hLink = atk_hypertext_get_link(ATK_HYPERTEXT(paragraph2), 0);
- g_assert(ATK_HYPERLINK(hLink));
- hLinkObject = atk_hyperlink_get_object(hLink, 0);
- g_assert(ATK_OBJECT(hLinkObject));
- g_assert(atk_object_get_role(hLinkObject) == ATK_ROLE_COMBO_BOX);
- g_assert_cmpint(atk_hyperlink_get_start_index(hLink), ==, 8);
- g_assert_cmpint(atk_hyperlink_get_end_index(hLink), ==, 9);
- g_assert_cmpint(atk_hyperlink_get_n_anchors(hLink), ==, 1);
- g_assert_cmpstr(atk_hyperlink_get_uri(hLink, 0), ==, 0);
-
- AtkText* paragraph3 = ATK_TEXT(atk_object_ref_accessible_child(object, 2));
- g_assert(ATK_IS_HYPERTEXT(paragraph3));
-
- nLinks = atk_hypertext_get_n_links(ATK_HYPERTEXT(paragraph3));
- g_assert_cmpint(nLinks, ==, 1);
-
- hLink = atk_hypertext_get_link(ATK_HYPERTEXT(paragraph3), 0);
- g_assert(ATK_HYPERLINK(hLink));
- hLinkObject = atk_hyperlink_get_object(hLink, 0);
- g_assert(ATK_OBJECT(hLinkObject));
- g_assert(atk_object_get_role(hLinkObject) == ATK_ROLE_PUSH_BUTTON);
- g_assert_cmpint(atk_hyperlink_get_start_index(hLink), ==, 0);
- g_assert_cmpint(atk_hyperlink_get_end_index(hLink), ==, 1);
- g_assert_cmpint(atk_hyperlink_get_n_anchors(hLink), ==, 1);
- g_assert_cmpstr(atk_hyperlink_get_uri(hLink, 0), ==, 0);
-
- g_object_unref(paragraph1);
- g_object_unref(paragraph2);
- g_object_unref(paragraph3);
- g_object_unref(webView);
-}
-
-static void testWebkitAtkGetHeadersInTable()
-{
- WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(webView);
- GtkAllocation allocation = { 0, 0, 800, 600 };
- gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
- webkit_web_view_load_string(webView, contentsInTableWithHeaders, 0, 0, 0);
-
- AtkObject* axWebView = getWebAreaObject(webView);
- g_assert(axWebView);
-
- /* Check table with both column and row headers. */
- AtkObject* table = atk_object_ref_accessible_child(axWebView, 0);
- g_assert(table);
- g_assert(atk_object_get_role(table) == ATK_ROLE_TABLE);
-
- AtkObject* colHeader = atk_table_get_column_header(ATK_TABLE(table), 0);
- g_assert(colHeader);
- g_assert(atk_object_get_role(colHeader) == ATK_ROLE_TABLE_CELL);
- g_assert(atk_object_get_index_in_parent(colHeader) == 0);
-
- colHeader = atk_table_get_column_header(ATK_TABLE(table), 1);
- g_assert(colHeader);
- g_assert(atk_object_get_role(colHeader) == ATK_ROLE_TABLE_CELL);
- g_assert(atk_object_get_index_in_parent(colHeader) == 1);
-
- colHeader = atk_table_get_column_header(ATK_TABLE(table), 2);
- g_assert(colHeader);
- g_assert(atk_object_get_role(colHeader) == ATK_ROLE_TABLE_CELL);
- g_assert(atk_object_get_index_in_parent(colHeader) == 2);
-
- colHeader = atk_table_get_column_header(ATK_TABLE(table), 3);
- g_assert(colHeader);
- g_assert(atk_object_get_role(colHeader) == ATK_ROLE_TABLE_CELL);
- g_assert(atk_object_get_index_in_parent(colHeader) == 2);
-
- AtkObject* rowHeader = atk_table_get_row_header(ATK_TABLE(table), 0);
- g_assert(rowHeader);
- g_assert(atk_object_get_role(rowHeader) == ATK_ROLE_TABLE_CELL);
- g_assert(atk_object_get_index_in_parent(rowHeader) == 0);
-
- rowHeader = atk_table_get_row_header(ATK_TABLE(table), 1);
- g_assert(rowHeader);
- g_assert(atk_object_get_role(rowHeader) == ATK_ROLE_TABLE_CELL);
- g_assert(atk_object_get_index_in_parent(rowHeader) == 3);
-
- rowHeader = atk_table_get_row_header(ATK_TABLE(table), 2);
- g_assert(rowHeader);
- g_assert(atk_object_get_role(rowHeader) == ATK_ROLE_TABLE_CELL);
- g_assert(atk_object_get_index_in_parent(rowHeader) == 7);
-
- rowHeader = atk_table_get_row_header(ATK_TABLE(table), 3);
- g_assert(rowHeader);
- g_assert(atk_object_get_role(rowHeader) == ATK_ROLE_TABLE_CELL);
- g_assert(atk_object_get_index_in_parent(rowHeader) == 7);
-
- g_object_unref(table);
-
- /* Check table with no headers at all. */
- table = atk_object_ref_accessible_child(axWebView, 1);
- g_assert(table);
- g_assert(atk_object_get_role(table) == ATK_ROLE_TABLE);
-
- colHeader = atk_table_get_column_header(ATK_TABLE(table), 0);
- g_assert(colHeader == 0);
-
- colHeader = atk_table_get_column_header(ATK_TABLE(table), 1);
- g_assert(colHeader == 0);
-
- rowHeader = atk_table_get_row_header(ATK_TABLE(table), 0);
- g_assert(rowHeader == 0);
-
- rowHeader = atk_table_get_row_header(ATK_TABLE(table), 1);
- g_assert(rowHeader == 0);
-
- g_object_unref(table);
- g_object_unref(webView);
-}
-
-static gint compAtkAttribute(AtkAttribute* a1, AtkAttribute* a2)
-{
- gint strcmpVal = g_strcmp0(a1->name, a2->name);
- if (strcmpVal)
- return strcmpVal;
- return g_strcmp0(a1->value, a2->value);
-}
-
-static gint compAtkAttributeName(AtkAttribute* a1, AtkAttribute* a2)
-{
- return g_strcmp0(a1->name, a2->name);
-}
-
-static gboolean atkAttributeSetAttributeNameHasValue(AtkAttributeSet* set, const gchar* attributeName, const gchar* value)
-{
- AtkAttribute at;
- at.name = (gchar*)attributeName;
- GSList* element = g_slist_find_custom(set, &at, (GCompareFunc)compAtkAttributeName);
- return element && !g_strcmp0(((AtkAttribute*)(element->data))->value, value);
-}
-
-static gboolean atkAttributeSetContainsAttributeName(AtkAttributeSet* set, const gchar* attributeName)
-{
- AtkAttribute at;
- at.name = (gchar*)attributeName;
- return g_slist_find_custom(set, &at, (GCompareFunc)compAtkAttributeName) ? true : false;
-}
-
-static gboolean atkAttributeSetAttributeHasValue(AtkAttributeSet* set, AtkTextAttribute attribute, const gchar* value)
-{
- return atkAttributeSetAttributeNameHasValue(set, atk_text_attribute_get_name(attribute), value);
-}
-
-static gboolean atkAttributeSetAreEqual(AtkAttributeSet* set1, AtkAttributeSet* set2)
-{
- if (!set1)
- return !set2;
-
- set1 = g_slist_sort(set1, (GCompareFunc)compAtkAttribute);
- set2 = g_slist_sort(set2, (GCompareFunc)compAtkAttribute);
-
- while (set1) {
- if (!set2 || compAtkAttribute(set1->data, set2->data))
- return FALSE;
-
- set1 = set1->next;
- set2 = set2->next;
- }
-
- return (!set2);
-}
-
-static void testWebkitAtkTextAttributes()
-{
- WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(webView);
- GtkAllocation allocation = { 0, 0, 800, 600 };
- gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
- webkit_web_view_load_string(webView, textWithAttributes, 0, 0, 0);
-
- AtkObject* object = getWebAreaObject(webView);
- g_assert(object);
-
- AtkObject* child = atk_object_ref_accessible_child(object, 0);
- g_assert(child && ATK_IS_TEXT(child));
- AtkText* childText = ATK_TEXT(child);
-
- gint startOffset;
- gint endOffset;
- AtkAttributeSet* set1 = atk_text_get_run_attributes(childText, 0, &startOffset, &endOffset);
- g_assert_cmpint(startOffset, ==, 0);
- g_assert_cmpint(endOffset, ==, 12);
- g_assert(atkAttributeSetAreEqual(set1, 0));
-
- AtkAttributeSet* set2 = atk_text_get_run_attributes(childText, 15, &startOffset, &endOffset);
- g_assert_cmpint(startOffset, ==, 12);
- g_assert_cmpint(endOffset, ==, 17);
- g_assert(atkAttributeSetAttributeHasValue(set2, ATK_TEXT_ATTR_STYLE, "italic"));
-
- AtkAttributeSet* set3 = atk_text_get_run_attributes(childText, 17, &startOffset, &endOffset);
- g_assert_cmpint(startOffset, ==, 17);
- g_assert_cmpint(endOffset, ==, 40);
- g_assert(atkAttributeSetAttributeHasValue(set3, ATK_TEXT_ATTR_WEIGHT, "700"));
-
- AtkAttributeSet* set4 = atk_text_get_default_attributes(childText);
- g_assert(atkAttributeSetAttributeHasValue(set4, ATK_TEXT_ATTR_STYLE, "normal"));
- g_assert(atkAttributeSetAttributeHasValue(set4, ATK_TEXT_ATTR_JUSTIFICATION, "right"));
- g_assert(atkAttributeSetAttributeHasValue(set4, ATK_TEXT_ATTR_SIZE, "14"));
- atk_attribute_set_free(set1);
- atk_attribute_set_free(set2);
- atk_attribute_set_free(set3);
- atk_attribute_set_free(set4);
-
- g_object_unref(child);
- child = atk_object_ref_accessible_child(object, 1);
- g_assert(child && ATK_IS_TEXT(child));
- childText = ATK_TEXT(child);
-
- set1 = atk_text_get_default_attributes(childText);
- g_assert(atkAttributeSetAttributeHasValue(set1, ATK_TEXT_ATTR_FAMILY_NAME, "monospace"));
- g_assert(atkAttributeSetAttributeHasValue(set1, ATK_TEXT_ATTR_STYLE, "normal"));
- g_assert(atkAttributeSetAttributeHasValue(set1, ATK_TEXT_ATTR_STRIKETHROUGH, "false"));
- g_assert(atkAttributeSetAttributeHasValue(set1, ATK_TEXT_ATTR_WEIGHT, "400"));
- g_assert(atkAttributeSetAttributeHasValue(set1, ATK_TEXT_ATTR_FG_COLOR, "120,121,122"));
-
- set2 = atk_text_get_run_attributes(childText, 43, &startOffset, &endOffset);
- g_assert_cmpint(startOffset, ==, 43);
- g_assert_cmpint(endOffset, ==, 80);
- /* Checks that default attributes of text are not returned when called to atk_text_get_run_attributes. */
- g_assert(!atkAttributeSetAttributeHasValue(set2, ATK_TEXT_ATTR_FG_COLOR, "120,121,122"));
- g_assert(atkAttributeSetAttributeHasValue(set2, ATK_TEXT_ATTR_UNDERLINE, "single"));
- g_assert(atkAttributeSetAttributeHasValue(set2, ATK_TEXT_ATTR_BG_COLOR, "80,81,82"));
- atk_attribute_set_free(set1);
- atk_attribute_set_free(set2);
- g_object_unref(child);
-
- child = atk_object_ref_accessible_child(object, 2);
- g_assert(child && ATK_IS_TEXT(child));
- childText = ATK_TEXT(child);
-
- set1 = atk_text_get_run_attributes(childText, 0, &startOffset, &endOffset);
- set2 = atk_text_get_run_attributes(childText, 3, &startOffset, &endOffset);
- g_assert(atkAttributeSetAreEqual(set1, set2));
- atk_attribute_set_free(set2);
-
- set2 = atk_text_get_run_attributes(childText, 1, &startOffset, &endOffset);
- set3 = atk_text_get_run_attributes(childText, 5, &startOffset, &endOffset);
- g_assert(atkAttributeSetAreEqual(set2, set3));
- g_assert(!atkAttributeSetAreEqual(set1, set2));
- atk_attribute_set_free(set3);
-
- set3 = atk_text_get_run_attributes(childText, 2, &startOffset, &endOffset);
- set4 = atk_text_get_run_attributes(childText, 6, &startOffset, &endOffset);
- g_assert(atkAttributeSetAreEqual(set3, set4));
- g_assert(!atkAttributeSetAreEqual(set1, set3));
- g_assert(!atkAttributeSetAreEqual(set2, set3));
- atk_attribute_set_free(set1);
- atk_attribute_set_free(set2);
- atk_attribute_set_free(set3);
- atk_attribute_set_free(set4);
- g_object_unref(child);
-
- child = atk_object_ref_accessible_child(object, 3);
- g_assert(child && ATK_IS_TEXT(child));
- childText = ATK_TEXT(child);
- set1 = atk_text_get_run_attributes(childText, 24, &startOffset, &endOffset);
- g_assert_cmpint(startOffset, ==, 21);
- g_assert_cmpint(endOffset, ==, 25);
- g_assert(atkAttributeSetAttributeHasValue(set1, ATK_TEXT_ATTR_STRIKETHROUGH, "true"));
-
- set2 = atk_text_get_run_attributes(childText, 25, &startOffset, &endOffset);
- g_assert_cmpint(startOffset, ==, 25);
- g_assert_cmpint(endOffset, ==, 30);
- g_assert(atkAttributeSetAreEqual(set2, 0));
-
- set3 = atk_text_get_default_attributes(childText);
- g_assert(atkAttributeSetAttributeHasValue(set3, ATK_TEXT_ATTR_JUSTIFICATION, "center"));
- atk_attribute_set_free(set1);
- atk_attribute_set_free(set2);
- atk_attribute_set_free(set3);
-
- g_object_unref(child);
-}
-
-static gchar* textSelectionChangedResult = 0;
-
-static void textSelectionChangedCallback(AtkText* text, gpointer data)
-{
- g_assert(ATK_IS_TEXT(text));
-
- g_free(textSelectionChangedResult);
- AtkRole role = atk_object_get_role(ATK_OBJECT(text));
- int startOffset = 0;
- int endOffset = 0;
- atk_text_get_selection(ATK_TEXT(text), 0, &startOffset, &endOffset);
- textSelectionChangedResult = g_strdup_printf("|%s|%d|%d|", atk_role_get_name(role), startOffset, endOffset);
-}
-
-static void testWebkitAtkTextSelections()
-{
- WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(webView);
- GtkAllocation allocation = { 0, 0, 800, 600 };
- gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
- webkit_web_view_load_string(webView, textForSelections, 0, 0, 0);
-
- AtkObject* object = getWebAreaObject(webView);
- g_assert(object);
-
- AtkText* paragraph1 = ATK_TEXT(atk_object_ref_accessible_child(object, 0));
- g_assert(ATK_IS_TEXT(paragraph1));
- g_signal_connect(paragraph1, "text-selection-changed", G_CALLBACK(textSelectionChangedCallback), 0);
-
- AtkText* paragraph2 = ATK_TEXT(atk_object_ref_accessible_child(object, 1));
- g_assert(ATK_IS_TEXT(paragraph2));
- g_signal_connect(paragraph2, "text-selection-changed", G_CALLBACK(textSelectionChangedCallback), 0);
-
- AtkText* link = ATK_TEXT(atk_object_ref_accessible_child(ATK_OBJECT(paragraph2), 0));
- g_assert(ATK_IS_TEXT(link));
-
- AtkObject* list = atk_object_ref_accessible_child(object, 2);
- g_assert(ATK_OBJECT(list));
-
- AtkText* listItem = ATK_TEXT(atk_object_ref_accessible_child(list, 0));
- g_assert(ATK_IS_TEXT(listItem));
-
- /* First paragraph (simple text). */
-
- /* Basic initial checks. */
- g_assert_cmpint(atk_text_get_n_selections(paragraph1), ==, 0);
-
- gint startOffset;
- gint endOffset;
- gchar* selectedText = atk_text_get_selection(paragraph1, 0, &startOffset, &endOffset);
- g_assert_cmpint(startOffset, ==, 0);
- g_assert_cmpint(endOffset, ==, 0);
- g_assert_cmpstr(selectedText, ==, 0);
- g_free (selectedText);
-
- /* Try removing a non existing (yet) selection. */
- gboolean result = atk_text_remove_selection(paragraph1, 0);
- g_assert(!result);
-
- /* Try setting a 0-char selection. */
- result = atk_text_set_selection(paragraph1, 0, 5, 5);
- g_assert(result);
-
- /* Make a selection and test it. */
- result = atk_text_set_selection(paragraph1, 0, 5, 25);
- g_assert(result);
- g_assert_cmpint(atk_text_get_n_selections(paragraph1), ==, 1);
- g_assert_cmpstr(textSelectionChangedResult, ==, "|paragraph|5|25|");
- selectedText = atk_text_get_selection(paragraph1, 0, &startOffset, &endOffset);
- g_assert_cmpint(startOffset, ==, 5);
- g_assert_cmpint(endOffset, ==, 25);
- g_assert_cmpstr(selectedText, ==, "agraph with plain te");
- g_free (selectedText);
-
- /* Try removing the selection from other AtkText object (should fail). */
- result = atk_text_remove_selection(paragraph2, 0);
- g_assert(!result);
-
- /* Remove the selection and test everything again. */
- result = atk_text_remove_selection(paragraph1, 0);
- g_assert(result);
- g_assert_cmpint(atk_text_get_n_selections(paragraph1), ==, 0);
- selectedText = atk_text_get_selection(paragraph1, 0, &startOffset, &endOffset);
- /* Now offsets should be the same, set to the last position of the caret. */
- g_assert_cmpint(startOffset, ==, endOffset);
- g_assert_cmpint(startOffset, ==, 25);
- g_assert_cmpint(endOffset, ==, 25);
- g_assert_cmpstr(selectedText, ==, 0);
- g_free (selectedText);
-
- /* Second paragraph (text + link + text). */
-
- /* Set a selection partially covering the link and test it. */
- result = atk_text_set_selection(paragraph2, 0, 7, 21);
- g_assert(result);
-
- /* Test the paragraph first. */
- g_assert_cmpint(atk_text_get_n_selections(paragraph2), ==, 1);
- selectedText = atk_text_get_selection(paragraph2, 0, &startOffset, &endOffset);
- g_assert_cmpint(startOffset, ==, 7);
- g_assert_cmpint(endOffset, ==, 21);
- g_assert_cmpstr(selectedText, ==, "raph with a li");
- g_free (selectedText);
-
- /* Now test just the link. */
- g_assert_cmpint(atk_text_get_n_selections(link), ==, 1);
- selectedText = atk_text_get_selection(link, 0, &startOffset, &endOffset);
- g_assert_cmpint(startOffset, ==, 0);
- g_assert_cmpint(endOffset, ==, 4);
- g_assert_cmpstr(selectedText, ==, "a li");
- g_free (selectedText);
-
- /* Make a selection after the link and check selection for the whole paragraph. */
- result = atk_text_set_selection(paragraph2, 0, 27, 37);
- g_assert(result);
- g_assert_cmpint(atk_text_get_n_selections(paragraph2), ==, 1);
- g_assert_cmpstr(textSelectionChangedResult, ==, "|paragraph|27|37|");
- selectedText = atk_text_get_selection(paragraph2, 0, &startOffset, &endOffset);
- g_assert_cmpint(startOffset, ==, 27);
- g_assert_cmpint(endOffset, ==, 37);
- g_assert_cmpstr(selectedText, ==, "the middle");
- g_free (selectedText);
-
- /* Remove selections and text everything again. */
- result = atk_text_remove_selection(paragraph2, 0);
- g_assert(result);
- g_assert_cmpint(atk_text_get_n_selections(paragraph2), ==, 0);
- selectedText = atk_text_get_selection(paragraph2, 0, &startOffset, &endOffset);
- /* Now offsets should be the same (no selection). */
- g_assert_cmpint(startOffset, ==, endOffset);
- g_assert_cmpstr(selectedText, ==, 0);
- g_free (selectedText);
-
- g_assert_cmpint(atk_text_get_n_selections(link), ==, 0);
- selectedText = atk_text_get_selection(link, 0, &startOffset, &endOffset);
- /* Now offsets should be the same (no selection). */
- g_assert_cmpint(startOffset, ==, endOffset);
- g_assert_cmpstr(selectedText, ==, 0);
- g_free (selectedText);
-
- /* List item */
-
- g_assert(atk_object_get_role(list) == ATK_ROLE_LIST);
- g_assert_cmpint(atk_object_get_n_accessible_children(list), ==, 1);
-
- /* It's not possible to select text inside an item's marker. */
- result = atk_text_set_selection (listItem, 0, 0, 9);
- g_assert(!result);
- result = atk_text_set_selection (listItem, 0, 9, 1);
- g_assert(!result);
-
- /* It should be possible to select text inside an item's text. */
- result = atk_text_set_selection (listItem, 0, 3, 9);
- g_assert(result);
-
- g_assert_cmpint(atk_text_get_n_selections(listItem), ==, 1);
- selectedText = atk_text_get_selection(listItem, 0, &startOffset, &endOffset);
- g_assert_cmpint(startOffset, ==, 3);
- g_assert_cmpint(endOffset, ==, 9);
- g_assert_cmpstr(selectedText, ==, "A list");
- g_free (selectedText);
-
- g_free(textSelectionChangedResult);
-
- g_object_unref(paragraph1);
- g_object_unref(paragraph2);
- g_object_unref(link);
- g_object_unref(list);
- g_object_unref(listItem);
- g_object_unref(webView);
-}
-
-static void testWebkitAtkGetExtents()
-{
- WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(webView);
- GtkAllocation allocation = { 0, 0, 800, 600 };
- gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
- webkit_web_view_load_string(webView, centeredContents, 0, 0, 0);
-
- AtkObject* object = getWebAreaObject(webView);
- g_assert(object);
-
- AtkText* shortText1 = ATK_TEXT(atk_object_ref_accessible_child(object, 0));
- g_assert(ATK_IS_TEXT(shortText1));
- AtkText* longText = ATK_TEXT(atk_object_ref_accessible_child(object, 1));
- g_assert(ATK_IS_TEXT(longText));
- AtkText* shortText2 = ATK_TEXT(atk_object_ref_accessible_child(object, 2));
- g_assert(ATK_IS_TEXT(shortText2));
- AtkText* multilineText = ATK_TEXT(atk_object_ref_accessible_child(object, 3));
- g_assert(ATK_IS_TEXT(multilineText));
-
- /* Start with window extents. */
- AtkTextRectangle sline_window1, sline_window2, lline_window, mline_window;
- atk_text_get_range_extents(shortText1, 0, 10, ATK_XY_WINDOW, &sline_window1);
- atk_text_get_range_extents(longText, 0, 44, ATK_XY_WINDOW, &lline_window);
- atk_text_get_range_extents(shortText2, 0, 10, ATK_XY_WINDOW, &sline_window2);
- atk_text_get_range_extents(multilineText, 0, 60, ATK_XY_WINDOW, &mline_window);
-
- /* Check vertical line position. */
- g_assert_cmpint(sline_window1.y + sline_window1.height, <=, lline_window.y);
- g_assert_cmpint(lline_window.y + lline_window.height + sline_window2.height, <=, mline_window.y);
-
- /* Paragraphs 1 and 3 have identical text and alignment. */
- g_assert_cmpint(sline_window1.x, ==, sline_window2.x);
- g_assert_cmpint(sline_window1.width, ==, sline_window2.width);
- g_assert_cmpint(sline_window1.height, ==, sline_window2.height);
-
- /* All lines should be the same height; line 2 is the widest line. */
- g_assert_cmpint(sline_window1.height, ==, lline_window.height);
- g_assert_cmpint(sline_window1.width, <, lline_window.width);
-
- /* Make sure the character extents jive with the range extents. */
- gint x;
- gint y;
- gint width;
- gint height;
-
- /* First paragraph (short text). */
- atk_text_get_character_extents(shortText1, 0, &x, &y, &width, &height, ATK_XY_WINDOW);
- g_assert_cmpint(x, ==, sline_window1.x);
- g_assert_cmpint(y, ==, sline_window1.y);
- g_assert_cmpint(height, ==, sline_window1.height);
-
- atk_text_get_character_extents(shortText1, 9, &x, &y, &width, &height, ATK_XY_WINDOW);
- g_assert_cmpint(x, ==, sline_window1.x + sline_window1.width - width);
- g_assert_cmpint(y, ==, sline_window1.y);
- g_assert_cmpint(height, ==, sline_window1.height);
-
- /* Second paragraph (long text). */
- atk_text_get_character_extents(longText, 0, &x, &y, &width, &height, ATK_XY_WINDOW);
- g_assert_cmpint(x, ==, lline_window.x);
- g_assert_cmpint(y, ==, lline_window.y);
- g_assert_cmpint(height, ==, lline_window.height);
-
- atk_text_get_character_extents(longText, 43, &x, &y, &width, &height, ATK_XY_WINDOW);
- g_assert_cmpint(x, ==, lline_window.x + lline_window.width - width);
- g_assert_cmpint(y, ==, lline_window.y);
- g_assert_cmpint(height, ==, lline_window.height);
-
- /* Third paragraph (short text). */
- atk_text_get_character_extents(shortText2, 0, &x, &y, &width, &height, ATK_XY_WINDOW);
- g_assert_cmpint(x, ==, sline_window2.x);
- g_assert_cmpint(y, ==, sline_window2.y);
- g_assert_cmpint(height, ==, sline_window2.height);
-
- atk_text_get_character_extents(shortText2, 9, &x, &y, &width, &height, ATK_XY_WINDOW);
- g_assert_cmpint(x, ==, sline_window2.x + sline_window2.width - width);
- g_assert_cmpint(y, ==, sline_window2.y);
- g_assert_cmpint(height, ==, sline_window2.height);
-
- /* Four paragraph (3 lines multi-line text). */
- atk_text_get_character_extents(multilineText, 0, &x, &y, &width, &height, ATK_XY_WINDOW);
- g_assert_cmpint(x, ==, mline_window.x);
- g_assert_cmpint(y, ==, mline_window.y);
- g_assert_cmpint(3 * height, ==, mline_window.height);
-
- atk_text_get_character_extents(multilineText, 59, &x, &y, &width, &height, ATK_XY_WINDOW);
- /* Last line won't fill the whole width of the rectangle. */
- g_assert_cmpint(x, <=, mline_window.x + mline_window.width - width);
- g_assert_cmpint(y, ==, mline_window.y + mline_window.height - height);
- g_assert_cmpint(height, <=, mline_window.height);
-
- /* Check that extent for a full line are the same height than for
- a partial section of the same line */
- gint startOffset;
- gint endOffset;
-
-#if !ATK_CHECK_VERSION(2, 10, 0)
- gchar* text = atk_text_get_text_at_offset(multilineText, 0, ATK_TEXT_BOUNDARY_LINE_START, &startOffset, &endOffset);
- g_free(text);
-#else
- gchar* text = atk_text_get_string_at_offset(multilineText, 0, ATK_TEXT_GRANULARITY_LINE, &startOffset, &endOffset);
- g_free(text);
-#endif
-
- AtkTextRectangle fline_window;
- AtkTextRectangle afline_window;
- atk_text_get_range_extents(multilineText, startOffset, endOffset, ATK_XY_WINDOW, &fline_window);
- atk_text_get_range_extents(multilineText, startOffset, endOffset - 1, ATK_XY_WINDOW, &afline_window);
- g_assert_cmpint(fline_window.x, ==, afline_window.x);
- g_assert_cmpint(fline_window.y, ==, afline_window.y);
- g_assert_cmpint(fline_window.height, ==, afline_window.height);
-
- g_object_unref(shortText1);
- g_object_unref(shortText2);
- g_object_unref(longText);
- g_object_unref(multilineText);
- g_object_unref(webView);
-}
-
-static void testWebkitAtkLayoutAndDataTables()
-{
- WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(webView);
- GtkAllocation allocation = { 0, 0, 800, 600 };
- gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
- webkit_web_view_load_string(webView, layoutAndDataTables, 0, 0, 0);
-
- AtkObject* object = getWebAreaObject(webView);
- g_assert(object);
-
- /* Check the non-layout table (data table). */
-
- AtkObject* table1 = atk_object_ref_accessible_child(object, 0);
- g_assert(ATK_IS_TABLE(table1));
- AtkAttributeSet* set1 = atk_object_get_attributes(table1);
- g_assert(set1);
- g_assert(!atkAttributeSetContainsAttributeName(set1, "layout-guess"));
- atk_attribute_set_free(set1);
-
- /* Check the layout table. */
-
- AtkObject* table2 = atk_object_ref_accessible_child(object, 1);
- g_assert(ATK_IS_TABLE(table2));
- AtkAttributeSet* set2 = atk_object_get_attributes(table2);
- g_assert(set2);
- g_assert(atkAttributeSetContainsAttributeName(set2, "layout-guess"));
- g_assert(atkAttributeSetAttributeNameHasValue(set2, "layout-guess", "true"));
- atk_attribute_set_free(set2);
-
- g_object_unref(table1);
- g_object_unref(table2);
- g_object_unref(webView);
-}
-
-static void testWebkitAtkLinksWithInlineImages()
-{
- WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(webView);
- GtkAllocation allocation = { 0, 0, 800, 600 };
- gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
- webkit_web_view_load_string(webView, linksWithInlineImages, 0, 0, 0);
-
- AtkObject* object = getWebAreaObject(webView);
- g_assert(object);
-
- /* First paragraph (link at the beginning). */
- AtkObject* paragraph = atk_object_ref_accessible_child(object, 0);
- g_assert(ATK_IS_TEXT(paragraph));
- gint startOffset;
- gint endOffset;
-
-#if !ATK_CHECK_VERSION(2, 10, 0)
- gchar* text = atk_text_get_text_at_offset(ATK_TEXT(paragraph), 0, ATK_TEXT_BOUNDARY_LINE_START, &startOffset, &endOffset);
- g_assert(text);
- g_assert_cmpstr(text, ==, "foo bar baz");
- g_assert_cmpint(startOffset, ==, 0);
- g_assert_cmpint(endOffset, ==, 11);
- g_free(text);
-#else
- gchar* text = atk_text_get_string_at_offset(ATK_TEXT(paragraph), 0, ATK_TEXT_GRANULARITY_LINE, &startOffset, &endOffset);
- g_assert(text);
- g_assert_cmpstr(text, ==, "foo bar baz");
- g_assert_cmpint(startOffset, ==, 0);
- g_assert_cmpint(endOffset, ==, 11);
- g_free(text);
-#endif
-
- g_object_unref(paragraph);
-
- /* Second paragraph (link in the middle). */
- paragraph = atk_object_ref_accessible_child(object, 1);
- g_assert(ATK_IS_TEXT(paragraph));
-
-#if !ATK_CHECK_VERSION(2, 10, 0)
- text = atk_text_get_text_at_offset(ATK_TEXT(paragraph), 0, ATK_TEXT_BOUNDARY_LINE_START, &startOffset, &endOffset);
- g_assert(text);
- g_assert_cmpstr(text, ==, "foo bar baz");
- g_assert_cmpint(startOffset, ==, 0);
- g_assert_cmpint(endOffset, ==, 11);
- g_free(text);
-#else
- text = atk_text_get_string_at_offset(ATK_TEXT(paragraph), 0, ATK_TEXT_GRANULARITY_LINE, &startOffset, &endOffset);
- g_assert(text);
- g_assert_cmpstr(text, ==, "foo bar baz");
- g_assert_cmpint(startOffset, ==, 0);
- g_assert_cmpint(endOffset, ==, 11);
- g_free(text);
-#endif
-
- g_object_unref(paragraph);
-
- /* Third paragraph (link at the end). */
- paragraph = atk_object_ref_accessible_child(object, 2);
- g_assert(ATK_IS_TEXT(paragraph));
-
-#if !ATK_CHECK_VERSION(2, 10, 0)
- text = atk_text_get_text_at_offset(ATK_TEXT(paragraph), 0, ATK_TEXT_BOUNDARY_LINE_START, &startOffset, &endOffset);
- g_assert(text);
- g_assert_cmpstr(text, ==, "foo bar baz");
- g_assert_cmpint(startOffset, ==, 0);
- g_assert_cmpint(endOffset, ==, 11);
- g_free(text);
-#else
- text = atk_text_get_string_at_offset(ATK_TEXT(paragraph), 0, ATK_TEXT_GRANULARITY_LINE, &startOffset, &endOffset);
- g_assert(text);
- g_assert_cmpstr(text, ==, "foo bar baz");
- g_assert_cmpint(startOffset, ==, 0);
- g_assert_cmpint(endOffset, ==, 11);
- g_free(text);
-#endif
-
- g_object_unref(paragraph);
- g_object_unref(webView);
-}
-
-static void testWebkitAtkHypertextAndHyperlinks()
-{
- WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(webView);
- GtkAllocation allocation = { 0, 0, 800, 600 };
- gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
- webkit_web_view_load_string(webView, hypertextAndHyperlinks, 0, 0, 0);
-
- AtkObject* object = getWebAreaObject(webView);
- g_assert(object);
-
- AtkObject* paragraph1 = atk_object_ref_accessible_child(object, 0);
- g_assert(ATK_OBJECT(paragraph1));
- g_assert(atk_object_get_role(paragraph1) == ATK_ROLE_PARAGRAPH);
- g_assert(ATK_IS_HYPERTEXT(paragraph1));
-
- /* No links in the first paragraph. */
- gint nLinks = atk_hypertext_get_n_links(ATK_HYPERTEXT(paragraph1));
- g_assert_cmpint(nLinks, ==, 0);
-
- AtkObject* paragraph2 = atk_object_ref_accessible_child(object, 1);
- g_assert(ATK_OBJECT(paragraph2));
- g_assert(atk_object_get_role(paragraph2) == ATK_ROLE_PARAGRAPH);
- g_assert(ATK_IS_HYPERTEXT(paragraph2));
-
- /* Check links in the second paragraph.
- nLinks = atk_hypertext_get_n_links(ATK_HYPERTEXT(paragraph2));
- g_assert_cmpint(nLinks, ==, 3); */
-
- AtkHyperlink* hLink1 = atk_hypertext_get_link(ATK_HYPERTEXT(paragraph2), 0);
- g_assert(ATK_HYPERLINK(hLink1));
- AtkObject* hLinkObject1 = atk_hyperlink_get_object(hLink1, 0);
- g_assert(ATK_OBJECT(hLinkObject1));
- g_assert(atk_object_get_role(hLinkObject1) == ATK_ROLE_LINK);
- g_assert_cmpint(atk_hyperlink_get_start_index(hLink1), ==, 0);
- g_assert_cmpint(atk_hyperlink_get_end_index(hLink1), ==, 6);
- g_assert_cmpint(atk_hyperlink_get_n_anchors(hLink1), ==, 1);
- g_assert_cmpstr(atk_hyperlink_get_uri(hLink1, 0), ==, "http://foo.bar.baz/");
-
- AtkHyperlink* hLink2 = atk_hypertext_get_link(ATK_HYPERTEXT(paragraph2), 1);
- g_assert(ATK_HYPERLINK(hLink2));
- AtkObject* hLinkObject2 = atk_hyperlink_get_object(hLink2, 0);
- g_assert(ATK_OBJECT(hLinkObject2));
- g_assert(atk_object_get_role(hLinkObject2) == ATK_ROLE_LINK);
- g_assert_cmpint(atk_hyperlink_get_start_index(hLink2), ==, 12);
- g_assert_cmpint(atk_hyperlink_get_end_index(hLink2), ==, 32);
- g_assert_cmpint(atk_hyperlink_get_n_anchors(hLink2), ==, 1);
- g_assert_cmpstr(atk_hyperlink_get_uri(hLink2, 0), ==, "http://bar.baz.foo/");
-
- AtkHyperlink* hLink3 = atk_hypertext_get_link(ATK_HYPERTEXT(paragraph2), 2);
- g_assert(ATK_HYPERLINK(hLink3));
- AtkObject* hLinkObject3 = atk_hyperlink_get_object(hLink3, 0);
- g_assert(ATK_OBJECT(hLinkObject3));
- g_assert(atk_object_get_role(hLinkObject3) == ATK_ROLE_LINK);
- g_assert_cmpint(atk_hyperlink_get_start_index(hLink3), ==, 65);
- g_assert_cmpint(atk_hyperlink_get_end_index(hLink3), ==, 75);
- g_assert_cmpint(atk_hyperlink_get_n_anchors(hLink3), ==, 1);
- g_assert_cmpstr(atk_hyperlink_get_uri(hLink3, 0), ==, "http://baz.foo.bar/");
-
- AtkObject* list = atk_object_ref_accessible_child(object, 2);
- g_assert(ATK_OBJECT(list));
- g_assert(atk_object_get_role(list) == ATK_ROLE_LIST);
- g_assert_cmpint(atk_object_get_n_accessible_children(list), ==, 1);
-
- AtkObject* listItem = atk_object_ref_accessible_child(list, 0);
- g_assert(ATK_IS_TEXT(listItem));
- g_assert(ATK_IS_HYPERTEXT(listItem));
-
- AtkHyperlink* hLinkInListItem = atk_hypertext_get_link(ATK_HYPERTEXT(listItem), 0);
- g_assert(ATK_HYPERLINK(hLinkInListItem));
- AtkObject* hLinkObject = atk_hyperlink_get_object(hLinkInListItem, 0);
- g_assert(ATK_OBJECT(hLinkObject));
- g_assert(atk_object_get_role(hLinkObject) == ATK_ROLE_LINK);
- g_assert_cmpint(atk_hyperlink_get_start_index(hLinkInListItem), ==, 20);
- g_assert_cmpint(atk_hyperlink_get_end_index(hLinkInListItem), ==, 43);
- g_assert_cmpint(atk_hyperlink_get_n_anchors(hLinkInListItem), ==, 1);
- g_assert_cmpstr(atk_hyperlink_get_uri(hLinkInListItem, 0), ==, "http://foo.bar.baz/");
-
- /* Finally check the AtkAction interface for a given AtkHyperlink. */
- g_assert(ATK_IS_ACTION(hLink1));
- g_assert_cmpint(atk_action_get_n_actions(ATK_ACTION(hLink1)), ==, 1);
- g_assert_cmpstr(atk_action_get_keybinding(ATK_ACTION(hLink1), 0), ==, "");
- g_assert_cmpstr(atk_action_get_name(ATK_ACTION(hLink1), 0), ==, "jump");
- g_assert(atk_action_do_action(ATK_ACTION(hLink1), 0));
-
- g_object_unref(paragraph1);
- g_object_unref(paragraph2);
- g_object_unref(list);
- g_object_unref(listItem);
- g_object_unref(webView);
-}
-
-static void testWebkitAtkListsOfItems()
-{
- WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(webView);
- GtkAllocation allocation = { 0, 0, 800, 600 };
- gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
- webkit_web_view_load_string(webView, listsOfItems, 0, 0, 0);
-
- AtkObject* object = getWebAreaObject(webView);
- g_assert(object);
-
- /* Unordered list. */
-
- AtkObject* uList = atk_object_ref_accessible_child(object, 0);
- g_assert(ATK_OBJECT(uList));
- g_assert(atk_object_get_role(uList) == ATK_ROLE_LIST);
- g_assert_cmpint(atk_object_get_n_accessible_children(uList), ==, 3);
-
- AtkObject* item1 = atk_object_ref_accessible_child(uList, 0);
- AtkObject* item2 = atk_object_ref_accessible_child(uList, 1);
- AtkObject* item3 = atk_object_ref_accessible_child(uList, 2);
-
- g_assert_cmpint(atk_object_get_n_accessible_children(item1), ==, 0);
- g_assert_cmpint(atk_object_get_n_accessible_children(item2), ==, 1);
- g_assert_cmpint(atk_object_get_n_accessible_children(item3), ==, 1);
-
- g_object_unref(item1);
- g_object_unref(item2);
- g_object_unref(item3);
-
- /* Ordered list. */
-
- AtkObject* oList = atk_object_ref_accessible_child(object, 1);
- g_assert(ATK_OBJECT(oList));
- g_assert(atk_object_get_role(oList) == ATK_ROLE_LIST);
- g_assert_cmpint(atk_object_get_n_accessible_children(oList), ==, 3);
-
- item1 = atk_object_ref_accessible_child(oList, 0);
- item2 = atk_object_ref_accessible_child(oList, 1);
- item3 = atk_object_ref_accessible_child(oList, 2);
-
- g_assert_cmpint(atk_object_get_n_accessible_children(item1), ==, 0);
- g_assert_cmpint(atk_object_get_n_accessible_children(item2), ==, 1);
- g_assert_cmpint(atk_object_get_n_accessible_children(item3), ==, 1);
-
- g_object_unref(item1);
- g_object_unref(item2);
- g_object_unref(item3);
-
- g_object_unref(uList);
- g_object_unref(oList);
- g_object_unref(webView);
-}
-
-typedef enum {
- TEXT_CHANGE_INSERT = 1,
- TEXT_CHANGE_REMOVE = 2
-} TextChangeType;
-
-static gchar* textChangedResult = 0;
-
-static void textChangedCb(AtkText* text, gint pos, gint len, gchar* modifiedText, gpointer data)
-{
- g_assert(text && ATK_IS_OBJECT(text));
-
- TextChangeType type = GPOINTER_TO_INT(data);
- g_free(textChangedResult);
- textChangedResult = g_strdup_printf("|%d|%d|%d|'%s'|", type, pos, len, modifiedText);
-}
-
-static void testWebkitAtkTextChangedNotifications()
-{
- WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(webView);
- GtkAllocation allocation = { 0, 0, 800, 600 };
- gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
- webkit_web_view_load_string(webView, formWithTextInputs, 0, 0, 0);
-
- AtkObject* object = getWebAreaObject(webView);
- g_assert(object);
-
- AtkObject* form = atk_object_ref_accessible_child(object, 0);
- g_assert(ATK_IS_OBJECT(form));
-
- /* First check normal text entries. */
- AtkObject* textEntry = atk_object_ref_accessible_child(form, 0);
- g_assert(ATK_IS_EDITABLE_TEXT(textEntry));
- g_assert(atk_object_get_role(ATK_OBJECT(textEntry)) == ATK_ROLE_ENTRY);
-
- g_signal_connect(textEntry, "text-insert",
- G_CALLBACK(textChangedCb),
- GINT_TO_POINTER(TEXT_CHANGE_INSERT));
- g_signal_connect(textEntry, "text-remove",
- G_CALLBACK(textChangedCb),
- GINT_TO_POINTER(TEXT_CHANGE_REMOVE));
-
- gint pos = 0;
- atk_editable_text_insert_text(ATK_EDITABLE_TEXT(textEntry), "foo bar baz", 11, &pos);
- char* text = atk_text_get_text(ATK_TEXT(textEntry), 0, -1);
- g_assert_cmpstr(text, ==, "foo bar baz");
- g_assert_cmpstr(textChangedResult, ==, "|1|0|11|'foo bar baz'|");
- g_free(text);
-
- atk_editable_text_delete_text(ATK_EDITABLE_TEXT(textEntry), 4, 7);
- text = atk_text_get_text(ATK_TEXT(textEntry), 0, -1);
- g_assert_cmpstr(text, ==, "foo baz");
- g_assert_cmpstr(textChangedResult, ==, "|2|4|3|'bar'|");
- g_free(text);
-
- pos = 4;
- atk_editable_text_insert_text(ATK_EDITABLE_TEXT(textEntry), "qux quux tobeignored", 8, &pos);
- text = atk_text_get_text(ATK_TEXT(textEntry), 0, -1);
- g_assert_cmpstr(text, ==, "foo qux quux baz");
- g_assert_cmpstr(textChangedResult, ==, "|1|4|8|'qux quux'|");
- g_free(text);
-
- /* Now check for password entries. */
- AtkObject* passwordEntry = atk_object_ref_accessible_child(form, 1);
- g_assert(ATK_IS_EDITABLE_TEXT(passwordEntry));
- g_assert(atk_object_get_role(ATK_OBJECT(passwordEntry)) == ATK_ROLE_PASSWORD_TEXT);
-
- g_signal_connect(passwordEntry, "text-insert",
- G_CALLBACK(textChangedCb),
- GINT_TO_POINTER(TEXT_CHANGE_INSERT));
- g_signal_connect(passwordEntry, "text-remove",
- G_CALLBACK(textChangedCb),
- GINT_TO_POINTER(TEXT_CHANGE_REMOVE));
-
- pos = 0;
- /* A single bullet character is '\342\200\242' */
- atk_editable_text_insert_text(ATK_EDITABLE_TEXT(passwordEntry), "foobar", 6, &pos);
- g_assert_cmpstr(textChangedResult, ==, "|1|0|6|'\342\200\242\342\200\242\342\200\242\342\200\242\342\200\242\342\200\242'|");
- text = atk_text_get_text(ATK_TEXT(passwordEntry), 0, -1);
- g_assert_cmpstr(text, ==, "\342\200\242\342\200\242\342\200\242\342\200\242\342\200\242\342\200\242");
- g_free(text);
-
- atk_editable_text_delete_text(ATK_EDITABLE_TEXT(passwordEntry), 2, 4);
- g_assert_cmpstr(textChangedResult, ==, "|2|2|2|'\342\200\242\342\200\242'|");
-
- text = atk_text_get_text(ATK_TEXT(passwordEntry), 0, -1);
- g_assert_cmpstr(text, ==, "\342\200\242\342\200\242\342\200\242\342\200\242");
- g_free(text);
-
- pos = 3;
- atk_editable_text_insert_text(ATK_EDITABLE_TEXT(passwordEntry), "qux tobeignored", 3, &pos);
- g_assert_cmpstr(textChangedResult, ==, "|1|3|3|'\342\200\242\342\200\242\342\200\242'|");
-
- text = atk_text_get_text(ATK_TEXT(passwordEntry), 0, -1);
- g_assert_cmpstr(text, ==, "\342\200\242\342\200\242\342\200\242\342\200\242\342\200\242\342\200\242\342\200\242");
- g_free(text);
-
- g_free(textChangedResult);
-
- g_object_unref(form);
- g_object_unref(textEntry);
- g_object_unref(passwordEntry);
- g_object_unref(webView);
-}
-
-static void testWebkitAtkParentForRootObject()
-{
- WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- GtkAllocation allocation = { 0, 0, 800, 600 };
- gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
- webkit_web_view_load_string(webView, contents, 0, 0, 0);
-
- /* We need a parent container widget for the webview. */
- GtkWidget* parentContainer = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- g_object_ref_sink(parentContainer);
- gtk_container_add(GTK_CONTAINER(parentContainer), GTK_WIDGET(webView));
-
- AtkObject* axParent = gtk_widget_get_accessible(parentContainer);
- g_assert(ATK_IS_OBJECT(axParent));
-
- AtkObject* axRoot = gtk_widget_get_accessible(GTK_WIDGET(webView));
- g_assert(ATK_IS_OBJECT(axRoot));
-
- /* The child for the parent container's accessibility object
- should be the accessibility object for the WebView's root. */
- AtkObject* axParentChild = atk_object_ref_accessible_child(axParent, 0);
- g_assert(axParentChild == axRoot);
-
- /* Bottom-up navigation should match top-down one. */
- g_assert(atk_object_get_parent(axParentChild) == axParent);
-
- g_object_unref(axParentChild);
- g_object_unref(parentContainer);
-}
-
-static void testWebkitAtkSetParentForObject()
-{
- WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- GtkAllocation allocation = { 0, 0, 800, 600 };
- gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
- webkit_web_view_load_string(webView, contents, 0, 0, 0);
-
- /* Put the webview in a parent container widget to check that the
- normal behaviour keeps working as expected by default. */
- GtkWidget* parentContainer = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- g_object_ref_sink(parentContainer);
- gtk_container_add(GTK_CONTAINER(parentContainer), GTK_WIDGET(webView));
-
- AtkObject* axRoot = gtk_widget_get_accessible(GTK_WIDGET(webView));
- g_assert(ATK_IS_OBJECT(axRoot));
-
- AtkObject* axParent = gtk_widget_get_accessible(parentContainer);
- g_assert(ATK_IS_OBJECT(axParent));
-
- /* The parent of the root object is the parent container's a11y object. */
- g_assert(atk_object_get_parent(axRoot) == axParent);
-
- /* We now need to use something as a an alternative parent for
- the a11y object associated with the root of the DOM tree. */
- GtkWidget* alternativeParent = gtk_button_new();
- g_object_ref_sink(alternativeParent);
-
- AtkObject* axAlternativeParent = gtk_widget_get_accessible(alternativeParent);
- g_assert(ATK_IS_OBJECT(axAlternativeParent));
-
- /* Manually set the alternative parent's accessibility object as
- the parent for the WebKit accessibility root object and check. */
- atk_object_set_parent(axRoot, axAlternativeParent);
- g_assert(atk_object_get_parent(axRoot) == axAlternativeParent);
-
- g_object_unref(alternativeParent);
- g_object_unref(parentContainer);
-}
-
-#ifdef GTK_API_VERSION_2
-static void initializeTestingFramework(int argc, char** argv)
-{
- /* Ensure GAIL is the only module loaded. */
- g_setenv("GTK_MODULES", "gail", TRUE);
-
- /* Following lines were taken from gtk_test_init(). */
- g_test_init(&argc, &argv, 0);
- gtk_disable_setlocale();
- setlocale(LC_ALL, "C");
-
- gtk_init(&argc, &argv);
-}
-#endif
-
-int main(int argc, char** argv)
-{
-#ifdef GTK_API_VERSION_2
- /* We can't just call to gtk_test_init() in this case because its
- implementation makes sure that no GTK+ module will be loaded, and
- we will need to load GAIL for tests that need to use AtkObjects
- from non-WebKit GtkWidgets (e.g parentForRootObject).*/
- initializeTestingFramework(argc, argv);
-#else
- gtk_test_init(&argc, &argv, NULL);
-#endif
-
- g_test_bug_base("https://bugs.webkit.org/");
- g_test_add_func("/webkit/atk/caretOffsets", testWebkitAtkCaretOffsets);
- g_test_add_func("/webkit/atk/caretOffsetsAndExtranousWhiteSpaces", testWebkitAtkCaretOffsetsAndExtranousWhiteSpaces);
- g_test_add_func("/webkit/atk/comboBox", testWebkitAtkComboBox);
- g_test_add_func("/webkit/atk/documentLoadingEvents", testWebkitAtkDocumentLoadingEvents);
- g_test_add_func("/webkit/atk/embeddedObjects", testWebkitAtkEmbeddedObjects);
- g_test_add_func("/webkit/atk/getHeadersInTable", testWebkitAtkGetHeadersInTable);
- g_test_add_func("/webkit/atk/textAttributes", testWebkitAtkTextAttributes);
- g_test_add_func("/webkit/atk/textSelections", testWebkitAtkTextSelections);
- g_test_add_func("/webkit/atk/getExtents", testWebkitAtkGetExtents);
- g_test_add_func("/webkit/atk/hypertextAndHyperlinks", testWebkitAtkHypertextAndHyperlinks);
- g_test_add_func("/webkit/atk/layoutAndDataTables", testWebkitAtkLayoutAndDataTables);
- g_test_add_func("/webkit/atk/linksWithInlineImages", testWebkitAtkLinksWithInlineImages);
- g_test_add_func("/webkit/atk/listsOfItems", testWebkitAtkListsOfItems);
- g_test_add_func("/webkit/atk/textChangedNotifications", testWebkitAtkTextChangedNotifications);
- g_test_add_func("/webkit/atk/parentForRootObject", testWebkitAtkParentForRootObject);
- g_test_add_func("/webkit/atk/setParentForObject", testWebkitAtkSetParentForObject);
- return g_test_run ();
-}
-
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testatkroles.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testatkroles.c
deleted file mode 100644
index 88817cf8a..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testatkroles.c
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
- * Copyright © 2010 Joanmarie Diggs
- * Copyright © 2010 Igalia S.L.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <gtk/gtk.h>
-#include <webkit/webkit.h>
-
-/* Non form roles */
-#define HTML_DOCUMENT_FRAME "<html><body>This is a test.</body></html>"
-#define HTML_HEADING "<html><body><h1>1</h1><h2>2</h2><h3>3</h3><h4>4</h4><h5>5</h5><h6>6</h6></body></html>"
-#define HTML_IMAGE "<html><body><img src='foobar.png' alt='This is a test.'/></body></html>"
-#define HTML_LINK_TEXT "<html><body><a href='foobar.html'>This is a test.</a></body></html>"
-#define HTML_LIST "<html><body><ul><li>1</li><li>2</li></ul><ol><li>1</li><li>2</li></ol></body></html>"
-#define HTML_PARAGRAPH "<html><body><p>This is a test.</p></body></html>"
-#define HTML_SECTION "<html><body><div>This is a test.</div></body></html>"
-#define HTML_TABLE "<html><body><table border='1'><tr><td>This is</td><td>a test.</td></tr></table></body></html>"
-#define HTML_SEPARATOR "<html><body><hr/></body></html>"
-#define HTML_COMBOBOX "<html><body><select size='1'><option>one</option><option>two</option><option>three</option></select></body></html>"
-/* Form roles */
-#define HTML_FORM "<html><body><form>This is a test.</form></body></html>"
-#define HTML_CHECK_BOX "<html><body><input type='checkbox' />This is a test.</body></html>"
-#define HTML_LABELED_ENTRY "<html><body><label for='foo'>Name:</label><input type='text' id='foo' /></body></html>"
-#define HTML_LISTBOX "<html><body><select size='3'><option>one</option><option>two</option><option>three</option></select></body></html>"
-#define HTML_PASSWORD_TEXT "<html><body><input type='password' /></body></html>"
-#define HTML_PUSH_BUTTON "<html><body><input type='submit' value='ok' />This is a test.</body></html>"
-#define HTML_RADIO_BUTTON "<html><body><input type='radio' />This is a test.</body></html>"
-
-typedef struct {
- AtkObject* document;
- AtkObject* obj;
- AtkRole role;
- GtkWidget* webView;
- GtkAllocation alloc;
- GMainLoop* loop;
-} AtkRolesFixture;
-
-static gboolean finish_loading(AtkRolesFixture* fixture)
-{
- if (g_main_loop_is_running(fixture->loop))
- g_main_loop_quit(fixture->loop);
-
- // With the change to support WK2 accessibility, the root object
- // has changed and it's no longer the document frame, but a scroll
- // pane containing the document frame as its only child. See the
- // bug 72390 for more details on this change.
- // https://bugs.webkit.org/show_bug.cgi?id=72390
- AtkObject* rootObject = gtk_widget_get_accessible(fixture->webView);
- fixture->document = atk_object_ref_accessible_child(rootObject, 0);
- g_assert(fixture->document);
-
- // Remove the reference added by ref_accessible_child() and
- // return, since we don't need to keep that extra ref at all.
- g_object_unref(fixture->document);
- return FALSE;
-}
-
-static void atk_roles_fixture_setup(AtkRolesFixture* fixture, gconstpointer data)
-{
- fixture->loop = g_main_loop_new(NULL, TRUE);
- fixture->alloc = (GtkAllocation) { 0, 0, 800, 600 };
- fixture->webView = webkit_web_view_new();
- g_object_ref_sink(fixture->webView);
-
- gtk_widget_size_allocate(fixture->webView, &fixture->alloc);
-
- if (data != NULL)
- webkit_web_view_load_string(WEBKIT_WEB_VIEW (fixture->webView), (const char*) data, NULL, NULL, NULL);
-
- g_idle_add((GSourceFunc) finish_loading, fixture);
- g_main_loop_run(fixture->loop);
-}
-
-static void atk_roles_fixture_teardown(AtkRolesFixture* fixture, gconstpointer data)
-{
- g_object_unref(fixture->webView);
- g_main_loop_unref(fixture->loop);
-}
-
-static void get_child_and_test_role(AtkObject* obj, gint pos, AtkRole role)
-{
- AtkObject* child;
- AtkRole child_role;
-
- child = atk_object_ref_accessible_child(obj, pos);
- g_assert(child);
- child_role = atk_object_get_role(child);
- g_assert(child_role == role);
-
- g_object_unref(child);
-}
-
-static void test_webkit_atk_get_role_document_frame(AtkRolesFixture* fixture, gconstpointer data)
-{
- fixture->role = atk_object_get_role(fixture->document);
- g_assert(fixture->role == ATK_ROLE_DOCUMENT_WEB);
-}
-
-static void test_webkit_atk_get_role_heading(AtkRolesFixture* fixture, gconstpointer data)
-{
- get_child_and_test_role(fixture->document, 0, ATK_ROLE_HEADING);
- get_child_and_test_role(fixture->document, 1, ATK_ROLE_HEADING);
- get_child_and_test_role(fixture->document, 2, ATK_ROLE_HEADING);
- get_child_and_test_role(fixture->document, 3, ATK_ROLE_HEADING);
- get_child_and_test_role(fixture->document, 4, ATK_ROLE_HEADING);
- get_child_and_test_role(fixture->document, 5, ATK_ROLE_HEADING);
-}
-
-static void test_webkit_atk_get_role_image(AtkRolesFixture* fixture, gconstpointer data)
-{
- // This is an extraneous object of ATK_ROLE_PANEL which we should get rid of.
- fixture->obj = atk_object_ref_accessible_child(fixture->document, 0);
- g_assert(fixture->obj);
-
- get_child_and_test_role(fixture->obj, 0, ATK_ROLE_IMAGE);
-
- g_object_unref(fixture->obj);
-}
-
-static void test_webkit_atk_get_role_link(AtkRolesFixture* fixture, gconstpointer data)
-{
- // This is an extraneous object of ATK_ROLE_PANEL which we should get rid of.
- fixture->obj = atk_object_ref_accessible_child(fixture->document, 0);
- g_assert(fixture->obj);
-
- get_child_and_test_role(fixture->obj, 0, ATK_ROLE_LINK);
-
- g_object_unref(fixture->obj);
-}
-
-static void test_webkit_atk_get_role_list_and_item(AtkRolesFixture* fixture, gconstpointer data)
-{
- AtkObject* listObj;
-
- listObj = atk_object_ref_accessible_child(fixture->document, 0);
- g_assert(listObj);
- fixture->role = atk_object_get_role(listObj);
- g_assert(fixture->role == ATK_ROLE_LIST);
-
- get_child_and_test_role(listObj, 0, ATK_ROLE_LIST_ITEM);
- get_child_and_test_role(listObj, 1, ATK_ROLE_LIST_ITEM);
- g_object_unref(listObj);
-
- listObj = atk_object_ref_accessible_child(fixture->document, 1);
- g_assert(listObj);
- fixture->role = atk_object_get_role(listObj);
- g_assert(fixture->role == ATK_ROLE_LIST);
-
- get_child_and_test_role(listObj, 0, ATK_ROLE_LIST_ITEM);
- get_child_and_test_role(listObj, 1, ATK_ROLE_LIST_ITEM);
- g_object_unref(listObj);
-}
-
-static void test_webkit_atk_get_role_paragraph(AtkRolesFixture* fixture, gconstpointer data)
-{
- get_child_and_test_role(fixture->document, 0, ATK_ROLE_PARAGRAPH);
-}
-
-static void test_webkit_atk_get_role_section(AtkRolesFixture* fixture, gconstpointer data)
-{
- get_child_and_test_role(fixture->document, 0, ATK_ROLE_SECTION);
-}
-
-// Does not yet test table cells because of bug 30895.
-static void test_webkit_atk_get_role_table(AtkRolesFixture* fixture, gconstpointer data)
-{
- get_child_and_test_role(fixture->document, 0, ATK_ROLE_TABLE);
-}
-
-static void test_webkit_atk_get_role_separator(AtkRolesFixture *fixture, gconstpointer data)
-{
- get_child_and_test_role(fixture->document, 0, ATK_ROLE_SEPARATOR);
-}
-
-static void test_webkit_atk_get_role_combobox(AtkRolesFixture *fixture, gconstpointer data)
-{
- AtkObject* comboboxMenu;
-
- // This is an extraneous object of ATK_ROLE_PANEL which we should get rid of.
- fixture->obj = atk_object_ref_accessible_child(fixture->document, 0);
- g_assert(fixture->obj);
-
- fixture->obj = atk_object_ref_accessible_child(fixture->obj, 0);
- g_assert(fixture->obj);
- fixture->role = atk_object_get_role(fixture->obj);
- g_assert(fixture->role == ATK_ROLE_COMBO_BOX);
-
- comboboxMenu = atk_object_ref_accessible_child(fixture->obj, 0);
- g_assert(comboboxMenu);
- fixture->role = atk_object_get_role(comboboxMenu);
- g_assert(fixture->role == ATK_ROLE_MENU);
-
- get_child_and_test_role(comboboxMenu, 0, ATK_ROLE_MENU_ITEM);
- get_child_and_test_role(comboboxMenu, 1, ATK_ROLE_MENU_ITEM);
- get_child_and_test_role(comboboxMenu, 2, ATK_ROLE_MENU_ITEM);
-
- g_object_unref(fixture->obj);
- g_object_unref(comboboxMenu);
-}
-
-/* Form roles */
-static void test_webkit_atk_get_role_form(AtkRolesFixture *fixture, gconstpointer data)
-{
- get_child_and_test_role(fixture->document, 0, ATK_ROLE_FORM);
-}
-
-static void test_webkit_atk_get_role_check_box(AtkRolesFixture* fixture, gconstpointer data)
-{
- // This is an extraneous object of ATK_ROLE_PANEL which we should get rid of.
- fixture->obj = atk_object_ref_accessible_child(fixture->document, 0);
- g_assert(fixture->obj);
-
- get_child_and_test_role(fixture->obj, 0, ATK_ROLE_CHECK_BOX);
-
- g_object_unref(fixture->obj);
-}
-
-static void test_webkit_atk_get_role_entry(AtkRolesFixture* fixture, gconstpointer data)
-{
- // This is an extraneous object of ATK_ROLE_PANEL which we should get rid of.
- fixture->obj = atk_object_ref_accessible_child(fixture->document, 0);
- g_assert(fixture->obj);
-
- get_child_and_test_role(fixture->obj, 1, ATK_ROLE_ENTRY);
-
- g_object_unref(fixture->obj);
-}
-
-static void test_webkit_atk_get_role_label(AtkRolesFixture* fixture, gconstpointer data)
-{
- // This is an extraneous object of ATK_ROLE_PANEL which we should get rid of.
- fixture->obj = atk_object_ref_accessible_child(fixture->document, 0);
- g_assert(fixture->obj);
-
- get_child_and_test_role(fixture->obj, 0, ATK_ROLE_LABEL);
-
- g_object_unref(fixture->obj);
-}
-
-static void test_webkit_atk_get_role_listbox(AtkRolesFixture* fixture, gconstpointer data)
-{
- AtkObject* listboxObj;
- // This is an extraneous object of ATK_ROLE_PANEL which we should get rid of.
- fixture->obj = atk_object_ref_accessible_child(fixture->document, 0);
- g_assert(fixture->obj);
-
- listboxObj = atk_object_ref_accessible_child(fixture->obj, 0);
- g_assert(listboxObj);
- fixture->role = atk_object_get_role(listboxObj);
- g_assert(fixture->role == ATK_ROLE_LIST);
-
- get_child_and_test_role(listboxObj, 0, ATK_ROLE_LIST_ITEM);
- get_child_and_test_role(listboxObj, 1, ATK_ROLE_LIST_ITEM);
- get_child_and_test_role(listboxObj, 2, ATK_ROLE_LIST_ITEM);
-
- g_object_unref(fixture->obj);
- g_object_unref(listboxObj);
-}
-
-static void test_webkit_atk_get_role_password_text(AtkRolesFixture* fixture, gconstpointer data)
-{
- // This is an extraneous object of ATK_ROLE_PANEL which we should get rid of.
- fixture->obj = atk_object_ref_accessible_child(fixture->document, 0);
- g_assert(fixture->obj);
-
- get_child_and_test_role(fixture->obj, 0, ATK_ROLE_PASSWORD_TEXT);
-
- g_object_unref(fixture->obj);
-}
-
-static void test_webkit_atk_get_role_push_button(AtkRolesFixture* fixture, gconstpointer data)
-{
- // This is an extraneous object of ATK_ROLE_PANEL which we should get rid of.
- fixture->obj = atk_object_ref_accessible_child(fixture->document, 0);
- g_assert(fixture->obj);
-
- get_child_and_test_role(fixture->obj, 0, ATK_ROLE_PUSH_BUTTON);
-
- g_object_unref(fixture->obj);
-}
-
-static void test_webkit_atk_get_role_radio_button(AtkRolesFixture* fixture, gconstpointer data)
-{
- // This is an extraneous object of ATK_ROLE_PANEL which we should get rid of.
- fixture->obj = atk_object_ref_accessible_child(fixture->document, 0);
- g_assert(fixture->obj);
-
- get_child_and_test_role(fixture->obj, 0, ATK_ROLE_RADIO_BUTTON);
-
- g_object_unref(fixture->obj);
-}
-
-int main(int argc, char** argv)
-{
- gtk_test_init(&argc, &argv, NULL);
-
- g_test_bug_base("https://bugs.webkit.org/");
-
- g_test_add("/webkit/atk/test_webkit_atk_get_role_document_frame",
- AtkRolesFixture, HTML_DOCUMENT_FRAME,
- atk_roles_fixture_setup,
- test_webkit_atk_get_role_document_frame,
- atk_roles_fixture_teardown);
-
- g_test_add("/webkit/atk/test_webkit_atk_get_role_heading",
- AtkRolesFixture, HTML_HEADING,
- atk_roles_fixture_setup,
- test_webkit_atk_get_role_heading,
- atk_roles_fixture_teardown);
-
- g_test_add("/webkit/atk/test_webkit_atk_get_role_image",
- AtkRolesFixture, HTML_IMAGE,
- atk_roles_fixture_setup,
- test_webkit_atk_get_role_image,
- atk_roles_fixture_teardown);
-
- g_test_add("/webkit/atk/test_webkit_atk_get_role_link",
- AtkRolesFixture, HTML_LINK_TEXT,
- atk_roles_fixture_setup,
- test_webkit_atk_get_role_link,
- atk_roles_fixture_teardown);
-
- g_test_add("/webkit/atk/test_webkit_atk_get_role_list_and_item",
- AtkRolesFixture, HTML_LIST,
- atk_roles_fixture_setup,
- test_webkit_atk_get_role_list_and_item,
- atk_roles_fixture_teardown);
-
- g_test_add("/webkit/atk/test_webkit_atk_get_role_paragraph",
- AtkRolesFixture, HTML_PARAGRAPH,
- atk_roles_fixture_setup,
- test_webkit_atk_get_role_paragraph,
- atk_roles_fixture_teardown);
-
- g_test_add("/webkit/atk/test_webkit_atk_get_role_section",
- AtkRolesFixture, HTML_SECTION,
- atk_roles_fixture_setup,
- test_webkit_atk_get_role_section,
- atk_roles_fixture_teardown);
-
- g_test_add("/webkit/atk/test_webkit_atk_get_role_table",
- AtkRolesFixture, HTML_TABLE,
- atk_roles_fixture_setup,
- test_webkit_atk_get_role_table,
- atk_roles_fixture_teardown);
-
- g_test_add("/webkit/atk/test_webkit_atk_get_role_separator",
- AtkRolesFixture, HTML_SEPARATOR,
- atk_roles_fixture_setup,
- test_webkit_atk_get_role_separator,
- atk_roles_fixture_teardown);
-
- g_test_add("/webkit/atk/test_webkit_atk_get_role_combobox",
- AtkRolesFixture, HTML_COMBOBOX,
- atk_roles_fixture_setup,
- test_webkit_atk_get_role_combobox,
- atk_roles_fixture_teardown);
-
- /* Form roles */
- g_test_add("/webkit/atk/test_webkit_atk_get_role_form",
- AtkRolesFixture, HTML_FORM,
- atk_roles_fixture_setup,
- test_webkit_atk_get_role_form,
- atk_roles_fixture_teardown);
- g_test_add("/webkit/atk/test_webkit_atk_get_role_check_box",
- AtkRolesFixture, HTML_CHECK_BOX,
- atk_roles_fixture_setup,
- test_webkit_atk_get_role_check_box,
- atk_roles_fixture_teardown);
-
- g_test_add("/webkit/atk/test_webkit_atk_get_role_entry",
- AtkRolesFixture, HTML_LABELED_ENTRY,
- atk_roles_fixture_setup,
- test_webkit_atk_get_role_entry,
- atk_roles_fixture_teardown);
-
- g_test_add("/webkit/atk/test_webkit_atk_get_role_label",
- AtkRolesFixture, HTML_LABELED_ENTRY,
- atk_roles_fixture_setup,
- test_webkit_atk_get_role_label,
- atk_roles_fixture_teardown);
-
- g_test_add("/webkit/atk/test_webkit_atk_get_role_listbox",
- AtkRolesFixture, HTML_LISTBOX,
- atk_roles_fixture_setup,
- test_webkit_atk_get_role_listbox,
- atk_roles_fixture_teardown);
-
- g_test_add("/webkit/atk/test_webkit_atk_get_role_password_text",
- AtkRolesFixture, HTML_PASSWORD_TEXT,
- atk_roles_fixture_setup,
- test_webkit_atk_get_role_password_text,
- atk_roles_fixture_teardown);
-
- g_test_add("/webkit/atk/test_webkit_atk_get_role_push_button",
- AtkRolesFixture, HTML_PUSH_BUTTON,
- atk_roles_fixture_setup,
- test_webkit_atk_get_role_push_button,
- atk_roles_fixture_teardown);
-
- g_test_add("/webkit/atk/test_webkit_atk_get_role_radio_button",
- AtkRolesFixture, HTML_RADIO_BUTTON,
- atk_roles_fixture_setup,
- test_webkit_atk_get_role_radio_button,
- atk_roles_fixture_teardown);
-
- return g_test_run();
-}
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testcontextmenu.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testcontextmenu.c
deleted file mode 100644
index bc941a756..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testcontextmenu.c
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * Copyright (C) 2012 Igalia S.L.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2,1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include <webkit/webkit.h>
-
-typedef struct {
- char *data;
- guint flag;
-} TestInfo;
-
-static GMainLoop *loop;
-
-typedef struct {
- WebKitWebView *webView;
- TestInfo *info;
-} ContextMenuFixture;
-
-static TestInfo *testInfoNew(const char *data, guint flag)
-{
- TestInfo *info = g_slice_new(TestInfo);
- info->data = g_strdup(data);
- info->flag = flag;
-
- return info;
-}
-
-static void testInfoDestroy(TestInfo *info)
-{
- g_free(info->data);
- g_slice_free(TestInfo, info);
-}
-
-static void contextMenuFixtureSetup(ContextMenuFixture *fixture, gconstpointer data)
-{
- fixture->webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- loop = g_main_loop_new(NULL, TRUE);
- fixture->info = (TestInfo *)data;
-}
-
-static void contextMenuFixtureTeardown(ContextMenuFixture *fixture, gconstpointer data)
-{
- g_object_unref(fixture->webView);
- g_main_loop_unref(loop);
- testInfoDestroy(fixture->info);
-}
-
-static GList *checkAction(GList *iter, WebKitContextMenuAction action)
-{
- GtkMenuItem *item = (GtkMenuItem *)iter->data;
-
- g_assert(GTK_IS_MENU_ITEM(item));
- g_assert(webkit_context_menu_item_get_action(item) == action);
-
- return iter->next;
-}
-
-static GList *checkActionWithSubmenu(GList *iter, WebKitContextMenuAction action)
-{
- GtkMenuItem *item = (GtkMenuItem *)iter->data;
-
- g_assert(GTK_IS_MENU_ITEM(item));
- g_assert(webkit_context_menu_item_get_action(item) == action);
- g_assert(GTK_IS_MENU(gtk_menu_item_get_submenu(item)));
-
- return iter->next;
-}
-
-static GList *checkSeparator(GList *iter)
-{
- GtkMenuItem *item = (GtkMenuItem *)iter->data;
-
- g_assert(GTK_IS_SEPARATOR_MENU_ITEM(item));
-
- return iter->next;
-}
-
-static gboolean contextMenuCallback(WebKitWebView *webView, GtkWidget *defaultMenu, WebKitHitTestResult *hitTestResult, gboolean keyboardMode, gpointer userData)
-{
- TestInfo *info = (TestInfo *)userData;
- guint context;
- GList *items;
- GList *iter;
-
- /* Check signal parameters */
- g_assert(WEBKIT_IS_WEB_VIEW(webView));
- g_assert(GTK_IS_MENU(defaultMenu));
- g_assert(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult));
- g_assert(!keyboardMode);
-
- g_object_get(hitTestResult, "context", &context, NULL);
- g_assert(context & info->flag);
-
- items = gtk_container_get_children(GTK_CONTAINER(defaultMenu));
- switch (info->flag) {
- case WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT:
- iter = items;
- iter = checkAction(iter, WEBKIT_CONTEXT_MENU_ACTION_GO_BACK);
- iter = checkAction(iter, WEBKIT_CONTEXT_MENU_ACTION_GO_FORWARD);
- iter = checkAction(iter, WEBKIT_CONTEXT_MENU_ACTION_STOP);
- iter = checkAction(iter, WEBKIT_CONTEXT_MENU_ACTION_RELOAD);
- g_assert(!iter);
-
- break;
- case WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE:
- iter = items;
- iter = checkAction(iter, WEBKIT_CONTEXT_MENU_ACTION_OPEN_IMAGE_IN_NEW_WINDOW);
- iter = checkAction(iter, WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_IMAGE_TO_DISK);
- iter = checkAction(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_TO_CLIPBOARD);
- iter = checkAction(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_URL_TO_CLIPBOARD);
- g_assert(!iter);
-
- break;
- case WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE:
- iter = items;
- iter = checkAction(iter, WEBKIT_CONTEXT_MENU_ACTION_CUT);
- iter = checkAction(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY);
- iter = checkAction(iter, WEBKIT_CONTEXT_MENU_ACTION_PASTE);
- iter = checkAction(iter, WEBKIT_CONTEXT_MENU_ACTION_DELETE);
- iter = checkSeparator(iter);
- iter = checkAction(iter, WEBKIT_CONTEXT_MENU_ACTION_SELECT_ALL);
- iter = checkSeparator(iter);
- iter = checkActionWithSubmenu(iter, WEBKIT_CONTEXT_MENU_ACTION_INPUT_METHODS);
- iter = checkActionWithSubmenu(iter, WEBKIT_CONTEXT_MENU_ACTION_UNICODE);
- g_assert(!iter);
-
- break;
- case WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK:
- iter = items;
- iter = checkAction(iter, WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK);
- iter = checkAction(iter, WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK_IN_NEW_WINDOW);
- iter = checkAction(iter, WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_LINK_TO_DISK);
- iter = checkAction(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY_LINK_TO_CLIPBOARD);
- g_assert(!iter);
-
- break;
- default:
- g_assert_not_reached();
- }
-
- g_list_free(items);
- g_main_loop_quit(loop);
-
- return TRUE;
-}
-
-static void pushEvent(WebKitWebView *webView)
-{
- GdkEvent *event = gdk_event_new(GDK_BUTTON_PRESS);
-#if GTK_CHECK_VERSION(3, 0, 0)
- GdkDeviceManager *deviceManager;
-#endif
-
- event->any.window = g_object_ref(gtk_widget_get_window(GTK_WIDGET(webView)));
- event->any.send_event = FALSE;
- event->button.time = GDK_CURRENT_TIME;
- event->button.button = 3;
- event->button.x = event->button.y = 5;
- event->button.x_root = event->button.x;
- event->button.y_root = event->button.y;
-#if GTK_CHECK_VERSION(3, 0, 0)
- deviceManager = gdk_display_get_device_manager(gdk_display_get_default());
- event->button.device = gdk_device_manager_get_client_pointer(deviceManager);
-#endif
-
- gdk_event_put(event);
- gdk_event_free(event);
-}
-
-static void loadStatusCallback(WebKitWebView *webView, GParamSpec *spec, gpointer data)
-{
- WebKitLoadStatus status = webkit_web_view_get_load_status(webView);
- TestInfo *info = (TestInfo *)data;
-
- g_assert(status != WEBKIT_LOAD_FAILED);
-
- if (status != WEBKIT_LOAD_FINISHED)
- return;
-
- g_signal_connect(webView, "context-menu", G_CALLBACK(contextMenuCallback), info);
- pushEvent(webView);
-}
-
-static gboolean mapEventCallback(GtkWidget *widget, GdkEvent *event, gpointer data)
-{
- gtk_widget_grab_focus(widget);
- ContextMenuFixture *fixture = (ContextMenuFixture *)data;
- webkit_web_view_load_string(fixture->webView,
- fixture->info->data,
- "text/html",
- "utf-8",
- "file://");
- g_signal_connect(fixture->webView, "notify::load-status", G_CALLBACK(loadStatusCallback), fixture->info);
- return FALSE;
-}
-
-static void testContextMenu(ContextMenuFixture *fixture, gconstpointer data)
-{
- GtkAllocation allocation = { 0, 0, 50, 50 };
- GtkWidget *window = gtk_window_new(GTK_WINDOW_POPUP);
-
- gtk_window_resize(GTK_WINDOW(window), 50, 50);
- gtk_window_move(GTK_WINDOW(window), 0, 0);
- gtk_widget_size_allocate(GTK_WIDGET(fixture->webView), &allocation);
- gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(fixture->webView));
- g_signal_connect(window, "map-event", G_CALLBACK(mapEventCallback), fixture);
- gtk_widget_show_all(window);
-
- g_main_loop_run(loop);
-}
-
-static gboolean contextMenuCustomItemCallback(WebKitWebView *webView, GtkWidget *defaultMenu, WebKitHitTestResult *hitTestResult, gboolean keyboardMode, gpointer userData)
-{
- TestInfo *info = (TestInfo *)userData;
- guint context;
- GList *items;
- GList *iter;
- GtkWidget *menuItem;
- GtkAction *action;
-
- /* Check signal parameters */
- g_assert(WEBKIT_IS_WEB_VIEW(webView));
- g_assert(GTK_IS_MENU(defaultMenu));
- g_assert(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult));
- g_assert(!keyboardMode);
-
- g_object_get(hitTestResult, "context", &context, NULL);
- g_assert(context & info->flag);
-
- action = gtk_action_new("TestAction", "Custom Action", "Custom Action Tooltip", NULL);
- menuItem = gtk_action_create_menu_item(action);
- g_object_unref(action);
-
- gtk_menu_shell_append(GTK_MENU_SHELL(defaultMenu), menuItem);
- gtk_widget_show(menuItem);
-
- items = gtk_container_get_children(GTK_CONTAINER(defaultMenu));
- iter = items;
- iter = checkAction(iter, WEBKIT_CONTEXT_MENU_ACTION_GO_BACK);
- iter = checkAction(iter, WEBKIT_CONTEXT_MENU_ACTION_GO_FORWARD);
- iter = checkAction(iter, WEBKIT_CONTEXT_MENU_ACTION_STOP);
- iter = checkAction(iter, WEBKIT_CONTEXT_MENU_ACTION_RELOAD);
- iter = checkAction(iter, WEBKIT_CONTEXT_MENU_ACTION_NO_ACTION);
- g_assert(!iter);
-
- g_list_free(items);
- g_main_loop_quit(loop);
-
- return TRUE;
-}
-
-static void testContextMenuCustomItem(ContextMenuFixture *fixture, gconstpointer data)
-{
- GtkWidget *window = gtk_window_new(GTK_WINDOW_POPUP);
- gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(fixture->webView));
- gtk_widget_show_all(window);
- gtk_widget_grab_focus(GTK_WIDGET(fixture->webView));
-
- webkit_web_view_load_string(fixture->webView,
- fixture->info->data,
- "text/html",
- "utf-8",
- "file://");
- g_signal_connect(fixture->webView, "context-menu", G_CALLBACK(contextMenuCustomItemCallback), fixture->info);
- pushEvent(fixture->webView);
-}
-
-int main(int argc, char **argv)
-{
- gtk_test_init(&argc, &argv, NULL);
-
- // Get rid of runtime warnings about deprecated properties and signals, since they break the tests.
- g_setenv("G_ENABLE_DIAGNOSTIC", "0", TRUE);
-
- g_test_bug_base("https://bugs.webkit.org/");
-
- g_test_add("/webkit/testcontextmenu/document", ContextMenuFixture,
- testInfoNew("<html><body><h1>WebKitGTK+!</h1></body></html>",
- WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT),
- contextMenuFixtureSetup, testContextMenu, contextMenuFixtureTeardown);
- /* We hardcode all elements to be at 0,0 so that we know where to generate the button events */
- g_test_add("/webkit/testcontextmenu/image", ContextMenuFixture,
- testInfoNew("<html><body><img style='position:absolute; left:0; top:0' src='0xdeadbeef' width=50 height=50></img></body></html>",
- WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE),
- contextMenuFixtureSetup, testContextMenu, contextMenuFixtureTeardown);
- g_test_add("/webkit/testcontextmenu/editable", ContextMenuFixture,
- testInfoNew("<html><body><input style='position:absolute; left:0; top:0' size='35'></input>></body></html>",
- WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE),
- contextMenuFixtureSetup, testContextMenu, contextMenuFixtureTeardown);
- g_test_add("/webkit/testcontextmenu/link", ContextMenuFixture,
- testInfoNew("<html><body><a style='position:absolute; left:0; top:0' href='http://www.example.com'>HELLO WORLD</a></body></html>",
- WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK),
- contextMenuFixtureSetup, testContextMenu, contextMenuFixtureTeardown);
- g_test_add("/webkit/testcontextmenu/customitem", ContextMenuFixture,
- testInfoNew("<html><body><h1>WebKitGTK+!</h1></body></html>",
- WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT),
- contextMenuFixtureSetup, testContextMenuCustomItem, contextMenuFixtureTeardown);
-
- return g_test_run();
-}
-
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testcopyandpaste.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testcopyandpaste.c
deleted file mode 100644
index bb38ea66b..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testcopyandpaste.c
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Copyright (C) 2010 Igalia S.L.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2,1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <glib/gstdio.h>
-#include <webkit/webkit.h>
-#include <JavaScriptCore/JSStringRef.h>
-#include <JavaScriptCore/JSContextRef.h>
-
-typedef struct {
- char* page;
- char* expectedContent;
-} TestInfo;
-
-typedef struct {
- GtkWidget* window;
- WebKitWebView* webView;
- GMainLoop* loop;
- TestInfo* info;
-} CopyAndPasteFixture;
-
-TestInfo*
-test_info_new(const char* page, const char* expectedContent)
-{
- TestInfo* info;
- info = g_slice_new0(TestInfo);
- info->page = g_strdup(page);
- if (expectedContent)
- info->expectedContent = g_strdup(expectedContent);
- return info;
-}
-
-void
-test_info_destroy(TestInfo* info)
-{
- g_free(info->page);
- g_free(info->expectedContent);
- g_slice_free(TestInfo, info);
-}
-
-static void copy_and_paste_fixture_setup(CopyAndPasteFixture* fixture, gconstpointer data)
-{
- fixture->loop = g_main_loop_new(NULL, TRUE);
-
- fixture->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- fixture->webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
-
- gtk_container_add(GTK_CONTAINER(fixture->window), GTK_WIDGET(fixture->webView));
-}
-
-static void copy_and_paste_fixture_teardown(CopyAndPasteFixture* fixture, gconstpointer data)
-{
- gtk_widget_destroy(fixture->window);
- g_main_loop_unref(fixture->loop);
- test_info_destroy(fixture->info);
-}
-
-static void load_status_cb(WebKitWebView* webView, GParamSpec* spec, gpointer data)
-{
- CopyAndPasteFixture* fixture = (CopyAndPasteFixture*)data;
- WebKitLoadStatus status = webkit_web_view_get_load_status(webView);
- if (status != WEBKIT_LOAD_FINISHED)
- return;
-
- GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
- gtk_clipboard_clear(clipboard);
-
- webkit_web_view_copy_clipboard(webView);
-
- gchar* text = gtk_clipboard_wait_for_text(clipboard);
- g_assert(text || !fixture->info->expectedContent);
- g_assert(!text || !strcmp(text, fixture->info->expectedContent));
- g_free(text);
-
- // Verify that the markup starts with the proper content-type meta tag prefix.
- GtkSelectionData* selectionData = gtk_clipboard_wait_for_contents(clipboard, gdk_atom_intern("text/html", FALSE));
- if (selectionData) {
- static const char* markupPrefix = "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">";
- char* markup = g_strndup((const char*) gtk_selection_data_get_data(selectionData),
- gtk_selection_data_get_length(selectionData));
- g_assert(strlen(markupPrefix) <= strlen(markup));
- g_assert(!strncmp(markupPrefix, markup, strlen(markupPrefix)));
- g_free(markup);
- }
-
- g_assert(!gtk_clipboard_wait_is_uris_available(clipboard));
- g_assert(!gtk_clipboard_wait_is_image_available(clipboard));
-
- g_main_loop_quit(fixture->loop);
-}
-
-gboolean map_event_cb(GtkWidget *widget, GdkEvent* event, gpointer data)
-{
- CopyAndPasteFixture* fixture = (CopyAndPasteFixture*)data;
- webkit_web_view_load_string(fixture->webView, fixture->info->page,
- "text/html", "utf-8", "file://");
- return FALSE;
-}
-
-static void test_copy_and_paste(CopyAndPasteFixture* fixture, gconstpointer data)
-{
- fixture->info = (TestInfo*)data;
- g_signal_connect(fixture->window, "map-event",
- G_CALLBACK(map_event_cb), fixture);
-
- gtk_widget_show(fixture->window);
- gtk_widget_show(GTK_WIDGET(fixture->webView));
- gtk_window_present(GTK_WINDOW(fixture->window));
- gtk_widget_grab_focus(GTK_WIDGET(fixture->webView));
-
- g_signal_connect(fixture->webView, "notify::load-status",
- G_CALLBACK(load_status_cb), fixture);
-
- g_main_loop_run(fixture->loop);
-}
-
-static CopyAndPasteFixture* currentFixture;
-static JSValueRef runPasteTestCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
- gtk_widget_grab_focus(GTK_WIDGET(currentFixture->webView));
-
- // Simulate a paste keyboard sequence.
- GdkEvent* event = gdk_event_new(GDK_KEY_PRESS);
- event->key.keyval = gdk_unicode_to_keyval('v');
- event->key.state = GDK_CONTROL_MASK;
- event->key.window = gtk_widget_get_window(GTK_WIDGET(currentFixture->webView));
- g_object_ref(event->key.window);
-#ifndef GTK_API_VERSION_2
- GdkDeviceManager* manager = gdk_display_get_device_manager(gdk_window_get_display(event->key.window));
- gdk_event_set_device(event, gdk_device_manager_get_client_pointer(manager));
-#endif
-
- GdkKeymapKey* keys;
- gint n_keys;
- if (gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), event->key.keyval, &keys, &n_keys)) {
- event->key.hardware_keycode = keys[0].keycode;
- g_free(keys);
- }
-
- gtk_main_do_event(event);
- event->key.type = GDK_KEY_RELEASE;
- gtk_main_do_event(event);
- gdk_event_free(event);
-
- JSStringRef scriptString = JSStringCreateWithUTF8CString("document.body.innerHTML;");
- JSValueRef value = JSEvaluateScript(context, scriptString, 0, 0, 0, 0);
- JSStringRelease(scriptString);
-
- g_assert(JSValueIsString(context, value));
- JSStringRef actual = JSValueToStringCopy(context, value, exception);
- g_assert(!exception || !*exception);
- g_assert(currentFixture->info->expectedContent);
- JSStringRef expected = JSStringCreateWithUTF8CString(currentFixture->info->expectedContent);
- g_assert(JSStringIsEqual(expected, actual));
-
- JSStringRelease(expected);
- JSStringRelease(actual);
- g_main_loop_quit(currentFixture->loop);
- return JSValueMakeUndefined(context);
-}
-
-static void window_object_cleared_callback(WebKitWebView* web_view, WebKitWebFrame* web_frame, JSGlobalContextRef context, JSObjectRef window_object, gpointer data)
-{
- JSStringRef name = JSStringCreateWithUTF8CString("runTest");
- JSObjectRef testComplete = JSObjectMakeFunctionWithCallback(context, name, runPasteTestCallback);
- JSObjectSetProperty(context, window_object, name, testComplete, kJSPropertyAttributeNone, 0);
- JSStringRelease(name);
-}
-
-static void pasting_test_get_data_callback(GtkClipboard* clipboard, GtkSelectionData* selection_data, guint info, gpointer data)
-{
- gtk_selection_data_set(selection_data, gdk_atom_intern("text/html", FALSE), 8, (const guchar*) data, strlen((char*)data) + 1);
-}
-
-static void pasting_test_clear_data_callback(GtkClipboard* clipboard, gpointer data)
-{
- g_free(data);
-}
-
-static void test_pasting_markup(CopyAndPasteFixture* fixture, gconstpointer data)
-{
- fixture->info = (TestInfo*)data;
- currentFixture = fixture;
-
- GtkTargetList* targetList = gtk_target_list_new(0, 0);
- gtk_target_list_add(targetList, gdk_atom_intern("text/html", FALSE), 0, 0);
-
- int numberOfTargets = 1;
- GtkTargetEntry* targetTable = gtk_target_table_new_from_list(targetList, &numberOfTargets);
- gtk_clipboard_set_with_data(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD),
- targetTable, numberOfTargets,
- pasting_test_get_data_callback,
- pasting_test_clear_data_callback,
- g_strdup(fixture->info->expectedContent));
- gtk_target_list_unref(targetList);
- gtk_target_table_free(targetTable, numberOfTargets);
-
- g_signal_connect(fixture->window, "map-event",
- G_CALLBACK(map_event_cb), fixture);
- g_signal_connect(fixture->webView, "window-object-cleared",
- G_CALLBACK(window_object_cleared_callback), fixture);
-
- gtk_widget_show(fixture->window);
- gtk_widget_show(GTK_WIDGET(fixture->webView));
- gtk_window_present(GTK_WINDOW(fixture->window));
-
- g_main_loop_run(fixture->loop);
-}
-
-
-int main(int argc, char** argv)
-{
- gtk_test_init(&argc, &argv, NULL);
-
- g_test_bug_base("https://bugs.webkit.org/");
- const char* selected_span_html = "<html><body>"
- "<span id=\"mainspan\">All work and no play <span>make Jack a dull</span> boy.</span>"
- "<script>document.getSelection().collapse();\n"
- "document.getSelection().selectAllChildren(document.getElementById('mainspan'));\n"
- "</script></body></html>";
- const char* no_selection_html = "<html><body>"
- "<span id=\"mainspan\">All work and no play <span>make Jack a dull</span> boy</span>"
- "<script>document.getSelection().collapse();\n"
- "</script></body></html>";
-
- g_test_add("/webkit/copyandpaste/selection", CopyAndPasteFixture,
- test_info_new(selected_span_html, "All work and no play make Jack a dull boy."),
- copy_and_paste_fixture_setup,
- test_copy_and_paste,
- copy_and_paste_fixture_teardown);
- g_test_add("/webkit/copyandpaste/no-selection", CopyAndPasteFixture,
- test_info_new(no_selection_html, 0),
- copy_and_paste_fixture_setup,
- test_copy_and_paste,
- copy_and_paste_fixture_teardown);
-
- const char* paste_test_html = "<html>"
- "<body onLoad=\"document.body.focus(); runTest();\" contentEditable=\"true\">"
- "</body></html>";
- g_test_add("/webkit/copyandpaste/paste-markup", CopyAndPasteFixture,
- test_info_new(paste_test_html, "bobby"),
- copy_and_paste_fixture_setup,
- test_pasting_markup,
- copy_and_paste_fixture_teardown);
-
- return g_test_run();
-}
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testdomdocument.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testdomdocument.c
deleted file mode 100644
index 8e46c030d..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testdomdocument.c
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
- * Copyright (C) 2010 Igalia S.L.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include "test_utils.h"
-
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <gtk/gtk.h>
-#include <webkit/webkit.h>
-
-#define HTML_DOCUMENT_TITLE "<html><head><title>This is the title</title></head><body></body></html>"
-#define HTML_DOCUMENT_ELEMENTS "<html><body><ul><li>1</li><li>2</li><li>3</li></ul></body></html>"
-#define HTML_DOCUMENT_ELEMENTS_CLASS "<html><body><div class=\"test\"></div><div class=\"strange\"></div><div class=\"test\"></div></body></html>"
-#define HTML_DOCUMENT_ELEMENTS_ID "<html><body><div id=\"testok\"></div><div id=\"testbad\">first</div><div id=\"testbad\">second</div></body></html>"
-#define HTML_DOCUMENT_LINKS "<html><head><title>Title</title></head><body><a href=\"about:blank\">blank</a><a href=\"http://www.google.com\">google</a><a href=\"http://www.webkit.org\">webkit</a></body></html>"
-#define HTML_DOCUMENT_IFRAME "<html><head><title>IFrame</title></head><body><iframe id='iframe'></iframe><div id='test'></div></body></html>"
-#define HTML_DOCUMENT_TABLE "<html><body><table id=\"table\"></table></body></html>"
-#define HTML_DOCUMENT_EVALUATE "<html><head><title></title></head><body><div>First div</div><div>Second div</div></body></html>"
-
-typedef struct {
- GtkWidget* webView;
- GMainLoop* loop;
-} DomDocumentFixture;
-
-static gboolean finish_loading(DomDocumentFixture* fixture)
-{
- if (g_main_loop_is_running(fixture->loop))
- g_main_loop_quit(fixture->loop);
-
- return FALSE;
-}
-
-static void dom_document_fixture_setup(DomDocumentFixture* fixture, gconstpointer data)
-{
- fixture->loop = g_main_loop_new(NULL, TRUE);
- fixture->webView = webkit_web_view_new();
- g_object_ref_sink(fixture->webView);
-
- if (data != NULL)
- webkit_web_view_load_string(WEBKIT_WEB_VIEW (fixture->webView), (const char*) data, NULL, NULL, NULL);
-
- g_idle_add((GSourceFunc)finish_loading, fixture);
- g_main_loop_run(fixture->loop);
-}
-
-static void dom_document_fixture_teardown(DomDocumentFixture* fixture, gconstpointer data)
-{
- if (fixture->webView)
- g_object_unref(fixture->webView);
- g_main_loop_unref(fixture->loop);
-}
-
-static void test_dom_document_title(DomDocumentFixture* fixture, gconstpointer data)
-{
- g_assert(fixture);
- WebKitWebView* view = (WebKitWebView*)fixture->webView;
- g_assert(view);
- WebKitDOMDocument* document = webkit_web_view_get_dom_document(view);
- g_assert(document);
- gchar* title = webkit_dom_document_get_title(document);
- g_assert(title);
- g_assert_cmpstr(title, ==, "This is the title");
- g_free(title);
- webkit_dom_document_set_title(document, "This is the second title");
- title = webkit_dom_document_get_title(document);
- g_assert(title);
- g_assert_cmpstr(title, ==, "This is the second title");
- g_free(title);
-}
-
-static void test_dom_document_get_elements_by_tag_name(DomDocumentFixture* fixture, gconstpointer data)
-{
- g_assert(fixture);
- WebKitWebView* view = (WebKitWebView*)fixture->webView;
- g_assert(view);
- WebKitDOMDocument* document = webkit_web_view_get_dom_document(view);
- g_assert(document);
- WebKitDOMNodeList* list = webkit_dom_document_get_elements_by_tag_name(document, "li");
- g_assert(list);
- gulong length = webkit_dom_node_list_get_length(list);
- g_assert_cmpint(length, ==, 3);
-
- guint i;
-
- for (i = 0; i < length; i++) {
- WebKitDOMNode* item = webkit_dom_node_list_item(list, i);
- g_assert(item);
- WebKitDOMElement* element = (WebKitDOMElement*)item;
- g_assert(element);
- g_assert_cmpstr(webkit_dom_element_get_tag_name(element), ==, "LI");
- WebKitDOMHTMLElement* htmlElement = (WebKitDOMHTMLElement*)element;
- char* n = g_strdup_printf("%d", i+1);
- g_assert_cmpstr(webkit_dom_html_element_get_inner_text(htmlElement), ==, n);
- g_free(n);
- }
-
- g_object_unref(list);
-}
-
-static void test_dom_document_get_elements_by_class_name(DomDocumentFixture* fixture, gconstpointer data)
-{
- g_assert(fixture);
- WebKitWebView* view = (WebKitWebView*)fixture->webView;
- g_assert(view);
- WebKitDOMDocument* document = webkit_web_view_get_dom_document(view);
- g_assert(document);
- WebKitDOMNodeList* list = webkit_dom_document_get_elements_by_class_name(document, "test");
- g_assert(list);
- gulong length = webkit_dom_node_list_get_length(list);
- g_assert_cmpint(length, ==, 2);
-
- guint i;
-
- for (i = 0; i < length; i++) {
- WebKitDOMNode* item = webkit_dom_node_list_item(list, i);
- g_assert(item);
- WebKitDOMElement* element = (WebKitDOMElement*)item;
- g_assert(element);
- g_assert_cmpstr(webkit_dom_element_get_tag_name(element), ==, "DIV");
- }
-
- g_object_unref(list);
-}
-
-static void test_dom_document_get_element_by_id(DomDocumentFixture* fixture, gconstpointer data)
-{
- g_assert(fixture);
- WebKitWebView* view = (WebKitWebView*)fixture->webView;
- g_assert(view);
- WebKitDOMDocument* document = webkit_web_view_get_dom_document(view);
- g_assert(document);
- WebKitDOMElement* element = webkit_dom_document_get_element_by_id(document, "testok");
- g_assert(element);
- element = webkit_dom_document_get_element_by_id(document, "this-id-does-not-exist");
- g_assert(element == 0);
- /* The DOM spec says the return value is undefined when there's
- * more than one element with the same id; in our case the first
- * one will be returned */
- element = webkit_dom_document_get_element_by_id(document, "testbad");
- g_assert(element);
- WebKitDOMHTMLElement* htmlElement = (WebKitDOMHTMLElement*)element;
- g_assert_cmpstr(webkit_dom_html_element_get_inner_text(htmlElement), ==, "first");
-}
-
-static void test_dom_document_get_links(DomDocumentFixture* fixture, gconstpointer data)
-{
- g_assert(fixture);
- WebKitWebView* view = (WebKitWebView*)fixture->webView;
- g_assert(view);
- WebKitDOMDocument* document = webkit_web_view_get_dom_document(view);
- g_assert(document);
- WebKitDOMHTMLCollection *collection = webkit_dom_document_get_links(document);
- g_assert(collection);
- gulong length = webkit_dom_html_collection_get_length(collection);
- g_assert_cmpint(length, ==, 3);
-
- guint i;
-
- for (i = 0; i < length; i++) {
- static const char* names[] = { "blank", "google", "webkit" };
- static const char* uris[] = { "about:blank", "http://www.google.com/", "http://www.webkit.org/" };
- WebKitDOMNode *node = webkit_dom_html_collection_item(collection, i);
- g_assert(node);
- WebKitDOMElement* element = (WebKitDOMElement*)node;
- g_assert_cmpstr(webkit_dom_element_get_tag_name(element), ==, "A");
- WebKitDOMHTMLElement *htmlElement = (WebKitDOMHTMLElement*)element;
- g_assert_cmpstr(webkit_dom_html_element_get_inner_text(htmlElement), ==, names[i]);
- WebKitDOMHTMLAnchorElement *anchor = (WebKitDOMHTMLAnchorElement*)element;
- g_assert_cmpstr(webkit_dom_html_anchor_element_get_href(anchor), ==, uris[i]);
- }
- g_object_unref(collection);
-}
-
-static void test_dom_document_insert_row(DomDocumentFixture* fixture, gconstpointer data)
-{
- g_assert(fixture);
- WebKitWebView* view = (WebKitWebView*)fixture->webView;
- g_assert(view);
- WebKitDOMDocument* document = webkit_web_view_get_dom_document(view);
- g_assert(WEBKIT_DOM_IS_DOCUMENT(document));
- WebKitDOMElement* table = webkit_dom_document_get_element_by_id(document, "table");
- g_assert(WEBKIT_DOM_IS_HTML_ELEMENT(table));
- WebKitDOMHTMLCollection* rows = webkit_dom_html_table_element_get_rows(WEBKIT_DOM_HTML_TABLE_ELEMENT(table));
- g_assert(WEBKIT_DOM_IS_HTML_COLLECTION(rows));
-
- // Table is initially empty.
- g_assert_cmpint(webkit_dom_html_collection_get_length(rows), ==, 0);
- WebKitDOMHTMLElement* row = webkit_dom_html_table_element_insert_row(WEBKIT_DOM_HTML_TABLE_ELEMENT(table), -1, NULL);
- g_assert(WEBKIT_DOM_IS_HTML_TABLE_ROW_ELEMENT(row));
- rows = webkit_dom_html_table_element_get_rows(WEBKIT_DOM_HTML_TABLE_ELEMENT(table));
- g_assert(WEBKIT_DOM_IS_HTML_COLLECTION(rows));
- g_assert_cmpint(webkit_dom_html_collection_get_length(rows), ==, 1);
-}
-
-static void test_dom_document_evaluate(DomDocumentFixture* fixture, gconstpointer data)
-{
- g_assert(fixture);
- WebKitWebView* view = (WebKitWebView*)fixture->webView;
- g_assert(view);
- WebKitDOMDocument* document = webkit_web_view_get_dom_document(view);
- g_assert(WEBKIT_DOM_IS_DOCUMENT(document));
- WebKitDOMNodeList* list = webkit_dom_document_get_elements_by_tag_name(document, "html");
- g_assert(list);
- gulong length = webkit_dom_node_list_get_length(list);
- g_assert_cmpint(length, ==, 1);
- WebKitDOMNode* html = webkit_dom_node_list_item(list, 0);
- g_assert(WEBKIT_DOM_IS_NODE(html));
-
- WebKitDOMXPathResult* result = webkit_dom_document_evaluate(document, "//div", html, NULL, 0, NULL, NULL);
- g_assert(WEBKIT_DOM_IS_XPATH_RESULT(result));
-
- int i = 0;
- WebKitDOMNode* node;
- while ( (node = webkit_dom_xpath_result_iterate_next(result, NULL)) != NULL) {
- g_assert(node);
- WebKitDOMElement* element = (WebKitDOMElement*)node;
- g_assert_cmpstr(webkit_dom_element_get_tag_name(element), ==, "DIV");
- i++;
- }
- g_assert_cmpint(i, ==, 2);
-
- g_object_unref(list);
-}
-
-static void weak_notify(gpointer data, GObject* zombie)
-{
- guint* count = (guint*)data;
- (*count)++;
-}
-
-static void test_dom_document_garbage_collection(DomDocumentFixture* fixture, gconstpointer data)
-{
- guint count = 0;
- g_assert(fixture);
- WebKitWebView* view = (WebKitWebView*)fixture->webView;
- g_assert(view);
- WebKitDOMDocument* document = webkit_web_view_get_dom_document(view);
- g_assert(document);
- g_object_weak_ref(G_OBJECT(document), (GWeakNotify)weak_notify, &count);
- WebKitDOMHTMLHeadElement* head = webkit_dom_document_get_head(document);
- g_assert(head);
- g_object_weak_ref(G_OBJECT(head), (GWeakNotify)weak_notify, &count);
- WebKitDOMHTMLElement* body = webkit_dom_document_get_body(document);
- g_assert(body);
- g_object_weak_ref(G_OBJECT(body), (GWeakNotify)weak_notify, &count);
- WebKitDOMHTMLCollection *collection = webkit_dom_document_get_links(document);
- g_assert(collection);
- g_object_weak_ref(G_OBJECT(collection), (GWeakNotify)weak_notify, &count);
-
- webkit_web_view_load_string(WEBKIT_WEB_VIEW(view), HTML_DOCUMENT_LINKS, NULL, NULL, NULL);
-
- while (g_main_context_pending(NULL))
- g_main_context_iteration(NULL, FALSE);
-
- g_assert_cmpuint(count, ==, 3);
-
- g_object_unref(collection);
- g_assert_cmpuint(count, ==, 4);
-
- count = 0;
-
- document = webkit_web_view_get_dom_document(view);
- g_assert(document);
- g_object_weak_ref(G_OBJECT(document), (GWeakNotify)weak_notify, &count);
- head = webkit_dom_document_get_head(document);
- g_assert(head);
- g_object_weak_ref(G_OBJECT(head), (GWeakNotify)weak_notify, &count);
- body = webkit_dom_document_get_body(document);
- g_assert(body);
- g_object_weak_ref(G_OBJECT(body), (GWeakNotify)weak_notify, &count);
- collection = webkit_dom_document_get_links(document);
- g_assert(collection);
- g_object_weak_ref(G_OBJECT(collection), (GWeakNotify)weak_notify, &count);
- /* Ask twice for the same object */
- WebKitDOMHTMLCollection* collection2 = webkit_dom_document_get_links(document);
- g_assert(collection2);
- g_object_weak_ref(G_OBJECT(collection2), (GWeakNotify)weak_notify, &count);
-
- g_object_unref(document);
- g_object_unref(head);
- g_object_unref(body);
- g_object_unref(collection);
- g_object_unref(collection2);
-
- g_assert_cmpuint(count, ==, 5);
-
- webkit_web_view_load_string(WEBKIT_WEB_VIEW(view), HTML_DOCUMENT_IFRAME, NULL, NULL, NULL);
-
- while (g_main_context_pending(NULL))
- g_main_context_iteration(NULL, FALSE);
-
- count = 0;
-
- document = webkit_web_view_get_dom_document(view);
- body = webkit_dom_document_get_body(document);
- WebKitDOMElement* p = webkit_dom_document_create_element(document, "P", NULL);
- webkit_dom_node_append_child(WEBKIT_DOM_NODE(body), WEBKIT_DOM_NODE(p), NULL);
- g_object_weak_ref(G_OBJECT(p), (GWeakNotify)weak_notify, &count);
- /* This is wrong, p is transfer none and owned by the cache, but we shouldn't crash in that case. */
- g_object_unref(p);
-
- webkit_web_view_load_string(WEBKIT_WEB_VIEW(view), HTML_DOCUMENT_IFRAME, NULL, NULL, NULL);
-
- while (g_main_context_pending(NULL))
- g_main_context_iteration(NULL, FALSE);
-
- g_assert_cmpuint(count, ==, 1);
-
- count = 0;
-
- document = webkit_web_view_get_dom_document(view);
- WebKitDOMElement* div = webkit_dom_document_get_element_by_id(document, "test");
- g_assert(div);
- g_object_weak_ref(G_OBJECT(div), (GWeakNotify)weak_notify, &count);
- WebKitDOMElement* iframe = webkit_dom_document_get_element_by_id(document, "iframe");
- g_assert(iframe);
-
- webkit_dom_element_set_attribute(iframe, "src", "data:<html><head></head></html>", NULL);
-
- while (g_main_context_pending(NULL))
- g_main_context_iteration(NULL, FALSE);
-
- WebKitDOMDocument* iframeDocument = webkit_dom_html_iframe_element_get_content_document(WEBKIT_DOM_HTML_IFRAME_ELEMENT(iframe));
- g_assert(iframeDocument);
- head = webkit_dom_document_get_head(iframeDocument);
- g_assert(head);
- g_object_weak_ref(G_OBJECT(head), (GWeakNotify)weak_notify, &count);
-
- webkit_dom_element_set_attribute(iframe, "src", "about:blank", NULL);
-
- while (g_main_context_pending(NULL))
- g_main_context_iteration(NULL, FALSE);
-
- g_assert_cmpuint(count, ==, 1);
-
- webkit_web_view_load_string(WEBKIT_WEB_VIEW(view), HTML_DOCUMENT_LINKS, NULL, NULL, NULL);
-
- while (g_main_context_pending(NULL))
- g_main_context_iteration(NULL, FALSE);
-
- g_assert_cmpuint(count, ==, 2);
-
- count = 0;
-
- document = webkit_web_view_get_dom_document(view);
- g_assert(document);
- g_object_weak_ref(G_OBJECT(document), (GWeakNotify)weak_notify, &count);
- /* Ask twice for the Document */
- WebKitDOMDocument* document2 = webkit_web_view_get_dom_document(view);
- g_assert(document2);
- g_object_weak_ref(G_OBJECT(document2), (GWeakNotify)weak_notify, &count);
- head = webkit_dom_document_get_head(document);
- g_assert(head);
- g_object_weak_ref(G_OBJECT(head), (GWeakNotify)weak_notify, &count);
- body = webkit_dom_document_get_body(document);
- g_assert(body);
- g_object_weak_ref(G_OBJECT(body), (GWeakNotify)weak_notify, &count);
- collection = webkit_dom_document_get_links(document);
- g_assert(collection);
- g_object_weak_ref(G_OBJECT(collection), (GWeakNotify)weak_notify, &count);
-
- gtk_widget_destroy(fixture->webView);
- fixture->webView = NULL;
-
- g_assert_cmpuint(count, ==, 4);
-
- g_object_unref(collection);
-
- g_assert_cmpuint(count, ==, 5);
-}
-
-int main(int argc, char** argv)
-{
- gtk_test_init(&argc, &argv, NULL);
-
- g_test_bug_base("https://bugs.webkit.org/");
-
- g_test_add("/webkit/domdocument/test_title",
- DomDocumentFixture, HTML_DOCUMENT_TITLE,
- dom_document_fixture_setup,
- test_dom_document_title,
- dom_document_fixture_teardown);
-
- g_test_add("/webkit/domdocument/test_get_elements_by_tag_name",
- DomDocumentFixture, HTML_DOCUMENT_ELEMENTS,
- dom_document_fixture_setup,
- test_dom_document_get_elements_by_tag_name,
- dom_document_fixture_teardown);
-
- g_test_add("/webkit/domdocument/test_get_elements_by_class_name",
- DomDocumentFixture, HTML_DOCUMENT_ELEMENTS_CLASS,
- dom_document_fixture_setup,
- test_dom_document_get_elements_by_class_name,
- dom_document_fixture_teardown);
-
- g_test_add("/webkit/domdocument/test_get_element_by_id",
- DomDocumentFixture, HTML_DOCUMENT_ELEMENTS_ID,
- dom_document_fixture_setup,
- test_dom_document_get_element_by_id,
- dom_document_fixture_teardown);
-
- g_test_add("/webkit/domdocument/test_get_links",
- DomDocumentFixture, HTML_DOCUMENT_LINKS,
- dom_document_fixture_setup,
- test_dom_document_get_links,
- dom_document_fixture_teardown);
-
- g_test_add("/webkit/domdocument/test_table_insert_row",
- DomDocumentFixture, HTML_DOCUMENT_TABLE,
- dom_document_fixture_setup,
- test_dom_document_insert_row,
- dom_document_fixture_teardown);
-
- g_test_add("/webkit/domdocument/test_document_evaluate",
- DomDocumentFixture, HTML_DOCUMENT_EVALUATE,
- dom_document_fixture_setup,
- test_dom_document_evaluate,
- dom_document_fixture_teardown);
-
- g_test_add("/webkit/domdocument/test_garbage_collection",
- DomDocumentFixture, HTML_DOCUMENT_LINKS,
- dom_document_fixture_setup,
- test_dom_document_garbage_collection,
- dom_document_fixture_teardown);
-
- return g_test_run();
-}
-
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testdomdomwindow.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testdomdomwindow.c
deleted file mode 100644
index 14fcd186a..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testdomdomwindow.c
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (C) 2010 Igalia S.L.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include "test_utils.h"
-
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <gtk/gtk.h>
-#include <webkit/webkit.h>
-
-#define HTML_DOCUMENT "<html><head><title></title></head><style type='text/css'>#test { font-size: 16px; }</style><body><p id='test'>test</p></body></html>"
-
-typedef struct {
- GtkWidget* webView;
- GtkWidget* window;
- WebKitDOMDOMWindow* domWindow;
- GMainLoop* loop;
-
- gboolean loaded;
- gboolean clicked;
- gconstpointer data;
-} DomDomviewFixture;
-
-static gboolean finish_loading(DomDomviewFixture* fixture)
-{
- if (g_main_loop_is_running(fixture->loop))
- g_main_loop_quit(fixture->loop);
-
- return FALSE;
-}
-
-static void dom_domview_fixture_setup(DomDomviewFixture* fixture, gconstpointer data)
-{
- fixture->loop = g_main_loop_new(NULL, TRUE);
- fixture->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- fixture->webView = webkit_web_view_new();
- fixture->data = data;
-
- gtk_container_add(GTK_CONTAINER(fixture->window), GTK_WIDGET(fixture->webView));
-}
-
-static void dom_domview_fixture_teardown(DomDomviewFixture* fixture, gconstpointer data)
-{
- gtk_widget_destroy(fixture->window);
- g_main_loop_unref(fixture->loop);
-}
-
-static void dom_dom_window_fixture_setup(DomDomviewFixture* fixture, gconstpointer data)
-{
- fixture->loop = g_main_loop_new(NULL, TRUE);
- fixture->webView = webkit_web_view_new();
- g_object_ref_sink(fixture->webView);
-
- if (data != NULL)
- webkit_web_view_load_string(WEBKIT_WEB_VIEW (fixture->webView), (const char*) data, NULL, NULL, NULL);
-
- g_idle_add((GSourceFunc)finish_loading, fixture);
- g_main_loop_run(fixture->loop);
-}
-
-static void dom_dom_window_fixture_teardown(DomDomviewFixture* fixture, gconstpointer data)
-{
- if (fixture->webView)
- g_object_unref(fixture->webView);
- g_main_loop_unref(fixture->loop);
-}
-
-static gboolean loadedCallback(WebKitDOMDOMWindow* view, WebKitDOMEvent* event, DomDomviewFixture* fixture)
-{
- g_assert(fixture->loaded == FALSE);
- fixture->loaded = TRUE;
-
- return FALSE;
-}
-
-static gboolean clickedCallback(WebKitDOMDOMWindow* view, WebKitDOMEvent* event, DomDomviewFixture* fixture)
-{
- WebKitDOMEventTarget* target;
- gushort phase;
-
- g_assert(event);
- g_assert(WEBKIT_DOM_IS_EVENT(event));
-
- // We should catch this in the bubbling up phase, since we are connecting to the toplevel object
- phase = webkit_dom_event_get_event_phase(event);
- g_assert_cmpint(phase, ==, 3);
-
- target = webkit_dom_event_get_current_target(event);
- g_assert(target == WEBKIT_DOM_EVENT_TARGET(view));
-
- g_assert(fixture->clicked == FALSE);
- fixture->clicked = TRUE;
-
- finish_loading(fixture);
-
- return FALSE;
-}
-
-gboolean map_event_cb(GtkWidget *widget, GdkEvent* event, DomDomviewFixture* fixture)
-{
- webkit_web_view_load_string(WEBKIT_WEB_VIEW (fixture->webView), (const char*)fixture->data, NULL, NULL, NULL);
-
- return FALSE;
-}
-
-static void load_event_callback(WebKitWebView* webView, GParamSpec* spec, DomDomviewFixture* fixture)
-{
- WebKitLoadStatus status = webkit_web_view_get_load_status(webView);
- if (status == WEBKIT_LOAD_FINISHED) {
- webkit_dom_event_target_add_event_listener(WEBKIT_DOM_EVENT_TARGET(fixture->domWindow), "click", G_CALLBACK(clickedCallback), false, fixture);
-
- g_assert(fixture->clicked == FALSE);
- gtk_test_widget_click(GTK_WIDGET(fixture->webView), 1, 0);
- }
-
-}
-
-static void test_dom_domview_signals(DomDomviewFixture* fixture, gconstpointer data)
-{
- g_assert(fixture);
- WebKitWebView* view = (WebKitWebView*)fixture->webView;
- g_assert(view);
- WebKitDOMDocument* document = webkit_web_view_get_dom_document(view);
- g_assert(document);
- WebKitDOMDOMWindow* domWindow = webkit_dom_document_get_default_view(document);
- g_assert(domWindow);
-
- fixture->domWindow = domWindow;
-
- webkit_dom_event_target_add_event_listener(WEBKIT_DOM_EVENT_TARGET(fixture->domWindow), "load", G_CALLBACK(loadedCallback), false, fixture);
- g_signal_connect(fixture->window, "map-event", G_CALLBACK(map_event_cb), fixture);
- g_signal_connect(fixture->webView, "notify::load-status", G_CALLBACK(load_event_callback), fixture);
-
- gtk_widget_show_all(fixture->window);
- gtk_window_present(GTK_WINDOW(fixture->window));
-
- g_main_loop_run(fixture->loop);
-
- g_assert(fixture->loaded);
- g_assert(fixture->clicked);
-}
-
-static gboolean
-clicked_cb(WebKitDOMEventTarget* target, WebKitDOMEvent* event, DomDomviewFixture* fixture)
-{
- g_assert(fixture->clicked == FALSE);
- fixture->clicked = TRUE;
- finish_loading(fixture);
- return FALSE;
-}
-
-static void load_status_callback(WebKitWebView* webView, GParamSpec* spec, DomDomviewFixture* fixture)
-{
- WebKitLoadStatus status = webkit_web_view_get_load_status(webView);
- if (status == WEBKIT_LOAD_FINISHED) {
- WebKitDOMDocument* document;
- WebKitDOMDOMWindow* domWindow;
- WebKitDOMElement* element;
- WebKitDOMEvent* event;
- glong clientX, clientY;
-
- document = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(fixture->webView));
- g_assert(document);
- domWindow = webkit_dom_document_get_default_view(document);
- g_assert(domWindow);
- fixture->domWindow = domWindow;
-
- element = webkit_dom_document_get_element_by_id(document, "test");
- g_assert(element);
- event = webkit_dom_document_create_event(document, "MouseEvent", NULL);
- g_assert(event);
- g_assert(WEBKIT_DOM_IS_EVENT(event));
- g_assert(WEBKIT_DOM_IS_MOUSE_EVENT(event));
- clientX = webkit_dom_element_get_client_left(element);
- clientY = webkit_dom_element_get_client_top(element);
- webkit_dom_mouse_event_init_mouse_event(WEBKIT_DOM_MOUSE_EVENT(event),
- "click", TRUE, TRUE,
- fixture->domWindow, 0, 0, 0, clientX, clientY,
- FALSE, FALSE, FALSE, FALSE,
- 1, WEBKIT_DOM_EVENT_TARGET(element));
- webkit_dom_event_target_add_event_listener(WEBKIT_DOM_EVENT_TARGET(element), "click", G_CALLBACK(clicked_cb), false, fixture);
- g_assert(fixture->clicked == FALSE);
- webkit_dom_event_target_dispatch_event(WEBKIT_DOM_EVENT_TARGET(element), event, NULL);
- }
-
-}
-
-static void test_dom_domview_dispatch_event(DomDomviewFixture* fixture, gconstpointer data)
-{
- g_signal_connect(fixture->window, "map-event", G_CALLBACK(map_event_cb), fixture);
- g_signal_connect(fixture->webView, "notify::load-status", G_CALLBACK(load_status_callback), fixture);
-
- gtk_widget_show_all(fixture->window);
- gtk_window_present(GTK_WINDOW(fixture->window));
-
- g_main_loop_run (fixture->loop);
- g_assert(fixture->clicked);
-}
-
-static void test_dom_dom_window_get_computed_style(DomDomviewFixture* fixture, gconstpointer data)
-{
- WebKitDOMDocument* document = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(fixture->webView));
- g_assert(document);
- WebKitDOMDOMWindow* domWindow = webkit_dom_document_get_default_view(document);
- g_assert(domWindow);
-
- WebKitDOMElement* element = webkit_dom_document_get_element_by_id(document, "test");
- g_assert(element);
- g_assert(WEBKIT_DOM_IS_ELEMENT(element));
- WebKitDOMCSSStyleDeclaration* cssStyle = webkit_dom_dom_window_get_computed_style(domWindow, element, NULL);
- gchar* fontSize = webkit_dom_css_style_declaration_get_property_value(cssStyle, "font-size");
- g_assert_cmpstr(fontSize, ==, "16px");
-}
-
-int main(int argc, char** argv)
-{
- gtk_test_init(&argc, &argv, NULL);
-
- g_test_bug_base("https://bugs.webkit.org/");
-
- g_test_add("/webkit/domdomview/signals",
- DomDomviewFixture, HTML_DOCUMENT,
- dom_domview_fixture_setup,
- test_dom_domview_signals,
- dom_domview_fixture_teardown);
-
- g_test_add("/webkit/domdomview/dispatch_event",
- DomDomviewFixture, HTML_DOCUMENT,
- dom_domview_fixture_setup,
- test_dom_domview_dispatch_event,
- dom_domview_fixture_teardown);
-
- g_test_add("/webkit/domdomwindow/get_computed_style",
- DomDomviewFixture, HTML_DOCUMENT,
- dom_dom_window_fixture_setup,
- test_dom_dom_window_get_computed_style,
- dom_dom_window_fixture_teardown);
-
- return g_test_run();
-}
-
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testdomnode.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testdomnode.c
deleted file mode 100644
index ed4bcbdaa..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testdomnode.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (C) 2010 Igalia S.L.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include "test_utils.h"
-
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <gtk/gtk.h>
-#include <webkit/webkit.h>
-
-#define HTML_DOCUMENT_HIERARCHY_NAVIGATION "<html><head><title>This is the title</title></head><body><p>1</p><p>2</p><p>3</p></body></html>"
-#define HTML_DOCUMENT_NODE_INSERTION "<html><body></body></html>"
-
-typedef struct {
- GtkWidget* webView;
- GMainLoop* loop;
-} DomNodeFixture;
-
-static gboolean finish_loading(DomNodeFixture* fixture)
-{
- if (g_main_loop_is_running(fixture->loop))
- g_main_loop_quit(fixture->loop);
-
- return FALSE;
-}
-
-static void dom_node_fixture_setup(DomNodeFixture* fixture, gconstpointer data)
-{
- fixture->loop = g_main_loop_new(NULL, TRUE);
- fixture->webView = webkit_web_view_new();
- g_object_ref_sink(fixture->webView);
-
- if (data != NULL)
- webkit_web_view_load_string(WEBKIT_WEB_VIEW(fixture->webView), (const char*)data, NULL, NULL, NULL);
-
- g_idle_add((GSourceFunc)finish_loading, fixture);
- g_main_loop_run(fixture->loop);
-}
-
-static void dom_node_fixture_teardown(DomNodeFixture* fixture, gconstpointer data)
-{
- g_object_unref(fixture->webView);
- g_main_loop_unref(fixture->loop);
-}
-
-static void test_dom_node_hierarchy_navigation(DomNodeFixture* fixture, gconstpointer data)
-{
- WebKitDOMDocument* document;
- WebKitDOMHTMLHeadElement* head;
- WebKitDOMHTMLBodyElement* body;
- WebKitDOMNodeList* list;
- WebKitDOMNode* ptr;
- gulong i, length;
-
- document = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(fixture->webView));
- g_assert(document);
- g_assert(WEBKIT_DOM_IS_DOCUMENT(document));
- head = webkit_dom_document_get_head(document);
- g_assert(head);
- g_assert(WEBKIT_DOM_IS_HTML_HEAD_ELEMENT(head));
-
- /* Title, head's child */
- g_assert(webkit_dom_node_has_child_nodes(WEBKIT_DOM_NODE(head)));
- list = webkit_dom_node_get_child_nodes(WEBKIT_DOM_NODE(head));
- g_assert_cmpint(webkit_dom_node_list_get_length(list), ==, 1);
- ptr = webkit_dom_node_list_item(list, 0);
- g_assert(ptr);
- g_assert(WEBKIT_DOM_IS_HTML_TITLE_ELEMENT(ptr));
- g_object_unref(list);
-
- /* Body, Head sibling */
- ptr = webkit_dom_node_get_next_sibling(WEBKIT_DOM_NODE(head));
- g_assert(ptr);
- body = WEBKIT_DOM_HTML_BODY_ELEMENT(ptr);
- g_assert(WEBKIT_DOM_IS_HTML_BODY_ELEMENT(body));
-
- /* There is no third sibling */
- ptr = webkit_dom_node_get_next_sibling(ptr);
- g_assert(ptr == NULL);
-
- /* Body's previous sibling is Head */
- ptr = webkit_dom_node_get_previous_sibling(WEBKIT_DOM_NODE(body));
- g_assert(ptr);
- g_assert(WEBKIT_DOM_IS_HTML_HEAD_ELEMENT(ptr));
-
- /* Body has 3 children */
- g_assert(webkit_dom_node_has_child_nodes(WEBKIT_DOM_NODE(body)));
- list = webkit_dom_node_get_child_nodes(WEBKIT_DOM_NODE(body));
- length = webkit_dom_node_list_get_length(list);
- g_assert_cmpint(length, ==, 3);
-
- /* The three of them are P tags */
- for (i = 0; i < length; i++) {
- ptr = webkit_dom_node_list_item(list, i);
- g_assert(ptr);
- g_assert(WEBKIT_DOM_IS_HTML_PARAGRAPH_ELEMENT(ptr));
- }
-
- /* Go backwards */
- for (i = 0; ptr; ptr = webkit_dom_node_get_previous_sibling(ptr), i++)
- /* Nothing */;
-
- g_assert_cmpint(i, ==, 3);
- g_object_unref(list);
-}
-
-static void test_dom_node_insertion(DomNodeFixture* fixture, gconstpointer data)
-{
- WebKitDOMDocument* document;
- WebKitDOMHTMLElement* body;
- WebKitDOMElement* p, *div;
- WebKitDOMNodeList* list;
- WebKitDOMNode* node;
-
- document = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(fixture->webView));
- g_assert(document);
- body = webkit_dom_document_get_body(document);
- g_assert(body);
- g_assert(WEBKIT_DOM_IS_HTML_ELEMENT(body));
-
- /* Body shouldn't have any children at this point */
- g_assert(webkit_dom_node_has_child_nodes(WEBKIT_DOM_NODE(body)) == FALSE);
-
- /* Insert one P element */
- p = webkit_dom_document_create_element(document, "P", NULL);
- webkit_dom_node_append_child(WEBKIT_DOM_NODE(body), WEBKIT_DOM_NODE(p), NULL);
-
- /* Now it should have one, the same that we inserted */
- g_assert(webkit_dom_node_has_child_nodes(WEBKIT_DOM_NODE(body)));
- list = webkit_dom_node_get_child_nodes(WEBKIT_DOM_NODE(body));
- g_assert_cmpint(webkit_dom_node_list_get_length(list), ==, 1);
- node = webkit_dom_node_list_item(list, 0);
- g_assert(node);
- g_assert(webkit_dom_node_is_same_node(WEBKIT_DOM_NODE(p), node));
- g_object_unref(list);
-
- /* Replace the P tag with a DIV tag */
- div = webkit_dom_document_create_element(document, "DIV", NULL);
- webkit_dom_node_replace_child(WEBKIT_DOM_NODE(body), WEBKIT_DOM_NODE(div), WEBKIT_DOM_NODE(p), NULL);
- g_assert(webkit_dom_node_has_child_nodes(WEBKIT_DOM_NODE(body)));
- list = webkit_dom_node_get_child_nodes(WEBKIT_DOM_NODE(body));
- g_assert_cmpint(webkit_dom_node_list_get_length(list), ==, 1);
- node = webkit_dom_node_list_item(list, 0);
- g_assert(node);
- g_assert(webkit_dom_node_is_same_node(WEBKIT_DOM_NODE(div), node));
- g_object_unref(list);
-
- /* Now remove the tag */
- webkit_dom_node_remove_child(WEBKIT_DOM_NODE(body), node, NULL);
- list = webkit_dom_node_get_child_nodes(WEBKIT_DOM_NODE(body));
- g_assert_cmpint(webkit_dom_node_list_get_length(list), ==, 0);
- g_object_unref(list);
-
- /* Test insert_before */
-
- /* If refChild is null, insert newChild as last element of parent */
- div = webkit_dom_document_create_element(document, "DIV", NULL);
- webkit_dom_node_insert_before(WEBKIT_DOM_NODE(body), WEBKIT_DOM_NODE(div), NULL, NULL);
- g_assert(webkit_dom_node_has_child_nodes(WEBKIT_DOM_NODE(body)));
- list = webkit_dom_node_get_child_nodes(WEBKIT_DOM_NODE(body));
- g_assert_cmpint(webkit_dom_node_list_get_length(list), ==, 1);
- node = webkit_dom_node_list_item(list, 0);
- g_assert(node);
- g_assert(webkit_dom_node_is_same_node(WEBKIT_DOM_NODE(div), node));
- g_object_unref(list);
-
- /* Now insert a 'p' before 'div' */
- p = webkit_dom_document_create_element(document, "P", NULL);
- webkit_dom_node_insert_before(WEBKIT_DOM_NODE(body), WEBKIT_DOM_NODE(p), WEBKIT_DOM_NODE(div), NULL);
- g_assert(webkit_dom_node_has_child_nodes(WEBKIT_DOM_NODE(body)));
- list = webkit_dom_node_get_child_nodes(WEBKIT_DOM_NODE(body));
- g_assert_cmpint(webkit_dom_node_list_get_length(list), ==, 2);
- node = webkit_dom_node_list_item(list, 0);
- g_assert(node);
- g_assert(webkit_dom_node_is_same_node(WEBKIT_DOM_NODE(p), node));
- node = webkit_dom_node_list_item(list, 1);
- g_assert(node);
- g_assert(webkit_dom_node_is_same_node(WEBKIT_DOM_NODE(div), node));
- g_object_unref(list);
-}
-
-int main(int argc, char** argv)
-{
- gtk_test_init(&argc, &argv, NULL);
-
- g_test_bug_base("https://bugs.webkit.org/");
-
- g_test_add("/webkit/domnode/test_hierarchy_navigation",
- DomNodeFixture, HTML_DOCUMENT_HIERARCHY_NAVIGATION,
- dom_node_fixture_setup,
- test_dom_node_hierarchy_navigation,
- dom_node_fixture_teardown);
-
- g_test_add("/webkit/domnode/test_insertion",
- DomNodeFixture, HTML_DOCUMENT_NODE_INSERTION,
- dom_node_fixture_setup,
- test_dom_node_insertion,
- dom_node_fixture_teardown);
-
- return g_test_run();
-}
-
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testdownload.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testdownload.c
deleted file mode 100644
index e34d63230..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testdownload.c
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * Copyright (C) 2009 Christian Dywan <christian@twotoasts.de>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2,1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include <errno.h>
-#include <unistd.h>
-#include <glib/gstdio.h>
-#include <webkit/webkit.h>
-
-GMainLoop* loop;
-char* temporaryFilename = NULL;
-WebKitDownload* theDownload = NULL;
-
-static void
-test_webkit_download_create(void)
-{
- WebKitNetworkRequest* request;
- WebKitDownload* download;
- const gchar* uri = "http://example.com";
- gchar* tmpDir;
-
- request = webkit_network_request_new(uri);
- download = webkit_download_new(request);
- g_object_unref(request);
- g_assert_cmpstr(webkit_download_get_uri(download), ==, uri);
- g_assert(webkit_download_get_network_request(download) == request);
- g_assert(g_strrstr(uri, webkit_download_get_suggested_filename(download)));
- g_assert(webkit_download_get_status(download) == WEBKIT_DOWNLOAD_STATUS_CREATED);
- g_assert(!webkit_download_get_total_size(download));
- g_assert(!webkit_download_get_current_size(download));
- g_assert(!webkit_download_get_progress(download));
- g_assert(!webkit_download_get_elapsed_time(download));
- tmpDir = g_filename_to_uri(g_get_tmp_dir(), NULL, NULL);
- webkit_download_set_destination_uri(download, tmpDir);
- g_assert_cmpstr(tmpDir, ==, webkit_download_get_destination_uri(download));;
- g_free(tmpDir);
- g_object_unref(download);
-}
-
-static gboolean
-navigation_policy_decision_requested_cb(WebKitWebView* web_view,
- WebKitWebFrame* web_frame,
- WebKitNetworkRequest* request,
- WebKitWebNavigationAction* action,
- WebKitWebPolicyDecision* decision,
- gpointer data)
-{
- webkit_web_policy_decision_download(decision);
- return TRUE;
-}
-
-static void
-notify_status_cb(GObject* object, GParamSpec* pspec, gpointer data)
-{
- WebKitDownload* download = WEBKIT_DOWNLOAD(object);
- switch (webkit_download_get_status(download)) {
- case WEBKIT_DOWNLOAD_STATUS_FINISHED:
- case WEBKIT_DOWNLOAD_STATUS_ERROR:
- g_main_loop_quit(loop);
- break;
- case WEBKIT_DOWNLOAD_STATUS_CANCELLED:
- g_assert_not_reached();
- break;
- default:
- break;
- }
-}
-
-static gboolean
-set_filename(gchar* filename)
-{
- gchar *uri = g_filename_to_uri(filename, NULL, NULL);
-
- webkit_download_set_destination_uri(theDownload, uri);
- g_free(uri);
-
- webkit_download_start(theDownload);
- return FALSE;
-}
-
-static void
-handle_download_requested_cb(WebKitDownload* download,
- gboolean* beenThere,
- gboolean asynch)
-{
- theDownload = download;
- *beenThere = TRUE;
-
- if (temporaryFilename) {
- if (asynch) {
- g_idle_add((GSourceFunc)set_filename, temporaryFilename);
- } else {
- gchar *uri = g_filename_to_uri(temporaryFilename, NULL, NULL);
- if (uri)
- webkit_download_set_destination_uri(download, uri);
- g_free(uri);
- }
- }
-
- g_signal_connect(download, "notify::status",
- G_CALLBACK(notify_status_cb), NULL);
-}
-
-static gboolean
-download_requested_cb(WebKitWebView* web_view,
- WebKitDownload* download,
- gboolean* beenThere)
-{
- handle_download_requested_cb(download, beenThere, FALSE);
- return TRUE;
-}
-
-static gboolean
-download_requested_asynch_cb(WebKitWebView* web_view,
- WebKitDownload* download,
- gboolean* beenThere)
-{
- handle_download_requested_cb(download, beenThere, TRUE);
- return TRUE;
-}
-
-static void
-test_webkit_download_perform(gboolean asynch)
-{
- WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- GCallback downloadRequestCallback = NULL;
-
- g_object_ref_sink(G_OBJECT(webView));
-
- g_signal_connect(webView, "navigation-policy-decision-requested",
- G_CALLBACK(navigation_policy_decision_requested_cb),
- NULL);
-
- if (asynch)
- downloadRequestCallback = G_CALLBACK(download_requested_asynch_cb);
- else
- downloadRequestCallback = G_CALLBACK(download_requested_cb);
-
- gboolean beenThere = FALSE;
- g_signal_connect(webView, "download-requested",
- downloadRequestCallback, &beenThere);
-
- /* Preparation; FIXME: we should move this code to a test
- * utilities file, because we have a very similar one in
- * testwebframe.c */
- GError *error = NULL;
- gchar* filename;
- int fd = g_file_open_tmp("webkit-testwebdownload-XXXXXX", &filename, &error);
- close(fd);
-
- if (error)
- g_critical("Failed to open a temporary file for writing: %s.", error->message);
-
- if (g_unlink(filename) == -1)
- g_critical("Failed to delete the temporary file: %s.", g_strerror(errno));
-
- theDownload = NULL;
- temporaryFilename = filename;
-
- loop = g_main_loop_new(NULL, TRUE);
- webkit_web_view_load_uri(webView, "http://gnome.org/");
- g_main_loop_run(loop);
-
- g_assert_cmpint(beenThere, ==, TRUE);
-
- g_assert_cmpint(g_file_test(temporaryFilename, G_FILE_TEST_IS_REGULAR), ==, TRUE);
-
- g_unlink(temporaryFilename);
- g_free(temporaryFilename);
- temporaryFilename = NULL;
-
- g_main_loop_unref(loop);
- g_object_unref(webView);
-}
-
-static void
-test_webkit_download_synch(void)
-{
- test_webkit_download_perform(FALSE);
-}
-
-static void
-test_webkit_download_asynch(void)
-{
- test_webkit_download_perform(TRUE);
-}
-
-static gboolean mime_type_policy_decision_requested_cb(WebKitWebView* view, WebKitWebFrame* frame,
- WebKitNetworkRequest* request, const char* mime_type,
- WebKitWebPolicyDecision* decision, gpointer data)
-{
- webkit_web_policy_decision_download(decision);
- return TRUE;
-}
-
-static void idle_quit_loop_cb(WebKitWebView* web_view, GParamSpec* pspec, gpointer data)
-{
- if (webkit_web_view_get_load_status(web_view) == WEBKIT_LOAD_FINISHED ||
- webkit_web_view_get_load_status(web_view) == WEBKIT_LOAD_FAILED)
- g_main_loop_quit(loop);
-}
-
-static void
-test_webkit_download_data(void)
-{
- gboolean beenThere = FALSE;
- WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(webView);
-
- g_signal_connect(webView, "download-requested",
- G_CALLBACK(download_requested_cb),
- &beenThere);
-
- g_signal_connect(webView, "notify::load-status",
- G_CALLBACK(idle_quit_loop_cb),
- NULL);
-
- g_signal_connect(webView, "mime-type-policy-decision-requested",
- G_CALLBACK(mime_type_policy_decision_requested_cb),
- NULL);
-
- loop = g_main_loop_new(NULL, TRUE);
-
- /* We're testing for a crash, so just not crashing is a pass */
- webkit_web_view_load_uri(webView, "data:application/octect-stream,");
- g_main_loop_run(loop);
-
- g_assert_cmpint(beenThere, ==, TRUE);
-
- g_main_loop_unref(loop);
- g_object_unref(webView);
-}
-
-static void notifyDownloadStatusCallback(GObject *object, GParamSpec *pspec, gpointer data)
-{
- WebKitDownload *download = WEBKIT_DOWNLOAD(object);
- WebKitNetworkResponse *response = webkit_download_get_network_response(download);
- SoupMessage *message = webkit_network_response_get_message(response);
-
- switch (webkit_download_get_status(download)) {
- case WEBKIT_DOWNLOAD_STATUS_ERROR:
- g_assert_cmpint(message->status_code, ==, 404);
- g_main_loop_quit(loop);
- break;
- case WEBKIT_DOWNLOAD_STATUS_FINISHED:
- case WEBKIT_DOWNLOAD_STATUS_CANCELLED:
- g_assert_not_reached();
- break;
- default:
- break;
- }
-}
-
-static void serverCallback(SoupServer *server, SoupMessage *message, const char *path, GHashTable *query, SoupClientContext *context, gpointer userData)
-{
- if (message->method != SOUP_METHOD_GET) {
- soup_message_set_status(message, SOUP_STATUS_NOT_IMPLEMENTED);
- return;
- }
-
- soup_message_set_status(message, SOUP_STATUS_NOT_FOUND);
- soup_message_body_complete(message->response_body);
-}
-
-static void test_webkit_download_not_found(void)
-{
- SoupServer *server = soup_server_new(SOUP_SERVER_PORT, 0, NULL);
- soup_server_run_async(server);
- soup_server_add_handler(server, NULL, serverCallback, NULL, NULL);
- SoupURI *baseURI = soup_uri_new("http://127.0.0.1/");
- soup_uri_set_port(baseURI, soup_server_get_port(server));
-
- SoupURI *uri = soup_uri_new_with_base(baseURI, "/foo");
- char *uriString = soup_uri_to_string(uri, FALSE);
- soup_uri_free(uri);
-
- loop = g_main_loop_new(NULL, TRUE);
- WebKitNetworkRequest *request = webkit_network_request_new(uriString);
- g_free (uriString);
- WebKitDownload *download = webkit_download_new(request);
- g_object_unref(request);
-
- webkit_download_set_destination_uri(download, "file:///tmp/foo");
- g_signal_connect(download, "notify::status", G_CALLBACK(notifyDownloadStatusCallback), NULL);
-
- webkit_download_start(download);
- g_main_loop_run(loop);
-
- g_object_unref(download);
- g_main_loop_unref(loop);
- soup_uri_free(baseURI);
- g_object_unref(server);
-}
-
-int main(int argc, char** argv)
-{
- gtk_test_init(&argc, &argv, NULL);
-
- // Get rid of runtime warnings about deprecated properties and signals, since they break the tests.
- g_setenv("G_ENABLE_DIAGNOSTIC", "0", TRUE);
-
- g_test_bug_base("https://bugs.webkit.org/");
- g_test_add_func("/webkit/download/create", test_webkit_download_create);
- g_test_add_func("/webkit/download/synch", test_webkit_download_synch);
- g_test_add_func("/webkit/download/asynch", test_webkit_download_asynch);
- g_test_add_func("/webkit/download/data", test_webkit_download_data);
- g_test_add_func("/webkit/download/not-found", test_webkit_download_not_found);
- return g_test_run ();
-}
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testfavicondatabase.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testfavicondatabase.c
deleted file mode 100644
index 393732b85..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testfavicondatabase.c
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (C) 2012 Igalia S.L.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include "test_utils.h"
-#include <glib/gstdio.h>
-#include <gtk/gtk.h>
-#include <string.h>
-#include <webkit/webkit.h>
-
-const int gIconSize = 16;
-
-GMainLoop *loop;
-char *baseURI;
-
-static void
-serverCallback(SoupServer *server, SoupMessage *message, const char *path, GHashTable *query, SoupClientContext *context, void *data)
-{
- if (message->method != SOUP_METHOD_GET) {
- soup_message_set_status(message, SOUP_STATUS_NOT_IMPLEMENTED);
- return;
- }
-
- soup_message_set_status(message, SOUP_STATUS_OK);
-
- char *contents;
- gsize length;
- if (g_str_equal(path, "/favicon.ico")) {
- GError *error = NULL;
-
- g_file_get_contents("blank.ico", &contents, &length, &error);
- g_assert(!error);
- } else {
- contents = g_strdup("<html><body>test</body></html>");
- length = strlen(contents);
- }
-
- soup_message_body_append(message->response_body, SOUP_MEMORY_TAKE, contents, length);
- soup_message_body_complete(message->response_body);
-}
-
-static void deleteDatabaseFileIfExists(const char *databasePath)
-{
- if (!g_file_test(databasePath, G_FILE_TEST_IS_DIR))
- return;
-
- char *databaseFilename = g_build_filename(databasePath, "WebpageIcons.db", NULL);
- if (g_unlink(databaseFilename) == -1) {
- g_free(databaseFilename);
- return;
- }
-
- g_free(databaseFilename);
- g_rmdir(databasePath);
-}
-
-static void testWebKitFaviconDatabaseSetPath()
-{
- char *databasePath = g_build_filename(g_get_tmp_dir(), "webkit-testfavicondatabase", NULL);
- deleteDatabaseFileIfExists(databasePath);
-
- WebKitFaviconDatabase *database = webkit_get_favicon_database();
- webkit_favicon_database_set_path(database, databasePath);
-
- g_assert_cmpstr(databasePath, ==, webkit_favicon_database_get_path(database));
-
- g_free(databasePath);
-}
-
-// See the comment in main() function that goes with this same guard.
-#ifdef NDEBUG
-
-static void faviconDatabaseGetValidFaviconCallback(GObject *sourceObject, GAsyncResult *result, void *userData)
-{
- gboolean *beenHere = (gboolean*)userData;
- GError *error = NULL;
- GdkPixbuf *icon = webkit_favicon_database_get_favicon_pixbuf_finish(WEBKIT_FAVICON_DATABASE(sourceObject), result, &error);
- g_assert(icon);
- g_object_unref(icon);
-
- *beenHere = TRUE;
-
- g_main_loop_quit(loop);
-}
-
-static void faviconDatabaseGetInvalidFaviconCallback(GObject *sourceObject, GAsyncResult *result, void *userData)
-{
- gboolean *beenHere = (gboolean*)userData;
- GError *error = NULL;
- GdkPixbuf *icon = webkit_favicon_database_get_favicon_pixbuf_finish(WEBKIT_FAVICON_DATABASE(sourceObject), result, &error);
- g_assert(!icon);
-
- *beenHere = TRUE;
-
- g_main_loop_quit(loop);
-}
-
-static void faviconDatabaseGetFaviconCancelledCallback(GObject *sourceObject, GAsyncResult *result, void *userData)
-{
- gboolean *beenHere = (gboolean*)userData;
- GError *error = NULL;
- GdkPixbuf *icon = webkit_favicon_database_get_favicon_pixbuf_finish(WEBKIT_FAVICON_DATABASE(sourceObject), result, &error);
- g_assert(!icon);
- g_assert(error && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED));
-
- *beenHere = TRUE;
-
- g_main_loop_quit(loop);
-}
-
-static inline void quitMainLoopIfLoadCompleted(gboolean *iconOrPageLoaded)
-{
- if (*iconOrPageLoaded)
- g_main_loop_quit(loop);
- else
- *iconOrPageLoaded = TRUE;
-}
-
-static void idleQuitLoopCallback(WebKitWebView *webView, GParamSpec *paramSpec, gboolean *iconOrPageLoaded)
-{
- WebKitLoadStatus status = webkit_web_view_get_load_status(webView);
-
- if (status == WEBKIT_LOAD_FINISHED || status == WEBKIT_LOAD_FAILED)
- quitMainLoopIfLoadCompleted(iconOrPageLoaded);
-}
-
-static void webkitWebViewIconLoaded(WebKitFaviconDatabase *database, const char *frameURI, gboolean *iconOrPageLoaded)
-{
- quitMainLoopIfLoadCompleted(iconOrPageLoaded);
-}
-
-static void loadURI(const char *uri)
-{
- WebKitWebView *view = WEBKIT_WEB_VIEW(webkit_web_view_new());
- gboolean iconOrPageLoaded = FALSE;
-
- webkit_web_view_load_uri(view, uri);
-
- g_signal_connect(view, "notify::load-status", G_CALLBACK(idleQuitLoopCallback), &iconOrPageLoaded);
- g_signal_connect(view, "icon-loaded", G_CALLBACK(webkitWebViewIconLoaded), &iconOrPageLoaded);
-
- g_main_loop_run(loop);
-
- g_signal_handlers_disconnect_matched(view, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, &iconOrPageLoaded);
-}
-
-static gboolean faviconDatabaseGetValidFaviconIdle(void *userData)
-{
- webkit_favicon_database_get_favicon_pixbuf(webkit_get_favicon_database(), baseURI,
- gIconSize, gIconSize, NULL,
- faviconDatabaseGetValidFaviconCallback, userData);
- return FALSE;
-}
-
-static gboolean faviconDatabaseGetInvalidFaviconIdle(void *userData)
-{
- webkit_favicon_database_get_favicon_pixbuf(webkit_get_favicon_database(), "http://www.webkitgtk.org/",
- gIconSize, gIconSize, NULL,
- faviconDatabaseGetInvalidFaviconCallback, userData);
- return FALSE;
-}
-
-static gboolean faviconDatabaseGetFaviconCancelledIdle(void *userData)
-{
- GCancellable *cancellable = g_cancellable_new();
- webkit_favicon_database_get_favicon_pixbuf(webkit_get_favicon_database(), baseURI,
- gIconSize, gIconSize, cancellable,
- faviconDatabaseGetFaviconCancelledCallback, userData);
- g_cancellable_cancel(cancellable);
- g_object_unref(cancellable);
- return FALSE;
-}
-
-static void testWebKitFaviconDatabaseGetFavicon()
-{
- gboolean beenToIconCallback;
-
- loop = g_main_loop_new(NULL, TRUE);
-
- /* Load uri to make sure favicon is added to database. */
- loadURI(baseURI);
-
- beenToIconCallback = FALSE;
- g_idle_add((GSourceFunc)faviconDatabaseGetValidFaviconIdle, &beenToIconCallback);
- g_main_loop_run(loop);
- g_assert(beenToIconCallback);
-
- beenToIconCallback = FALSE;
- g_idle_add((GSourceFunc)faviconDatabaseGetInvalidFaviconIdle, &beenToIconCallback);
- g_main_loop_run(loop);
- g_assert(beenToIconCallback);
-
- beenToIconCallback = FALSE;
- g_idle_add((GSourceFunc)faviconDatabaseGetFaviconCancelledIdle, &beenToIconCallback);
- g_main_loop_run(loop);
- g_assert(beenToIconCallback);
-}
-
-static void testWebKitFaviconDatabaseGetFaviconURI()
-{
- char *iconURI = webkit_favicon_database_get_favicon_uri(webkit_get_favicon_database(), baseURI);
- char *expectedURI = g_strdup_printf("%sfavicon.ico", baseURI);
- g_assert_cmpstr(iconURI, ==, expectedURI);
- g_free(expectedURI);
- g_free(iconURI);
-}
-
-#endif
-
-static void testWebKitFaviconDatabaseRemoveAll(void)
-{
- WebKitFaviconDatabase *database = webkit_get_favicon_database();
- webkit_favicon_database_clear(database);
- char *iconURI = webkit_favicon_database_get_favicon_uri(database, baseURI);
- g_assert(!iconURI);
- g_free(iconURI);
-}
-
-static void testWebKitFaviconDatabaseCloseDatabase(void)
-{
- WebKitFaviconDatabase *database = webkit_get_favicon_database();
- char *databasePath = g_strdup(webkit_favicon_database_get_path(database));
- webkit_favicon_database_set_path(database, 0);
- deleteDatabaseFileIfExists(databasePath);
- g_free(databasePath);
-}
-
-int main(int argc, char **argv)
-{
- gtk_test_init(&argc, &argv, NULL);
-
- // Get rid of runtime warnings about deprecated properties and signals, since they break the tests.
- g_setenv("G_ENABLE_DIAGNOSTIC", "0", TRUE);
-
- /* This hopefully makes the test independent of the path it's called from. */
- testutils_relative_chdir("Tools/TestWebKitAPI/Tests/WebKitGtk/resources/test.html", argv[0]);
-
- SoupServer *server = soup_server_new(SOUP_SERVER_PORT, 0, NULL);
- soup_server_run_async(server);
-
- soup_server_add_handler(server, NULL, serverCallback, NULL, NULL);
-
- SoupURI *soupURI = soup_uri_new("http://127.0.0.1/");
- soup_uri_set_port(soupURI, soup_server_get_port(server));
-
- baseURI = soup_uri_to_string(soupURI, FALSE);
- soup_uri_free(soupURI);
-
- g_test_bug_base("https://bugs.webkit.org/");
- g_test_add_func("/webkit/favicondatabase/set-path", testWebKitFaviconDatabaseSetPath);
-
- // These two tests will trigger an ASSERTION on debug builds due
- // to http://webkit.org/b/67582. Remove the guards once the bug is fixed.
-#ifdef NDEBUG
- g_test_add_func("/webkit/favicondatabase/get-favicon", testWebKitFaviconDatabaseGetFavicon);
- g_test_add_func("/webkit/favicondatabase/get-favicon-uri", testWebKitFaviconDatabaseGetFaviconURI);
-#endif
-
- g_test_add_func("/webkit/favicondatabase/remove-all", testWebKitFaviconDatabaseRemoveAll);
- g_test_add_func("/webkit/favicondatabase/close-db", testWebKitFaviconDatabaseCloseDatabase);
-
- return g_test_run();
-}
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testglobals.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testglobals.c
deleted file mode 100644
index 4b9ec4fcf..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testglobals.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2010 Collabora Ltd.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include <gtk/gtk.h>
-#include <libsoup/soup.h>
-#include <webkit/webkit.h>
-
-// Make sure the session is initialized properly when webkit_get_default_session() is called.
-static void test_globals_default_session()
-{
- g_test_bug("36754");
-
- SoupSession* session = webkit_get_default_session();
- soup_session_remove_feature_by_type(session, WEBKIT_TYPE_SOUP_AUTH_DIALOG);
-
- // This makes sure our initialization ran.
- g_assert(soup_session_get_feature(session, SOUP_TYPE_CONTENT_DECODER) != NULL);
-
- // Creating a WebView should make sure the session is
- // initialized, and not mess with our changes.
- WebKitWebView* web_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(web_view);
- g_object_unref(web_view);
-
- // These makes sure our modification was kept.
- g_assert(soup_session_get_feature(session, SOUP_TYPE_CONTENT_DECODER) != NULL);
- g_assert(soup_session_get_feature(session, WEBKIT_TYPE_SOUP_AUTH_DIALOG) == NULL);
-}
-
-static void test_globals_security_policy()
-{
- // Check default policy for well known schemes.
- WebKitSecurityPolicy policy = webkit_get_security_policy_for_uri_scheme("http");
- guint mask = WEBKIT_SECURITY_POLICY_CORS_ENABLED;
- g_assert_cmpuint(policy & mask, ==, mask);
-
- policy = webkit_get_security_policy_for_uri_scheme("https");
- mask = WEBKIT_SECURITY_POLICY_SECURE | WEBKIT_SECURITY_POLICY_CORS_ENABLED;
- g_assert_cmpuint(policy & mask, ==, mask);
-
- policy = webkit_get_security_policy_for_uri_scheme("file");
- mask = WEBKIT_SECURITY_POLICY_LOCAL;
- g_assert_cmpuint(policy & mask, ==, mask);
-
- policy = webkit_get_security_policy_for_uri_scheme("data");
- mask = WEBKIT_SECURITY_POLICY_NO_ACCESS_TO_OTHER_SCHEME | WEBKIT_SECURITY_POLICY_SECURE;
- g_assert_cmpuint(policy & mask, ==, mask);
-
- policy = webkit_get_security_policy_for_uri_scheme("about");
- mask = WEBKIT_SECURITY_POLICY_NO_ACCESS_TO_OTHER_SCHEME | WEBKIT_SECURITY_POLICY_SECURE | WEBKIT_SECURITY_POLICY_EMPTY_DOCUMENT;
- g_assert_cmpuint(policy & mask, ==, mask);
-
- // Custom scheme.
- policy = webkit_get_security_policy_for_uri_scheme("foo");
- g_assert(!policy);
-
- policy |= WEBKIT_SECURITY_POLICY_LOCAL;
- webkit_set_security_policy_for_uri_scheme("foo", policy);
- g_assert_cmpuint(webkit_get_security_policy_for_uri_scheme("foo"), ==, policy);
-
- policy |= WEBKIT_SECURITY_POLICY_NO_ACCESS_TO_OTHER_SCHEME;
- webkit_set_security_policy_for_uri_scheme("foo", policy);
- g_assert_cmpuint(webkit_get_security_policy_for_uri_scheme("foo"), ==, policy);
-
- policy |= WEBKIT_SECURITY_POLICY_DISPLAY_ISOLATED;
- webkit_set_security_policy_for_uri_scheme("foo", policy);
- g_assert_cmpuint(webkit_get_security_policy_for_uri_scheme("foo"), ==, policy);
-
- policy |= WEBKIT_SECURITY_POLICY_SECURE;
- webkit_set_security_policy_for_uri_scheme("foo", policy);
- g_assert_cmpuint(webkit_get_security_policy_for_uri_scheme("foo"), ==, policy);
-
- policy |= WEBKIT_SECURITY_POLICY_CORS_ENABLED;
- webkit_set_security_policy_for_uri_scheme("foo", policy);
- g_assert_cmpuint(webkit_get_security_policy_for_uri_scheme("foo"), ==, policy);
-
- policy |= WEBKIT_SECURITY_POLICY_EMPTY_DOCUMENT;
- webkit_set_security_policy_for_uri_scheme("foo", policy);
- g_assert_cmpuint(webkit_get_security_policy_for_uri_scheme("foo"), ==, policy);
-}
-
-int main(int argc, char** argv)
-{
- gtk_test_init(&argc, &argv, NULL);
-
- g_test_bug_base("https://bugs.webkit.org/");
- g_test_add_func("/webkit/globals/default_session",
- test_globals_default_session);
- g_test_add_func("/webkit/globals/security-policy",
- test_globals_security_policy);
- return g_test_run();
-}
-
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testhittestresult.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testhittestresult.c
deleted file mode 100644
index eac34c47b..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testhittestresult.c
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2009 Igalia S.L.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2,1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include <errno.h>
-#include <unistd.h>
-#include <glib/gstdio.h>
-#include <webkit/webkit.h>
-
-typedef struct {
- char* data;
- guint flag;
-} TestInfo;
-
-static GMainLoop* loop;
-
-typedef struct {
- WebKitWebView* webView;
- TestInfo* info;
-} HitTestResultFixture;
-
-TestInfo*
-test_info_new(const char* data, guint flag)
-{
- TestInfo* info;
-
- info = g_slice_new(TestInfo);
- info->data = g_strdup(data);
- info->flag = flag;
-
- return info;
-}
-
-void
-test_info_destroy(TestInfo* info)
-{
- g_free(info->data);
- g_slice_free(TestInfo, info);
-}
-
-static void hit_test_result_fixture_setup(HitTestResultFixture* fixture, gconstpointer data)
-{
- fixture->webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(fixture->webView);
- loop = g_main_loop_new(NULL, TRUE);
- fixture->info = (TestInfo*)data;
-}
-
-static void hit_test_result_fixture_teardown(HitTestResultFixture* fixture, gconstpointer data)
-{
- g_object_unref(fixture->webView);
- g_main_loop_unref(loop);
- test_info_destroy(fixture->info);
-}
-
-static void
-load_status_cb(WebKitWebView* webView,
- GParamSpec* spec,
- gpointer data)
-{
- WebKitLoadStatus status = webkit_web_view_get_load_status(webView);
- TestInfo* info = (TestInfo*)data;
-
- if (status == WEBKIT_LOAD_FINISHED) {
- WebKitHitTestResult* result;
- guint context;
- GdkEvent* event = gdk_event_new(GDK_BUTTON_PRESS);
- WebKitDOMNode* node;
- gint x, y;
-
- /* Close enough to 0,0 */
- event->button.x = 5;
- event->button.y = 5;
-
- result = webkit_web_view_get_hit_test_result(webView, (GdkEventButton*) event);
- gdk_event_free(event);
- g_assert(result);
-
- g_object_get(result, "context", &context, NULL);
- g_assert(context & info->flag);
-
- g_object_get(result, "inner-node", &node, NULL);
- g_assert(node);
- g_assert(WEBKIT_DOM_IS_NODE(node));
-
- g_object_get(result, "x", &x, "y", &y, NULL);
- g_assert_cmpint(x, ==, 5);
- g_assert_cmpint(y, ==, 5);
-
- /* We can only test these node types at the moment. In the
- * input case there seems to be an extra layer with a DIV on
- * top of the input, which gets assigned to the inner-node.
- * tag */
- if (info->flag == WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT)
- g_assert(WEBKIT_DOM_IS_HTML_HTML_ELEMENT(node));
- else if (info->flag == WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE)
- g_assert(WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT(node));
- else if (info->flag == WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK) {
- /* The hit test will give us the inner text node, we want
- * the A tag */
- WebKitDOMNode* parent = webkit_dom_node_get_parent_node(node);
- g_assert(WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT(parent));
- }
-
- g_object_unref(result);
- g_main_loop_quit(loop);
- }
-}
-
-static void
-test_webkit_hit_test_result(HitTestResultFixture* fixture, gconstpointer data)
-{
- TestInfo* info = (TestInfo*)data;
- GtkAllocation allocation = { 0, 0, 50, 50 };
-
- webkit_web_view_load_string(fixture->webView,
- info->data,
- "text/html",
- "utf-8",
- "file://");
- gtk_widget_size_allocate(GTK_WIDGET(fixture->webView), &allocation);
- g_signal_connect(fixture->webView, "notify::load-status", G_CALLBACK(load_status_cb), info);
- g_main_loop_run(loop);
-}
-
-int main(int argc, char** argv)
-{
- gtk_test_init(&argc, &argv, NULL);
- // Get rid of runtime warnings about deprecated properties and signals, since they break the tests.
- g_setenv("G_ENABLE_DIAGNOSTIC", "0", TRUE);
-
- g_test_bug_base("https://bugs.webkit.org/");
-
- g_test_add("/webkit/hittestresult/document", HitTestResultFixture,
- test_info_new("<html><body><h1>WebKitGTK+!</h1></body></html>",
- WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT),
- hit_test_result_fixture_setup, test_webkit_hit_test_result, hit_test_result_fixture_teardown);
- /* We hardcode all elements to be at 0,0 so that we know where to
- * generate the button events */
- g_test_add("/webkit/hittestresult/image", HitTestResultFixture,
- test_info_new("<html><body><img style='position:absolute; left:0; top:0'src='0xdeadbeef' width=50 height=50></img></body></html>",
- WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE),
- hit_test_result_fixture_setup, test_webkit_hit_test_result, hit_test_result_fixture_teardown);
- g_test_add("/webkit/hittestresult/editable", HitTestResultFixture,
- test_info_new("<html><body><input style='position:absolute; left:0; top:0' size='35'></input>></body></html>",
- WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE),
- hit_test_result_fixture_setup, test_webkit_hit_test_result, hit_test_result_fixture_teardown);
- g_test_add("/webkit/hittestresult/link", HitTestResultFixture,
- test_info_new("<html><body><a style='position:absolute; left:0; top:0' href='http://www.example.com'>HELLO WORLD</a></body></html>",
- WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK),
- hit_test_result_fixture_setup, test_webkit_hit_test_result, hit_test_result_fixture_teardown);
-
- return g_test_run ();
-}
-
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testhttpbackend.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testhttpbackend.c
deleted file mode 100644
index 93776879b..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testhttpbackend.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2009 Gustavo Noronha Silva
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include <errno.h>
-#include <unistd.h>
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <gtk/gtk.h>
-#include <webkit/webkit.h>
-
-// Not yet public API
-SoupMessage* webkit_network_request_get_message(WebKitNetworkRequest* request);
-
-static gboolean navigation_policy_decision_requested_cb(WebKitWebView* web_view,
- WebKitWebFrame* web_frame,
- WebKitNetworkRequest* request,
- WebKitWebNavigationAction* action,
- WebKitWebPolicyDecision* decision,
- gpointer data)
-{
- SoupMessage* message = webkit_network_request_get_message(request);
-
- /* 1 -> webkit_network_request_with_core_request
- *
- * The SoupMessage is created exclusively for the emission of this
- * signal.
- */
- g_assert_cmpint(G_OBJECT(message)->ref_count, ==, 1);
-
- return FALSE;
-}
-
-static void test_soup_message_lifetime()
-{
- WebKitWebView* web_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
-
- g_object_ref_sink(web_view);
-
- g_signal_connect(web_view, "navigation-policy-decision-requested",
- G_CALLBACK(navigation_policy_decision_requested_cb),
- NULL);
-
- /* load_uri will trigger the navigation-policy-decision-requested
- * signal emission;
- */
- webkit_web_view_load_uri(web_view, "http://127.0.0.1/");
-
- g_object_unref(web_view);
-}
-
-int main(int argc, char** argv)
-{
- gtk_test_init(&argc, &argv, NULL);
-
- g_test_bug_base("https://bugs.webkit.org/");
- g_test_add_func("/webkit/soupmessage/lifetime", test_soup_message_lifetime);
- return g_test_run ();
-}
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testkeyevents.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testkeyevents.c
deleted file mode 100644
index acd01f35f..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testkeyevents.c
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * Copyright (C) 2009, 2010 Martin Robinson <mrobinson@webkit.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2,1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <glib/gstdio.h>
-#include <webkit/webkit.h>
-#include <JavaScriptCore/JSStringRef.h>
-#include <JavaScriptCore/JSContextRef.h>
-
-typedef struct {
- char* page;
- char* text;
- gboolean shouldBeHandled;
-} TestInfo;
-
-typedef struct {
- GtkWidget* window;
- WebKitWebView* webView;
- GMainLoop* loop;
- TestInfo* info;
-} KeyEventFixture;
-
-TestInfo*
-test_info_new(const char* page, gboolean shouldBeHandled)
-{
- TestInfo* info;
-
- info = g_slice_new(TestInfo);
- info->page = g_strdup(page);
- info->shouldBeHandled = shouldBeHandled;
- info->text = 0;
-
- return info;
-}
-
-void
-test_info_destroy(TestInfo* info)
-{
- g_free(info->page);
- g_free(info->text);
- g_slice_free(TestInfo, info);
-}
-
-static void key_event_fixture_setup(KeyEventFixture* fixture, gconstpointer data)
-{
- fixture->loop = g_main_loop_new(NULL, TRUE);
-
- fixture->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- fixture->webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
-
- gtk_container_add(GTK_CONTAINER(fixture->window), GTK_WIDGET(fixture->webView));
-}
-
-static void key_event_fixture_teardown(KeyEventFixture* fixture, gconstpointer data)
-{
- gtk_widget_destroy(fixture->window);
- g_main_loop_unref(fixture->loop);
- test_info_destroy(fixture->info);
-}
-
-static gboolean key_press_event_cb(WebKitWebView* webView, GdkEvent* event, gpointer data)
-{
- KeyEventFixture* fixture = (KeyEventFixture*)data;
- gboolean handled = GTK_WIDGET_GET_CLASS(fixture->webView)->key_press_event(GTK_WIDGET(fixture->webView), &event->key);
- g_assert_cmpint(handled, ==, fixture->info->shouldBeHandled);
-
- return FALSE;
-}
-
-static gboolean key_release_event_cb(WebKitWebView* webView, GdkEvent* event, gpointer data)
-{
- // WebCore never seems to mark keyup events as handled.
- KeyEventFixture* fixture = (KeyEventFixture*)data;
- gboolean handled = GTK_WIDGET_GET_CLASS(fixture->webView)->key_press_event(GTK_WIDGET(fixture->webView), &event->key);
- g_assert(!handled);
-
- g_main_loop_quit(fixture->loop);
-
- return FALSE;
-}
-
-static void test_keypress_events_load_status_cb(WebKitWebView* webView, GParamSpec* spec, gpointer data)
-{
- KeyEventFixture* fixture = (KeyEventFixture*)data;
- WebKitLoadStatus status = webkit_web_view_get_load_status(webView);
- if (status == WEBKIT_LOAD_FINISHED) {
- g_signal_connect(fixture->webView, "key-press-event",
- G_CALLBACK(key_press_event_cb), fixture);
- g_signal_connect(fixture->webView, "key-release-event",
- G_CALLBACK(key_release_event_cb), fixture);
- if (!gtk_test_widget_send_key(GTK_WIDGET(fixture->webView),
- gdk_unicode_to_keyval('a'), 0))
- g_assert_not_reached();
- }
-
-}
-
-gboolean map_event_cb(GtkWidget *widget, GdkEvent* event, gpointer data)
-{
- KeyEventFixture* fixture = (KeyEventFixture*)data;
- webkit_web_view_load_string(fixture->webView, fixture->info->page,
- "text/html", "utf-8", "file://");
- return FALSE;
-}
-
-static void setup_keyevent_test(KeyEventFixture* fixture, gconstpointer data, GCallback load_event_callback)
-{
- fixture->info = (TestInfo*)data;
- g_signal_connect(fixture->window, "map-event",
- G_CALLBACK(map_event_cb), fixture);
-
- gtk_widget_grab_focus(GTK_WIDGET(fixture->webView));
- gtk_widget_show(fixture->window);
- gtk_widget_show(GTK_WIDGET(fixture->webView));
- gtk_window_present(GTK_WINDOW(fixture->window));
-
- g_signal_connect(fixture->webView, "notify::load-status",
- load_event_callback, fixture);
-
- g_main_loop_run(fixture->loop);
-}
-
-static void test_keypress_events(KeyEventFixture* fixture, gconstpointer data)
-{
- setup_keyevent_test(fixture, data, G_CALLBACK(test_keypress_events_load_status_cb));
-}
-
-static gboolean element_text_equal_to(JSContextRef context, const gchar* text)
-{
- JSStringRef scriptString = JSStringCreateWithUTF8CString(
- "window.document.getElementById(\"in\").value;");
- JSValueRef value = JSEvaluateScript(context, scriptString, 0, 0, 0, 0);
- JSStringRelease(scriptString);
-
- // If the value isn't a string, the element is probably a div
- // so grab the innerText instead.
- if (!JSValueIsString(context, value)) {
- JSStringRef scriptString = JSStringCreateWithUTF8CString(
- "window.document.getElementById(\"in\").innerText;");
- value = JSEvaluateScript(context, scriptString, 0, 0, 0, 0);
- JSStringRelease(scriptString);
- }
-
- g_assert(JSValueIsString(context, value));
- JSStringRef inputString = JSValueToStringCopy(context, value, 0);
- g_assert(inputString);
-
- gint size = JSStringGetMaximumUTF8CStringSize(inputString);
- gchar* cString = g_malloc(size);
- JSStringGetUTF8CString(inputString, cString, size);
- JSStringRelease(inputString);
-
- gboolean result = g_utf8_collate(cString, text) == 0;
- g_free(cString);
- return result;
-}
-
-static void test_ime_load_status_cb(WebKitWebView* webView, GParamSpec* spec, gpointer data)
-{
- KeyEventFixture* fixture = (KeyEventFixture*)data;
- WebKitLoadStatus status = webkit_web_view_get_load_status(webView);
- if (status != WEBKIT_LOAD_FINISHED)
- return;
-
- JSGlobalContextRef context = webkit_web_frame_get_global_context(
- webkit_web_view_get_main_frame(webView));
- g_assert(context);
-
- GtkIMContext* imContext = 0;
- g_object_get(webView, "im-context", &imContext, NULL);
- g_assert(imContext);
-
- // Test that commits that happen outside of key events
- // change the text field immediately. This closely replicates
- // the behavior of SCIM.
- g_assert(element_text_equal_to(context, ""));
- g_signal_emit_by_name(imContext, "commit", "a");
- g_assert(element_text_equal_to(context, "a"));
- g_signal_emit_by_name(imContext, "commit", "b");
- g_assert(element_text_equal_to(context, "ab"));
- g_signal_emit_by_name(imContext, "commit", "c");
- g_assert(element_text_equal_to(context, "abc"));
-
- g_object_unref(imContext);
- g_main_loop_quit(fixture->loop);
-}
-
-static void test_ime(KeyEventFixture* fixture, gconstpointer data)
-{
- setup_keyevent_test(fixture, data, G_CALLBACK(test_ime_load_status_cb));
-}
-
-static gboolean verify_contents(gpointer data)
-{
- KeyEventFixture* fixture = (KeyEventFixture*)data;
- JSGlobalContextRef context = webkit_web_frame_get_global_context(
- webkit_web_view_get_main_frame(fixture->webView));
- g_assert(context);
-
- g_assert(element_text_equal_to(context, fixture->info->text));
- g_main_loop_quit(fixture->loop);
- return FALSE;
-}
-
-static void test_blocking_load_status_cb(WebKitWebView* webView, GParamSpec* spec, gpointer data)
-{
- KeyEventFixture* fixture = (KeyEventFixture*)data;
- WebKitLoadStatus status = webkit_web_view_get_load_status(webView);
- if (status != WEBKIT_LOAD_FINISHED)
- return;
-
- // The first keypress event should not modify the field.
- fixture->info->text = g_strdup("bc");
- if (!gtk_test_widget_send_key(GTK_WIDGET(fixture->webView),
- gdk_unicode_to_keyval('a'), 0))
- g_assert_not_reached();
- if (!gtk_test_widget_send_key(GTK_WIDGET(fixture->webView),
- gdk_unicode_to_keyval('b'), 0))
- g_assert_not_reached();
- if (!gtk_test_widget_send_key(GTK_WIDGET(fixture->webView),
- gdk_unicode_to_keyval('c'), 0))
- g_assert_not_reached();
-
- g_idle_add(verify_contents, fixture);
-}
-
-static void test_blocking(KeyEventFixture* fixture, gconstpointer data)
-{
- setup_keyevent_test(fixture, data, G_CALLBACK(test_blocking_load_status_cb));
-}
-
-#if defined(GDK_WINDOWING_X11)
-static void test_xim_load_status_cb(WebKitWebView* webView, GParamSpec* spec, gpointer data)
-{
- KeyEventFixture* fixture = (KeyEventFixture*)data;
- WebKitLoadStatus status = webkit_web_view_get_load_status(webView);
- if (status != WEBKIT_LOAD_FINISHED)
- return;
-
- GtkIMContext* imContext = 0;
- g_object_get(webView, "im-context", &imContext, NULL);
- g_assert(imContext);
-
- gchar* originalId = g_strdup(gtk_im_multicontext_get_context_id(GTK_IM_MULTICONTEXT(imContext)));
- gtk_im_multicontext_set_context_id(GTK_IM_MULTICONTEXT(imContext), "xim");
-
- // Test that commits that happen outside of key events
- // change the text field immediately. This closely replicates
- // the behavior of SCIM.
- fixture->info->text = g_strdup("debian");
- if (!gtk_test_widget_send_key(GTK_WIDGET(fixture->webView),
- gdk_unicode_to_keyval('d'), 0))
- g_assert_not_reached();
- if (!gtk_test_widget_send_key(GTK_WIDGET(fixture->webView),
- gdk_unicode_to_keyval('e'), 0))
- g_assert_not_reached();
- if (!gtk_test_widget_send_key(GTK_WIDGET(fixture->webView),
- gdk_unicode_to_keyval('b'), 0))
- g_assert_not_reached();
- if (!gtk_test_widget_send_key(GTK_WIDGET(fixture->webView),
- gdk_unicode_to_keyval('i'), 0))
- g_assert_not_reached();
- if (!gtk_test_widget_send_key(GTK_WIDGET(fixture->webView),
- gdk_unicode_to_keyval('a'), 0))
- g_assert_not_reached();
- if (!gtk_test_widget_send_key(GTK_WIDGET(fixture->webView),
- gdk_unicode_to_keyval('n'), 0))
- g_assert_not_reached();
-
- gtk_im_multicontext_set_context_id(GTK_IM_MULTICONTEXT(imContext), originalId);
- g_free(originalId);
- g_object_unref(imContext);
-
- g_idle_add(verify_contents, fixture);
-}
-
-static void test_xim(KeyEventFixture* fixture, gconstpointer data)
-{
- setup_keyevent_test(fixture, data, G_CALLBACK(test_xim_load_status_cb));
-}
-#endif
-
-int main(int argc, char** argv)
-{
- gtk_test_init(&argc, &argv, NULL);
-
- g_test_bug_base("https://bugs.webkit.org/");
-
-
- // We'll test input on a slew of different node types. Key events to
- // text inputs and editable divs should be marked as handled. Key events
- // to buttons and links should not.
- const char* textinput_html = "<html><body><input id=\"in\" type=\"text\">"
- "<script>document.getElementById('in').focus();</script></body></html>";
- const char* button_html = "<html><body><input id=\"in\" type=\"button\">"
- "<script>document.getElementById('in').focus();</script></body></html>";
- const char* link_html = "<html><body><a href=\"http://www.gnome.org\" id=\"in\">"
- "LINKY MCLINKERSON</a><script>document.getElementById('in').focus();</script>"
- "</body></html>";
- const char* div_html = "<html><body><div id=\"in\" contenteditable=\"true\">"
- "<script>document.getElementById('in').focus();</script></body></html>";
-
- // These are similar to the blocks above, but they should block the first
- // keypress modifying the editable node.
- const char* textinput_html_blocking = "<html><body>"
- "<input id=\"in\" type=\"text\" "
- "onkeypress=\"if (first) {event.preventDefault();first=false;}\">"
- "<script>first = true;\ndocument.getElementById('in').focus();</script>\n"
- "</script></body></html>";
- const char* div_html_blocking = "<html><body>"
- "<div id=\"in\" contenteditable=\"true\" "
- "onkeypress=\"if (first) {event.preventDefault();first=false;}\">"
- "<script>first = true; document.getElementById('in').focus();</script>\n"
- "</script></body></html>";
-
- g_test_add("/webkit/keyevents/event-textinput", KeyEventFixture,
- test_info_new(textinput_html, TRUE),
- key_event_fixture_setup,
- test_keypress_events,
- key_event_fixture_teardown);
- g_test_add("/webkit/keyevents/event-buttons", KeyEventFixture,
- test_info_new(button_html, FALSE),
- key_event_fixture_setup,
- test_keypress_events,
- key_event_fixture_teardown);
- g_test_add("/webkit/keyevents/event-link", KeyEventFixture,
- test_info_new(link_html, FALSE),
- key_event_fixture_setup,
- test_keypress_events,
- key_event_fixture_teardown);
- g_test_add("/webkit/keyevent/event-div", KeyEventFixture,
- test_info_new(div_html, TRUE),
- key_event_fixture_setup,
- test_keypress_events,
- key_event_fixture_teardown);
- g_test_add("/webkit/keyevent/ime-textinput", KeyEventFixture,
- test_info_new(textinput_html, TRUE),
- key_event_fixture_setup,
- test_ime,
- key_event_fixture_teardown);
- g_test_add("/webkit/keyevent/ime-div", KeyEventFixture,
- test_info_new(div_html, TRUE),
- key_event_fixture_setup,
- test_ime,
- key_event_fixture_teardown);
- g_test_add("/webkit/keyevent/block-textinput", KeyEventFixture,
- test_info_new(textinput_html_blocking, TRUE),
- key_event_fixture_setup,
- test_blocking,
- key_event_fixture_teardown);
- g_test_add("/webkit/keyevent/block-div", KeyEventFixture,
- test_info_new(div_html_blocking, TRUE),
- key_event_fixture_setup,
- test_blocking,
- key_event_fixture_teardown);
-#if defined(GDK_WINDOWING_X11)
- g_test_add("/webkit/keyevent/xim-textinput", KeyEventFixture,
- test_info_new(textinput_html, TRUE),
- key_event_fixture_setup,
- test_xim,
- key_event_fixture_teardown);
- g_test_add("/webkit/keyevent/xim-div", KeyEventFixture,
- test_info_new(div_html, TRUE),
- key_event_fixture_setup,
- test_xim,
- key_event_fixture_teardown);
-#endif
-
- return g_test_run();
-}
-
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testloading.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testloading.c
deleted file mode 100644
index 95246ec28..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testloading.c
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- * Copyright (C) 2009, 2010 Gustavo Noronha Silva
- * Copyright (C) 2009 Igalia S.L.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include <gtk/gtk.h>
-#include <libsoup/soup.h>
-#include <string.h>
-#include <webkit/webkit.h>
-
-/* This string has to be rather big because of the cancelled test - it
- * looks like soup refuses to send or receive a too small chunk */
-#define HTML_STRING "<html><body>Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!Testing!</body></html>"
-
-SoupURI* base_uri;
-
-/* For real request testing */
-static void
-server_callback(SoupServer* server, SoupMessage* msg,
- const char* path, GHashTable* query,
- SoupClientContext* context, gpointer data)
-{
- if (msg->method != SOUP_METHOD_GET) {
- soup_message_set_status(msg, SOUP_STATUS_NOT_IMPLEMENTED);
- return;
- }
-
- soup_message_set_status(msg, SOUP_STATUS_OK);
-
- if (g_str_equal(path, "/test_loading_status") || g_str_equal(path, "/test_loading_status2"))
- soup_message_body_append(msg->response_body, SOUP_MEMORY_STATIC, HTML_STRING, strlen(HTML_STRING));
- else if (g_str_equal(path, "/test_load_error")) {
- soup_message_set_status(msg, SOUP_STATUS_CANT_CONNECT);
- } else if (g_str_equal(path, "/test_loading_cancelled")) {
- soup_message_headers_set_encoding(msg->response_headers, SOUP_ENCODING_CHUNKED);
- soup_message_body_append(msg->response_body, SOUP_MEMORY_STATIC, HTML_STRING, strlen(HTML_STRING));
- soup_server_unpause_message(server, msg);
- return;
- }
-
- soup_message_body_complete(msg->response_body);
-}
-
-typedef struct {
- WebKitWebView* webView;
- GMainLoop *loop;
- gboolean has_been_provisional;
- gboolean has_been_committed;
- gboolean has_been_first_visually_non_empty_layout;
- gboolean has_been_finished;
- gboolean has_been_failed;
- gboolean has_been_load_error;
-} WebLoadingFixture;
-
-static void web_loading_fixture_setup(WebLoadingFixture* fixture, gconstpointer data)
-{
- fixture->webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- fixture->loop = g_main_loop_new(NULL, TRUE);
- g_object_ref_sink(fixture->webView);
- fixture->has_been_provisional = FALSE;
- fixture->has_been_committed = FALSE;
- fixture->has_been_first_visually_non_empty_layout = FALSE;
- fixture->has_been_finished = FALSE;
- fixture->has_been_failed = FALSE;
- fixture->has_been_load_error = FALSE;
-}
-
-static void web_loading_fixture_teardown(WebLoadingFixture* fixture, gconstpointer data)
-{
- g_object_unref(fixture->webView);
- g_main_loop_unref(fixture->loop);
-}
-
-static char* get_uri_for_path(const char* path)
-{
- SoupURI* uri;
- char* uri_string;
-
- uri = soup_uri_new_with_base(base_uri, path);
- uri_string = soup_uri_to_string(uri, FALSE);
- soup_uri_free (uri);
-
- return uri_string;
-}
-
-static void load_finished_cb(WebKitWebView* web_view, WebKitWebFrame* web_frame, WebLoadingFixture* fixture)
-{
- g_assert(fixture->has_been_provisional);
- g_assert(fixture->has_been_committed);
- g_assert(fixture->has_been_first_visually_non_empty_layout);
-
- g_main_loop_quit(fixture->loop);
-}
-
-
-static void status_changed_cb(GObject* object, GParamSpec* pspec, WebLoadingFixture* fixture)
-{
- WebKitLoadStatus status = webkit_web_view_get_load_status(WEBKIT_WEB_VIEW(object));
-
- switch (status) {
- case WEBKIT_LOAD_PROVISIONAL:
- g_assert(!fixture->has_been_provisional);
- g_assert(!fixture->has_been_committed);
- g_assert(!fixture->has_been_first_visually_non_empty_layout);
- fixture->has_been_provisional = TRUE;
- break;
- case WEBKIT_LOAD_COMMITTED:
- g_assert(fixture->has_been_provisional);
- g_assert(!fixture->has_been_committed);
- g_assert(!fixture->has_been_first_visually_non_empty_layout);
- fixture->has_been_committed = TRUE;
- break;
- case WEBKIT_LOAD_FIRST_VISUALLY_NON_EMPTY_LAYOUT:
- g_assert(fixture->has_been_provisional);
- g_assert(fixture->has_been_committed);
- g_assert(!fixture->has_been_first_visually_non_empty_layout);
- fixture->has_been_first_visually_non_empty_layout = TRUE;
- break;
- case WEBKIT_LOAD_FINISHED:
- g_assert(fixture->has_been_provisional);
- g_assert(fixture->has_been_committed);
- g_assert(fixture->has_been_first_visually_non_empty_layout);
- break;
- default:
- g_assert_not_reached();
- }
-}
-
-static void test_loading_status(WebLoadingFixture* fixture, gconstpointer data)
-{
- char* uri_string;
-
- g_assert_cmpint(webkit_web_view_get_load_status(fixture->webView), ==, WEBKIT_LOAD_PROVISIONAL);
-
- g_object_connect(G_OBJECT(fixture->webView),
- "signal::notify::load-status", G_CALLBACK(status_changed_cb), fixture,
- "signal::load-finished", G_CALLBACK(load_finished_cb), fixture,
- NULL);
-
- uri_string = get_uri_for_path("/test_loading_status");
-
- /* load_uri will trigger the navigation-policy-decision-requested
- * signal emission;
- */
- webkit_web_view_load_uri(fixture->webView, uri_string);
- g_free(uri_string);
-
- g_main_loop_run(fixture->loop);
-}
-
-static void load_error_status_changed_cb(GObject* object, GParamSpec* pspec, WebLoadingFixture* fixture)
-{
- WebKitLoadStatus status = webkit_web_view_get_load_status(WEBKIT_WEB_VIEW(object));
-
- switch(status) {
- case WEBKIT_LOAD_PROVISIONAL:
- g_assert(!fixture->has_been_provisional);
- fixture->has_been_provisional = TRUE;
- break;
- case WEBKIT_LOAD_COMMITTED:
- g_assert(!fixture->has_been_committed);
- fixture->has_been_committed = TRUE;
- break;
- case WEBKIT_LOAD_FINISHED:
- g_assert(fixture->has_been_provisional);
- g_assert(fixture->has_been_load_error);
- g_assert(fixture->has_been_failed);
- g_assert(!fixture->has_been_finished);
- fixture->has_been_finished = TRUE;
- break;
- case WEBKIT_LOAD_FAILED:
- g_assert(!fixture->has_been_failed);
- fixture->has_been_failed = TRUE;
- g_main_loop_quit(fixture->loop);
- break;
- default:
- break;
- }
-}
-
-static gboolean load_error_cb(WebKitWebView* webView, WebKitWebFrame* frame, const char* uri, GError *error, WebLoadingFixture* fixture)
-{
- g_assert(fixture->has_been_provisional);
- g_assert(!fixture->has_been_load_error);
- fixture->has_been_load_error = TRUE;
-
- return FALSE;
-}
-
-static void test_loading_error(WebLoadingFixture* fixture, gconstpointer data)
-{
- char* uri_string;
-
- g_test_bug("28842");
-
- g_signal_connect(fixture->webView, "load-error", G_CALLBACK(load_error_cb), fixture);
- g_signal_connect(fixture->webView, "notify::load-status", G_CALLBACK(load_error_status_changed_cb), fixture);
-
- uri_string = get_uri_for_path("/test_load_error");
- webkit_web_view_load_uri(fixture->webView, uri_string);
- g_free(uri_string);
-
- g_main_loop_run(fixture->loop);
-
- g_assert(fixture->has_been_provisional);
- g_assert(!fixture->has_been_committed);
- g_assert(fixture->has_been_load_error);
- g_assert(fixture->has_been_failed);
- g_assert(!fixture->has_been_finished);
-}
-
-/* Cancelled load */
-
-static gboolean load_cancelled_cb(WebKitWebView* webView, WebKitWebFrame* frame, const char* uri, GError *error, WebLoadingFixture* fixture)
-{
- g_assert(fixture->has_been_provisional);
- g_assert(fixture->has_been_failed);
- g_assert(!fixture->has_been_load_error);
- g_assert(error->code == WEBKIT_NETWORK_ERROR_CANCELLED);
- fixture->has_been_load_error = TRUE;
-
- return TRUE;
-}
-
-static gboolean stop_load (gpointer data)
-{
- webkit_web_view_stop_loading(WEBKIT_WEB_VIEW(data));
- return FALSE;
-}
-
-static void load_cancelled_status_changed_cb(GObject* object, GParamSpec* pspec, WebLoadingFixture* fixture)
-{
- WebKitLoadStatus status = webkit_web_view_get_load_status(WEBKIT_WEB_VIEW(object));
-
- switch(status) {
- case WEBKIT_LOAD_PROVISIONAL:
- g_assert(!fixture->has_been_provisional);
- g_assert(!fixture->has_been_failed);
- fixture->has_been_provisional = TRUE;
- break;
- case WEBKIT_LOAD_COMMITTED:
- g_idle_add (stop_load, object);
- break;
- case WEBKIT_LOAD_FAILED:
- g_assert(fixture->has_been_provisional);
- g_assert(!fixture->has_been_failed);
- g_assert(!fixture->has_been_load_error);
- fixture->has_been_failed = TRUE;
- g_main_loop_quit(fixture->loop);
- break;
- case WEBKIT_LOAD_FINISHED:
- g_assert_not_reached();
- break;
- default:
- break;
- }
-}
-
-static void test_loading_cancelled(WebLoadingFixture* fixture, gconstpointer data)
-{
- char* uri_string;
-
- g_test_bug("29644");
-
- g_signal_connect(fixture->webView, "load-error", G_CALLBACK(load_cancelled_cb), fixture);
- g_signal_connect(fixture->webView, "notify::load-status", G_CALLBACK(load_cancelled_status_changed_cb), fixture);
-
- uri_string = get_uri_for_path("/test_loading_cancelled");
- webkit_web_view_load_uri(fixture->webView, uri_string);
- g_free(uri_string);
-
- g_main_loop_run(fixture->loop);
-}
-
-static void load_goback_status_changed_cb(GObject* object, GParamSpec* pspec, WebLoadingFixture* fixture)
-{
- WebKitLoadStatus status = webkit_web_view_get_load_status(WEBKIT_WEB_VIEW(object));
-
- switch(status) {
- case WEBKIT_LOAD_PROVISIONAL:
- g_assert(!fixture->has_been_provisional);
- fixture->has_been_provisional = TRUE;
- break;
- case WEBKIT_LOAD_COMMITTED:
- g_assert(fixture->has_been_provisional);
- fixture->has_been_committed = TRUE;
- break;
- case WEBKIT_LOAD_FAILED:
- g_assert_not_reached();
- break;
- case WEBKIT_LOAD_FINISHED:
- g_assert(fixture->has_been_provisional);
- g_assert(fixture->has_been_committed);
- fixture->has_been_finished = TRUE;
- g_main_loop_quit(fixture->loop);
- break;
- default:
- break;
- }
-}
-
-static void load_wentback_status_changed_cb(GObject* object, GParamSpec* pspec, WebLoadingFixture* fixture)
-{
- WebKitLoadStatus status = webkit_web_view_get_load_status(WEBKIT_WEB_VIEW(object));
- char* uri_string;
- char* uri_string2;
-
- uri_string = get_uri_for_path("/test_loading_status");
- uri_string2 = get_uri_for_path("/test_loading_status2");
-
- switch(status) {
- case WEBKIT_LOAD_PROVISIONAL:
- g_assert_cmpstr(webkit_web_view_get_uri(fixture->webView), ==, uri_string2);
- break;
- case WEBKIT_LOAD_COMMITTED:
- g_assert_cmpstr(webkit_web_view_get_uri(fixture->webView), ==, uri_string);
- break;
- case WEBKIT_LOAD_FAILED:
- g_assert_not_reached();
- break;
- case WEBKIT_LOAD_FINISHED:
- g_assert_cmpstr(webkit_web_view_get_uri(fixture->webView), ==, uri_string);
- g_main_loop_quit(fixture->loop);
- break;
- default:
- break;
- }
-
- g_free(uri_string);
- g_free(uri_string2);
-}
-
-static void load_error_test(WebKitWebView* webview, WebKitWebFrame* frame, const char* uri, GError* error)
-{
- g_debug("Error: %s", error->message);
-}
-
-static void test_loading_goback(WebLoadingFixture* fixture, gconstpointer data)
-{
- char* uri_string;
-
- g_signal_connect(fixture->webView, "notify::load-status", G_CALLBACK(load_goback_status_changed_cb), fixture);
-
- g_signal_connect(fixture->webView, "load-error", G_CALLBACK(load_error_test), fixture);
-
- uri_string = get_uri_for_path("/test_loading_status");
- webkit_web_view_load_uri(fixture->webView, uri_string);
- g_free(uri_string);
-
- g_main_loop_run(fixture->loop);
-
- fixture->has_been_provisional = FALSE;
- fixture->has_been_committed = FALSE;
- fixture->has_been_first_visually_non_empty_layout = FALSE;
- fixture->has_been_finished = FALSE;
- fixture->has_been_failed = FALSE;
- fixture->has_been_load_error = FALSE;
-
- uri_string = get_uri_for_path("/test_loading_status2");
- webkit_web_view_load_uri(fixture->webView, uri_string);
- g_free(uri_string);
-
- g_main_loop_run(fixture->loop);
-
- g_signal_handlers_disconnect_by_func(fixture->webView, load_goback_status_changed_cb, fixture);
-
- fixture->has_been_provisional = FALSE;
- fixture->has_been_committed = FALSE;
- fixture->has_been_first_visually_non_empty_layout = FALSE;
- fixture->has_been_finished = FALSE;
- fixture->has_been_failed = FALSE;
- fixture->has_been_load_error = FALSE;
-
- g_signal_connect(fixture->webView, "notify::load-status", G_CALLBACK(load_wentback_status_changed_cb), fixture);
- webkit_web_view_go_back(fixture->webView);
-
- g_main_loop_run(fixture->loop);
-
- g_signal_handlers_disconnect_by_func(fixture->webView, load_wentback_status_changed_cb, fixture);
-}
-
-int main(int argc, char** argv)
-{
- SoupServer* server;
-
- gtk_test_init(&argc, &argv, NULL);
- // Get rid of runtime warnings about deprecated properties and signals, since they break the tests.
- g_setenv("G_ENABLE_DIAGNOSTIC", "0", TRUE);
-
- server = soup_server_new(SOUP_SERVER_PORT, 0, NULL);
- soup_server_run_async(server);
-
- soup_server_add_handler(server, NULL, server_callback, NULL, NULL);
-
- base_uri = soup_uri_new("http://127.0.0.1/");
- soup_uri_set_port(base_uri, soup_server_get_port(server));
-
- g_test_bug_base("https://bugs.webkit.org/");
- g_test_add("/webkit/loading/status",
- WebLoadingFixture, NULL,
- web_loading_fixture_setup,
- test_loading_status,
- web_loading_fixture_teardown);
- g_test_add("/webkit/loading/error",
- WebLoadingFixture, NULL,
- web_loading_fixture_setup,
- test_loading_error,
- web_loading_fixture_teardown);
- g_test_add("/webkit/loading/cancelled",
- WebLoadingFixture, NULL,
- web_loading_fixture_setup,
- test_loading_cancelled,
- web_loading_fixture_teardown);
- g_test_add("/webkit/loading/goback",
- WebLoadingFixture, NULL,
- web_loading_fixture_setup,
- test_loading_goback,
- web_loading_fixture_teardown);
- return g_test_run();
-}
-
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testmimehandling.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testmimehandling.c
deleted file mode 100644
index 82568caf2..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testmimehandling.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (C) 2009 Jan Michael Alonzo
- * Copyright (C) 2009 Gustavo Noronha Silva
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include "test_utils.h"
-
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <libsoup/soup.h>
-#include <string.h>
-#include <webkit/webkit.h>
-#include <unistd.h>
-
-GMainLoop* loop;
-SoupSession *session;
-char* base_uri;
-
-/* For real request testing */
-static void
-server_callback(SoupServer *server, SoupMessage *msg,
- const char *path, GHashTable *query,
- SoupClientContext *context, gpointer data)
-{
- if (msg->method != SOUP_METHOD_GET) {
- soup_message_set_status(msg, SOUP_STATUS_NOT_IMPLEMENTED);
- return;
- }
-
- soup_message_set_status(msg, SOUP_STATUS_OK);
-
- /* PDF */
- if (g_str_equal(path, "/pdf")) {
- char* contents;
- gsize length;
- GError* error = NULL;
-
- g_file_get_contents("test.pdf", &contents, &length, &error);
- g_assert(!error);
-
- soup_message_body_append(msg->response_body, SOUP_MEMORY_TAKE, contents, length);
- } else if (g_str_equal(path, "/html")) {
- char* contents;
- gsize length;
- GError* error = NULL;
-
- g_file_get_contents("test.html", &contents, &length, &error);
- g_assert(!error);
-
- soup_message_body_append(msg->response_body, SOUP_MEMORY_TAKE, contents, length);
- } else if (g_str_equal(path, "/text")) {
- char* contents;
- gsize length;
- GError* error = NULL;
-
- soup_message_headers_append(msg->response_headers, "Content-Disposition", "attachment; filename=test.txt");
-
- g_file_get_contents("test.txt", &contents, &length, &error);
- g_assert(!error);
-
- soup_message_body_append(msg->response_body, SOUP_MEMORY_TAKE, contents, length);
- }
-
- soup_message_body_complete(msg->response_body);
-}
-
-static void idle_quit_loop_cb(WebKitWebView* web_view, GParamSpec* pspec, gpointer data)
-{
- if (webkit_web_view_get_load_status(web_view) == WEBKIT_LOAD_FINISHED ||
- webkit_web_view_get_load_status(web_view) == WEBKIT_LOAD_FAILED)
- g_main_loop_quit(loop);
-}
-
-static gboolean mime_type_policy_decision_requested_cb(WebKitWebView* view, WebKitWebFrame* frame,
- WebKitNetworkRequest* request, const char* mime_type,
- WebKitWebPolicyDecision* decision, gpointer data)
-{
- char* type = (char*)data;
-
- if (g_str_equal(type, "pdf")) {
- g_assert_cmpstr(mime_type, ==, "application/pdf");
- g_assert(!webkit_web_view_can_show_mime_type(view, mime_type));
- } else if (g_str_equal(type, "html")) {
- g_assert_cmpstr(mime_type, ==, "text/html");
- g_assert(webkit_web_view_can_show_mime_type(view, mime_type));
- } else if (g_str_equal(type, "text")) {
- WebKitNetworkResponse* response = webkit_web_frame_get_network_response(frame);
- SoupMessage* message = webkit_network_response_get_message(response);
- char* disposition;
-
- g_assert(message);
- soup_message_headers_get_content_disposition(message->response_headers,
- &disposition, NULL);
- g_object_unref(response);
-
- g_assert_cmpstr(disposition, ==, "attachment");
- g_free(disposition);
-
- g_assert_cmpstr(mime_type, ==, "text/plain");
- g_assert(webkit_web_view_can_show_mime_type(view, mime_type));
- }
-
- g_free(type);
-
- return FALSE;
-}
-
-static void testRemoteMimeType(const void* data)
-{
- const char* name = (const char*) data;
- WebKitWebView* view = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(G_OBJECT(view));
-
- loop = g_main_loop_new(NULL, TRUE);
-
- g_object_connect(G_OBJECT(view),
- "signal::notify::load-status", idle_quit_loop_cb, NULL,
- "signal::mime-type-policy-decision-requested", mime_type_policy_decision_requested_cb, g_strdup(name),
- NULL);
-
- char* effective_uri = g_strdup_printf("%s%s", base_uri, name);
- webkit_web_view_load_uri(view, effective_uri);
- g_free(effective_uri);
-
- g_main_loop_run(loop);
-
- g_object_unref(view);
-}
-
-static void testLocalMimeType(const void* data)
-{
- const char* typeName = (const char*) data;
- WebKitWebView* view = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(G_OBJECT(view));
-
- loop = g_main_loop_new(NULL, TRUE);
-
- g_object_connect(G_OBJECT(view),
- "signal::notify::load-status", idle_quit_loop_cb, NULL,
- "signal::mime-type-policy-decision-requested", mime_type_policy_decision_requested_cb, g_strdup(typeName),
- NULL);
-
- gchar* filename = g_strdup_printf("test.%s", typeName);
- GFile* file = g_file_new_for_path(filename);
- g_free(filename);
-
- gchar* fileURI = g_file_get_uri(file);
- g_object_unref(file);
-
- webkit_web_view_load_uri(view, fileURI);
- g_free(fileURI);
-
- g_main_loop_run(loop);
- g_object_unref(view);
-}
-
-int main(int argc, char** argv)
-{
- SoupServer* server;
- SoupURI* soup_uri;
-
- gtk_test_init(&argc, &argv, NULL);
-
- // Get rid of runtime warnings about deprecated properties and signals, since they break the tests.
- g_setenv("G_ENABLE_DIAGNOSTIC", "0", TRUE);
-
- /* Hopefully make test independent of the path it's called from. */
- testutils_relative_chdir("Tools/TestWebKitAPI/Tests/WebKitGtk/resources/test.html", argv[0]);
-
- server = soup_server_new(SOUP_SERVER_PORT, 0, NULL);
- soup_server_run_async(server);
-
- soup_server_add_handler(server, NULL, server_callback, NULL, NULL);
-
- soup_uri = soup_uri_new("http://127.0.0.1/");
- soup_uri_set_port(soup_uri, soup_server_get_port(server));
-
- base_uri = soup_uri_to_string(soup_uri, FALSE);
- soup_uri_free(soup_uri);
-
- g_test_bug_base("https://bugs.webkit.org/");
- g_test_add_data_func("/webkit/mime/remote-PDF", "pdf", testRemoteMimeType);
- g_test_add_data_func("/webkit/mime/remote-HTML", "html", testRemoteMimeType);
- g_test_add_data_func("/webkit/mime/remote-TEXT", "text", testRemoteMimeType);
- g_test_add_data_func("/webkit/mime/local-PDF", "pdf", testLocalMimeType);
- g_test_add_data_func("/webkit/mime/local-HTML", "html", testLocalMimeType);
- g_test_add_data_func("/webkit/mime/local-TEXT", "text", testLocalMimeType);
-
- return g_test_run();
-}
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testnetworkrequest.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testnetworkrequest.c
deleted file mode 100644
index 1b2c90f2d..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testnetworkrequest.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2009 Gustavo Noronha Silva
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include <errno.h>
-#include <unistd.h>
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <gtk/gtk.h>
-#include <stdlib.h>
-#include <webkit/webkit.h>
-
-static void test_network_request_create_destroy()
-{
- WebKitNetworkRequest* request;
- SoupMessage* message;
-
- /* Test creation with URI */
- request = WEBKIT_NETWORK_REQUEST(g_object_new(WEBKIT_TYPE_NETWORK_REQUEST, "uri", "http://debian.org/", NULL));
- g_assert(WEBKIT_IS_NETWORK_REQUEST(request));
- message = webkit_network_request_get_message(request);
- g_assert(!message);
- g_object_unref(request);
-
- /* Test creation with SoupMessage */
- message = soup_message_new("GET", "http://debian.org/");
- request = WEBKIT_NETWORK_REQUEST(g_object_new(WEBKIT_TYPE_NETWORK_REQUEST, "message", message, NULL));
- g_assert(WEBKIT_IS_NETWORK_REQUEST(request));
- g_assert_cmpint(G_OBJECT(message)->ref_count, ==, 2);
- g_object_unref(request);
- g_assert_cmpint(G_OBJECT(message)->ref_count, ==, 1);
- g_object_unref(message);
-
- /* Test creation with both SoupMessage and URI */
- message = soup_message_new("GET", "http://debian.org/");
- request = WEBKIT_NETWORK_REQUEST(g_object_new(WEBKIT_TYPE_NETWORK_REQUEST, "message", message, "uri", "http://gnome.org/", NULL));
- g_assert(WEBKIT_IS_NETWORK_REQUEST(request));
- g_assert_cmpint(G_OBJECT(message)->ref_count, ==, 2);
- g_assert_cmpstr(webkit_network_request_get_uri(request), ==, "http://gnome.org/");
- g_object_unref(request);
- g_assert_cmpint(G_OBJECT(message)->ref_count, ==, 1);
- g_object_unref(message);
-}
-
-static void test_network_request_properties()
-{
- WebKitNetworkRequest* request;
- SoupMessage* message;
- gchar* soupURI;
-
- /* Test URI is set correctly when creating with URI */
- request = webkit_network_request_new("http://debian.org/");
- g_assert(WEBKIT_IS_NETWORK_REQUEST(request));
- g_assert_cmpstr(webkit_network_request_get_uri(request), ==, "http://debian.org/");
- g_object_unref(request);
-
- /* Test URI is set correctly when creating with Message */
- message = soup_message_new("GET", "http://debian.org/");
- request = WEBKIT_NETWORK_REQUEST(g_object_new(WEBKIT_TYPE_NETWORK_REQUEST, "message", message, NULL));
- g_assert(WEBKIT_IS_NETWORK_REQUEST(request));
- g_object_unref(message);
-
- message = webkit_network_request_get_message(request);
- soupURI = soup_uri_to_string(soup_message_get_uri(message), FALSE);
- g_assert_cmpstr(soupURI, ==, "http://debian.org/");
- g_free(soupURI);
-
- g_assert_cmpstr(webkit_network_request_get_uri(request), ==, "http://debian.org/");
- g_object_unref(request);
-}
-
-int main(int argc, char** argv)
-{
- gtk_test_init(&argc, &argv, NULL);
-
- g_test_bug_base("https://bugs.webkit.org/");
- g_test_add_func("/webkit/networkrequest/createdestroy", test_network_request_create_destroy);
- g_test_add_func("/webkit/networkrequest/properties", test_network_request_properties);
- return g_test_run ();
-}
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testnetworkresponse.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testnetworkresponse.c
deleted file mode 100644
index b806aa111..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testnetworkresponse.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2009 Gustavo Noronha Silva
- * Copyright (C) 2009 Collabora Ltd.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include <errno.h>
-#include <unistd.h>
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <gtk/gtk.h>
-#include <stdlib.h>
-#include <webkit/webkit.h>
-
-static void test_network_response_create_destroy()
-{
- WebKitNetworkResponse* response;
- SoupMessage* message;
-
- /* Test creation with URI */
- response = WEBKIT_NETWORK_RESPONSE(g_object_new(WEBKIT_TYPE_NETWORK_RESPONSE, "uri", "http://debian.org/", NULL));
- g_assert(WEBKIT_IS_NETWORK_RESPONSE(response));
- message = webkit_network_response_get_message(response);
- g_assert(!message);
- g_object_unref(response);
-
- /* Test creation with SoupMessage */
- message = soup_message_new("GET", "http://debian.org/");
- response = WEBKIT_NETWORK_RESPONSE(g_object_new(WEBKIT_TYPE_NETWORK_RESPONSE, "message", message, NULL));
- g_assert(WEBKIT_IS_NETWORK_RESPONSE(response));
- g_assert_cmpint(G_OBJECT(message)->ref_count, ==, 2);
- g_object_unref(response);
- g_assert_cmpint(G_OBJECT(message)->ref_count, ==, 1);
- g_object_unref(message);
-
- /* Test creation with both SoupMessage and URI */
- message = soup_message_new("GET", "http://debian.org/");
- response = WEBKIT_NETWORK_RESPONSE(g_object_new(WEBKIT_TYPE_NETWORK_RESPONSE, "message", message, "uri", "http://gnome.org/", NULL));
- g_assert(WEBKIT_IS_NETWORK_RESPONSE(response));
- g_assert_cmpint(G_OBJECT(message)->ref_count, ==, 2);
- g_assert_cmpstr(webkit_network_response_get_uri(response), ==, "http://gnome.org/");
- g_object_unref(response);
- g_assert_cmpint(G_OBJECT(message)->ref_count, ==, 1);
- g_object_unref(message);
-}
-
-static void test_network_response_properties()
-{
- WebKitNetworkResponse* response;
- SoupMessage* message;
- gchar* soupURI;
-
- /* Test URI is set correctly when creating with URI */
- response = webkit_network_response_new("http://debian.org/");
- g_assert(WEBKIT_IS_NETWORK_RESPONSE(response));
- g_assert_cmpstr(webkit_network_response_get_uri(response), ==, "http://debian.org/");
- g_object_unref(response);
-
- /* Test URI is set correctly when creating with Message */
- message = soup_message_new("GET", "http://debian.org/");
- response = WEBKIT_NETWORK_RESPONSE(g_object_new(WEBKIT_TYPE_NETWORK_RESPONSE, "message", message, NULL));
- g_assert(WEBKIT_IS_NETWORK_RESPONSE(response));
- g_object_unref(message);
-
- message = webkit_network_response_get_message(response);
- soupURI = soup_uri_to_string(soup_message_get_uri(message), FALSE);
- g_assert_cmpstr(soupURI, ==, "http://debian.org/");
- g_free(soupURI);
-
- g_assert_cmpstr(webkit_network_response_get_uri(response), ==, "http://debian.org/");
- g_object_unref(response);
-}
-
-int main(int argc, char** argv)
-{
- gtk_test_init(&argc, &argv, NULL);
-
- g_test_bug_base("https://bugs.webkit.org/");
- g_test_add_func("/webkit/networkresponse/createdestroy", test_network_response_create_destroy);
- g_test_add_func("/webkit/networkresponse/properties", test_network_response_properties);
- return g_test_run ();
-}
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebbackforwardlist.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebbackforwardlist.c
deleted file mode 100644
index 7782d4070..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebbackforwardlist.c
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * Copyright (C) 2008 Holger Hans Peter Freyther
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include <glib.h>
-#include <gtk/gtk.h>
-#include <webkit/webkit.h>
-
-static void test_webkit_web_history_item_lifetime(void)
-{
- WebKitWebView* webView;
- WebKitWebBackForwardList* backForwardList;
- WebKitWebHistoryItem* currentItem;
- WebKitWebHistoryItem* forwardItem;
- WebKitWebHistoryItem* backItem;
- WebKitWebHistoryItem* nthItem;
- WebKitWebHistoryItem* item1;
- WebKitWebHistoryItem* item2;
- WebKitWebHistoryItem* item3;
- WebKitWebHistoryItem* item4;
- GList* backList = NULL;
- GList* forwardList = NULL;
- g_test_bug("19898");
-
- webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(webView);
- backForwardList = webkit_web_view_get_back_forward_list(webView);
- g_assert_cmpint(G_OBJECT(backForwardList)->ref_count, ==, 1);
-
- /* add test items */
- item1 = webkit_web_history_item_new_with_data("http://example.com/1/", "Site 1");
- webkit_web_back_forward_list_add_item(backForwardList, item1);
- g_object_unref(item1);
-
- item2 = webkit_web_history_item_new_with_data("http://example.com/2/", "Site 2");
- webkit_web_back_forward_list_add_item(backForwardList, item2);
- g_object_unref(item2);
-
- item3 = webkit_web_history_item_new_with_data("http://example.com/3/", "Site 3");
- webkit_web_back_forward_list_add_item(backForwardList, item3);
- g_object_unref(item3);
-
- item4 = webkit_web_history_item_new_with_data("http://example.com/4/", "Site 4");
- webkit_web_back_forward_list_add_item(backForwardList, item4);
- g_object_unref(item4);
-
- /* make sure these functions don't add unnecessary ref to the history item */
- backItem = webkit_web_back_forward_list_get_back_item(backForwardList);
- g_object_ref(backItem);
- g_assert_cmpint(G_OBJECT(backItem)->ref_count, ==, 2);
- g_object_unref(backItem);
- g_assert_cmpint(G_OBJECT(backItem)->ref_count, ==, 1);
-
- currentItem = webkit_web_back_forward_list_get_current_item(backForwardList);
- g_object_ref(currentItem);
- g_assert_cmpint(G_OBJECT(currentItem)->ref_count, ==, 2);
- g_object_unref(currentItem);
- g_assert_cmpint(G_OBJECT(currentItem)->ref_count, ==, 1);
-
- webkit_web_back_forward_list_go_to_item(backForwardList, item2);
- forwardItem = webkit_web_back_forward_list_get_forward_item(backForwardList);
- g_object_ref(forwardItem);
- g_assert_cmpint(G_OBJECT(forwardItem)->ref_count, ==, 2);
- g_object_unref(forwardItem);
- g_assert_cmpint(G_OBJECT(forwardItem)->ref_count, ==, 1);
-
- nthItem = webkit_web_back_forward_list_get_nth_item(backForwardList, 1);
- g_object_ref(nthItem);
- g_assert_cmpint(G_OBJECT(nthItem)->ref_count, ==, 2);
- g_object_unref(nthItem);
- g_assert_cmpint(G_OBJECT(nthItem)->ref_count, ==, 1);
-
- backList = webkit_web_back_forward_list_get_back_list_with_limit(backForwardList, 5);
- for (; backList; backList = backList->next)
- g_assert_cmpint(G_OBJECT(backList->data)->ref_count, ==, 1);
-
- forwardList = webkit_web_back_forward_list_get_forward_list_with_limit(backForwardList, 5);
- for (; forwardList; forwardList = forwardList->next)
- g_assert_cmpint(G_OBJECT(forwardList->data)->ref_count, ==, 1);
-
- g_list_free(forwardList);
- g_list_free(backList);
- g_assert_cmpint(G_OBJECT(item1)->ref_count, ==, 1);
- g_assert_cmpint(G_OBJECT(item2)->ref_count, ==, 1);
- g_assert_cmpint(G_OBJECT(item3)->ref_count, ==, 1);
- g_assert_cmpint(G_OBJECT(item4)->ref_count, ==, 1);
- g_assert_cmpint(G_OBJECT(backForwardList)->ref_count, ==, 1);
- g_object_unref(webView);
-}
-
-static void test_webkit_web_back_forward_list_order(void)
-{
- WebKitWebView* webView;
- WebKitWebBackForwardList* webBackForwardList;
- WebKitWebHistoryItem* item1;
- WebKitWebHistoryItem* item2;
- WebKitWebHistoryItem* item3;
- WebKitWebHistoryItem* item4;
- WebKitWebHistoryItem* currentItem;
- GList* backList = NULL;
- GList* forwardList = NULL;
- g_test_bug("22694");
-
- webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(webView);
-
- webkit_web_view_set_maintains_back_forward_list(webView, TRUE);
- webBackForwardList = webkit_web_view_get_back_forward_list(webView);
- g_assert(webBackForwardList);
-
- // Check that there is no item.
- g_assert(!webkit_web_back_forward_list_get_current_item(webBackForwardList));
- g_assert_cmpint(webkit_web_back_forward_list_get_forward_length(webBackForwardList), ==, 0);
- g_assert_cmpint(webkit_web_back_forward_list_get_back_length(webBackForwardList), ==, 0);
- g_assert(!webkit_web_view_can_go_forward(webView));
- g_assert(!webkit_web_view_can_go_back(webView));
-
- // Add a new items
- item1 = webkit_web_history_item_new_with_data("http://example.com/1/", "Site 1");
- webkit_web_back_forward_list_add_item(webBackForwardList, item1);
- g_object_unref(item1);
- g_assert(webkit_web_back_forward_list_contains_item(webBackForwardList, item1));
-
- item2 = webkit_web_history_item_new_with_data("http://example.com/2/", "Site 2");
- webkit_web_back_forward_list_add_item(webBackForwardList, item2);
- g_object_unref(item2);
- g_assert(webkit_web_back_forward_list_contains_item(webBackForwardList, item2));
-
- item3 = webkit_web_history_item_new_with_data("http://example.com/3/", "Site 3");
- webkit_web_back_forward_list_add_item(webBackForwardList, item3);
- g_object_unref(item3);
- g_assert(webkit_web_back_forward_list_contains_item(webBackForwardList, item3));
-
- item4 = webkit_web_history_item_new_with_data("http://example.com/4/", "Site 4");
- webkit_web_back_forward_list_add_item(webBackForwardList, item4);
- g_object_unref(item4);
- g_assert(webkit_web_back_forward_list_contains_item(webBackForwardList, item4));
-
- // check the back list order
- backList = webkit_web_back_forward_list_get_back_list_with_limit(webBackForwardList, 5);
- g_assert(backList);
-
- currentItem = WEBKIT_WEB_HISTORY_ITEM(backList->data);
- g_assert_cmpstr(webkit_web_history_item_get_uri(currentItem), ==, "http://example.com/3/");
- g_assert_cmpstr(webkit_web_history_item_get_title(currentItem), ==, "Site 3");
- backList = backList->next;
-
- currentItem = WEBKIT_WEB_HISTORY_ITEM(backList->data);
- g_assert_cmpstr(webkit_web_history_item_get_uri(currentItem), ==, "http://example.com/2/");
- g_assert_cmpstr(webkit_web_history_item_get_title(currentItem), ==, "Site 2");
- backList = backList->next;
-
- currentItem = WEBKIT_WEB_HISTORY_ITEM(backList->data);
- g_assert_cmpstr(webkit_web_history_item_get_uri(currentItem), ==, "http://example.com/1/");
- g_assert_cmpstr(webkit_web_history_item_get_title(currentItem), ==, "Site 1");
- g_list_free(backList);
-
- // check the forward list order
- g_assert(webkit_web_view_go_to_back_forward_item(webView, item1));
- forwardList = webkit_web_back_forward_list_get_forward_list_with_limit(webBackForwardList,5);
- g_assert(forwardList);
-
- currentItem = WEBKIT_WEB_HISTORY_ITEM(forwardList->data);
- g_assert_cmpstr(webkit_web_history_item_get_uri(currentItem), ==, "http://example.com/4/");
- g_assert_cmpstr(webkit_web_history_item_get_title(currentItem), ==, "Site 4");
- forwardList = forwardList->next;
-
- currentItem = WEBKIT_WEB_HISTORY_ITEM(forwardList->data);
- g_assert_cmpstr(webkit_web_history_item_get_uri(currentItem), ==, "http://example.com/3/");
- g_assert_cmpstr(webkit_web_history_item_get_title(currentItem), ==, "Site 3");
- forwardList = forwardList->next;
-
- currentItem = WEBKIT_WEB_HISTORY_ITEM(forwardList->data);
- g_assert_cmpstr(webkit_web_history_item_get_uri(currentItem), ==, "http://example.com/2/");
- g_assert_cmpstr(webkit_web_history_item_get_title(currentItem), ==, "Site 2");
-
- g_list_free(forwardList);
- g_object_unref(webView);
-}
-
-static void test_webkit_web_back_forward_list_add_item(void)
-{
- WebKitWebView* webView;
- WebKitWebBackForwardList* webBackForwardList;
- WebKitWebHistoryItem* addItem1;
- WebKitWebHistoryItem* addItem2;
- WebKitWebHistoryItem* backItem;
- WebKitWebHistoryItem* currentItem;
- g_test_bug("22988");
-
- webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(webView);
-
- webkit_web_view_set_maintains_back_forward_list(webView, TRUE);
- webBackForwardList = webkit_web_view_get_back_forward_list(webView);
- g_assert(webBackForwardList);
-
- // Check that there is no item.
- g_assert(!webkit_web_back_forward_list_get_current_item(webBackForwardList));
- g_assert_cmpint(webkit_web_back_forward_list_get_forward_length(webBackForwardList), ==, 0);
- g_assert_cmpint(webkit_web_back_forward_list_get_back_length(webBackForwardList), ==, 0);
- g_assert(!webkit_web_view_can_go_forward(webView));
- g_assert(!webkit_web_view_can_go_back(webView));
-
- // Add a new item
- addItem1 = webkit_web_history_item_new_with_data("http://example.com/", "Added site");
- webkit_web_back_forward_list_add_item(webBackForwardList, addItem1);
- g_object_unref(addItem1);
- g_assert(webkit_web_back_forward_list_contains_item(webBackForwardList, addItem1));
-
- // Check that the added item is the current item.
- currentItem = webkit_web_back_forward_list_get_current_item(webBackForwardList);
- g_assert(currentItem);
- g_assert_cmpint(webkit_web_back_forward_list_get_forward_length(webBackForwardList), ==, 0);
- g_assert_cmpint(webkit_web_back_forward_list_get_back_length(webBackForwardList), ==, 0);
- g_assert(!webkit_web_view_can_go_forward(webView));
- g_assert(!webkit_web_view_can_go_back(webView));
- g_assert_cmpstr(webkit_web_history_item_get_uri(currentItem), ==, "http://example.com/");
- g_assert_cmpstr(webkit_web_history_item_get_title(currentItem), ==, "Added site");
-
- // Add another item.
- addItem2 = webkit_web_history_item_new_with_data("http://example.com/2/", "Added site 2");
- webkit_web_back_forward_list_add_item(webBackForwardList, addItem2);
- g_object_unref(addItem2);
- g_assert(webkit_web_back_forward_list_contains_item(webBackForwardList, addItem2));
-
- // Check that the added item is new current item.
- currentItem = webkit_web_back_forward_list_get_current_item(webBackForwardList);
- g_assert(currentItem);
- g_assert_cmpint(webkit_web_back_forward_list_get_forward_length(webBackForwardList), ==, 0);
- g_assert_cmpint(webkit_web_back_forward_list_get_back_length(webBackForwardList), ==, 1);
- g_assert(!webkit_web_view_can_go_forward(webView));
- g_assert(webkit_web_view_can_go_back(webView));
- g_assert_cmpstr(webkit_web_history_item_get_uri(currentItem), ==, "http://example.com/2/");
- g_assert_cmpstr(webkit_web_history_item_get_title(currentItem), ==, "Added site 2");
-
- backItem = webkit_web_back_forward_list_get_back_item(webBackForwardList);
- g_assert(backItem);
- g_assert_cmpstr(webkit_web_history_item_get_uri(backItem), ==, "http://example.com/");
- g_assert_cmpstr(webkit_web_history_item_get_title(backItem), ==, "Added site");
-
- // Go to the first added item.
- g_assert(webkit_web_view_go_to_back_forward_item(webView, addItem1));
- g_assert_cmpint(webkit_web_back_forward_list_get_forward_length(webBackForwardList), ==, 1);
- g_assert_cmpint(webkit_web_back_forward_list_get_back_length(webBackForwardList), ==, 0);
- g_assert(webkit_web_view_can_go_forward(webView));
- g_assert(!webkit_web_view_can_go_back(webView));
-
- g_object_unref(webView);
-}
-
-static void test_webkit_web_back_forward_list_clear(void)
-{
- WebKitWebView* webView;
- WebKitWebBackForwardList* webBackForwardList;
- WebKitWebHistoryItem* addItem;
- g_test_bug("36173");
-
- webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(webView);
-
- webBackForwardList = webkit_web_view_get_back_forward_list(webView);
- g_assert(webBackForwardList);
-
- // Check that there is no item.
- g_assert_cmpint(webkit_web_back_forward_list_get_forward_length(webBackForwardList), ==, 0);
- g_assert_cmpint(webkit_web_back_forward_list_get_back_length(webBackForwardList), ==, 0);
- g_assert(!webkit_web_back_forward_list_get_current_item(webBackForwardList));
- g_assert(!webkit_web_view_can_go_forward(webView));
- g_assert(!webkit_web_view_can_go_back(webView));
-
- // Check that clearing the empty list does not modify counters
- webkit_web_back_forward_list_clear(webBackForwardList);
- g_assert_cmpint(webkit_web_back_forward_list_get_forward_length(webBackForwardList), ==, 0);
- g_assert_cmpint(webkit_web_back_forward_list_get_back_length(webBackForwardList), ==, 0);
- g_assert(!webkit_web_back_forward_list_get_current_item(webBackForwardList));
- g_assert(!webkit_web_view_can_go_forward(webView));
- g_assert(!webkit_web_view_can_go_back(webView));
-
- // Add a new item
- addItem = webkit_web_history_item_new_with_data("http://example.com/", "Added site");
- webkit_web_back_forward_list_add_item(webBackForwardList, addItem);
- g_object_unref(addItem);
- g_assert(webkit_web_back_forward_list_contains_item(webBackForwardList, addItem));
-
- // Check that after clearing the list the added item is no longer in the list
- webkit_web_back_forward_list_clear(webBackForwardList);
- g_assert(!webkit_web_back_forward_list_contains_item(webBackForwardList, addItem));
-
- // Check that after clearing it, the list is empty
- g_assert_cmpint(webkit_web_back_forward_list_get_forward_length(webBackForwardList), ==, 0);
- g_assert_cmpint(webkit_web_back_forward_list_get_back_length(webBackForwardList), ==, 0);
- g_assert(!webkit_web_back_forward_list_get_current_item(webBackForwardList));
- g_assert(!webkit_web_view_can_go_forward(webView));
- g_assert(!webkit_web_view_can_go_back(webView));
-
- g_object_unref(webView);
-}
-
-int main(int argc, char** argv)
-{
- gtk_test_init(&argc, &argv, NULL);
-
- g_test_bug_base("https://bugs.webkit.org/");
- g_test_add_func("/webkit/webbackforwardlist/add_item", test_webkit_web_back_forward_list_add_item);
- g_test_add_func("/webkit/webbackforwardlist/list_order", test_webkit_web_back_forward_list_order);
- g_test_add_func("/webkit/webhistoryitem/lifetime", test_webkit_web_history_item_lifetime);
- g_test_add_func("/webkit/webbackforwardlist/clear", test_webkit_web_back_forward_list_clear);
- return g_test_run ();
-}
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebdatasource.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebdatasource.c
deleted file mode 100644
index 056625744..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebdatasource.c
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright (C) 2009 Jan Michael Alonzo
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include <glib.h>
-#include <gtk/gtk.h>
-#include <webkit/webkit.h>
-
-static const gshort defaultTimeout = 10;
-guint waitTimer;
-gboolean shouldWait;
-
-typedef struct {
- WebKitWebView* webView;
- WebKitWebFrame* mainFrame;
-} WebDataSourceFixture;
-
-static void test_webkit_web_data_source_get_initial_request()
-{
- WebKitWebView* view;
- WebKitWebFrame* frame;
- WebKitWebDataSource* dataSource;
- WebKitNetworkRequest* initialRequest;
-
- view = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(view);
- frame = webkit_web_view_get_main_frame(view);
-
- WebKitNetworkRequest* request = webkit_network_request_new("http://www.google.com");
- webkit_web_frame_load_request(frame, request);
- g_object_unref(request);
-
- dataSource = webkit_web_frame_get_provisional_data_source(frame);
- g_assert(dataSource);
- initialRequest = webkit_web_data_source_get_initial_request(dataSource);
- g_assert_cmpstr(webkit_network_request_get_uri(initialRequest), ==, "http://www.google.com/");
-
- g_object_unref(view);
-}
-
-static void notify_load_status_unreachable_cb(WebKitWebView* view, GParamSpec* pspec, GMainLoop* loop)
-{
- WebKitLoadStatus status = webkit_web_view_get_load_status (view);
- WebKitWebFrame* frame = webkit_web_view_get_main_frame(view);
-
- g_assert(status != WEBKIT_LOAD_FINISHED);
-
- if (status != WEBKIT_LOAD_FAILED)
- return;
-
- WebKitWebDataSource* datasource = webkit_web_frame_get_data_source(frame);
-
- g_assert_cmpstr("http://this.host.does.not.exist/doireallyexist.html", ==,
- webkit_web_data_source_get_unreachable_uri(datasource));
-
- g_main_loop_quit(loop);
-}
-
-static void notify_load_status_cb(WebKitWebView* view, GParamSpec* pspec, GMainLoop* loop)
-{
- WebKitLoadStatus status = webkit_web_view_get_load_status (view);
- WebKitWebFrame* frame = webkit_web_view_get_main_frame(view);
- WebKitWebDataSource* dataSource = webkit_web_frame_get_data_source(frame);
-
- if (status == WEBKIT_LOAD_COMMITTED) {
- g_assert(webkit_web_data_source_is_loading(dataSource));
- return;
- }
- else if (status != WEBKIT_LOAD_FINISHED)
- return;
-
- /* Test get_request */
- g_test_message("Testing webkit_web_data_source_get_request");
- WebKitNetworkRequest* request = webkit_web_data_source_get_request(dataSource);
- g_assert_cmpstr(webkit_network_request_get_uri(request), ==, "http://www.webkit.org/");
-
- /* Test get_main_resource */
- g_test_message("Testing webkit_web_data_source_get_main_resource");
- WebKitWebResource* resource = webkit_web_data_source_get_main_resource(dataSource);
- g_assert_cmpstr("text/html", ==, webkit_web_resource_get_mime_type(resource));
- g_assert_cmpstr("http://www.webkit.org/", ==, webkit_web_resource_get_uri(resource));
-
- /* Test get_data. We just test if data has certain size for the mean time */
- g_test_message("Testing webkit_web_data_source_get_data has certain size");
- GString* data = webkit_web_data_source_get_data(dataSource);
- g_assert(data->len > 100);
-
- /* FIXME: Add test for get_encoding */
-
- g_main_loop_quit(loop);
-}
-
-static gboolean wait_timer_fired(GMainLoop* loop)
-{
- waitTimer = 0;
- g_main_loop_quit(loop);
-
- return FALSE;
-}
-
-static void test_webkit_web_data_source()
-{
- WebKitWebView* view;
- GMainLoop* loop;
-
- view = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(view);
- loop = g_main_loop_new(NULL, TRUE);
- g_signal_connect(view, "notify::load-status", G_CALLBACK(notify_load_status_cb), loop);
- webkit_web_view_load_uri(view, "http://www.webkit.org");
-
- waitTimer = g_timeout_add_seconds(defaultTimeout, (GSourceFunc)wait_timer_fired, loop);
-
- g_main_loop_run(loop);
-
- if (waitTimer)
- g_source_remove(waitTimer);
-
- waitTimer = 0;
-
- g_main_loop_unref(loop);
- g_object_unref(view);
-}
-
-static void notify_load_status_lifetime_cb(WebKitWebView* view, GParamSpec* pspec, GMainLoop* loop)
-{
- WebKitLoadStatus status = webkit_web_view_get_load_status (view);
- WebKitWebFrame* frame = webkit_web_view_get_main_frame(view);
- WebKitWebDataSource* dataSource = webkit_web_frame_get_data_source(frame);
-
- if (status == WEBKIT_LOAD_COMMITTED) {
- g_assert(webkit_web_data_source_is_loading(dataSource));
- return;
- } else if (status != WEBKIT_LOAD_FINISHED)
- return;
-
- g_main_loop_quit(loop);
-}
-
-static void test_webkit_web_data_source_lifetime()
-{
- WebKitWebView* view;
- GMainLoop* loop;
-
- view = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(view);
- loop = g_main_loop_new(NULL, TRUE);
- g_signal_connect(view, "notify::load-status", G_CALLBACK(notify_load_status_lifetime_cb), loop);
- webkit_web_view_load_uri(view, "http://www.webkit.org");
-
- waitTimer = g_timeout_add_seconds(defaultTimeout, (GSourceFunc)wait_timer_fired, loop);
-
- g_main_loop_run(loop);
-
- WebKitWebDataSource* dataSource = webkit_web_frame_get_data_source(webkit_web_view_get_main_frame(view));
- GList* subResources = webkit_web_data_source_get_subresources(dataSource);
- gint numberOfResources = g_list_length(subResources);
- g_list_free(subResources);
-
- g_assert_cmpint(webkit_web_view_get_load_status(view), ==, WEBKIT_LOAD_FINISHED);
-
- webkit_web_view_load_uri(view, "http://gnome.org");
-
- g_assert_cmpint(webkit_web_view_get_load_status(view), ==, WEBKIT_LOAD_PROVISIONAL);
-
- webkit_web_view_stop_loading(view);
-
- g_assert_cmpint(webkit_web_view_get_load_status(view), ==, WEBKIT_LOAD_FAILED);
-
- subResources = webkit_web_data_source_get_subresources(dataSource);
- g_assert_cmpint(numberOfResources, ==, g_list_length(subResources));
- g_list_free(subResources);
-
- if (waitTimer)
- g_source_remove(waitTimer);
-
- waitTimer = 0;
-
- g_main_loop_unref(loop);
- g_object_unref(view);
-}
-
-static void test_webkit_web_data_source_unreachable_uri()
-{
- /* FIXME: this test fails currently. */
- return;
-
- WebKitWebView* view;
- GMainLoop* loop;
-
- view = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(view);
- loop = g_main_loop_new(NULL, TRUE);
- g_signal_connect(view, "notify::load-status", G_CALLBACK(notify_load_status_unreachable_cb), loop);
- webkit_web_view_load_uri(view, "http://this.host.does.not.exist/doireallyexist.html");
-
- waitTimer = g_timeout_add_seconds(defaultTimeout, (GSourceFunc)wait_timer_fired, loop);
-
- g_main_loop_run(loop);
-
- if (waitTimer)
- g_source_remove(waitTimer);
-
- waitTimer = 0;
-
- g_main_loop_unref(loop);
- g_object_unref(view);
-}
-
-int main(int argc, char** argv)
-{
- gtk_test_init(&argc, &argv, NULL);
-
- g_test_bug_base("https://bugs.webkit.org/");
- g_test_bug("24758");
- g_test_add_func("/webkit/webdatasource/get_initial_request",
- test_webkit_web_data_source_get_initial_request);
- g_test_add_func("/webkit/webdatasource/api",
- test_webkit_web_data_source);
- g_test_add_func("/webkit/webdatasource/unreachable_uri",
- test_webkit_web_data_source_unreachable_uri);
- g_test_add_func("/webkit/webdatasource/lifetime",
- test_webkit_web_data_source_lifetime);
-
- return g_test_run ();
-}
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebframe.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebframe.c
deleted file mode 100644
index 1131873d4..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebframe.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright (C) 2008 Holger Hans Peter Freyther
- * Copyright (C) 2009 Collabora Ltd.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include <errno.h>
-#include <unistd.h>
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <gtk/gtk.h>
-#include <webkit/webkit.h>
-
-static int numberOfFramesCreated = 0;
-
-static void createFrameSignalTestFrameCreatedCallback(WebKitWebView* webView, WebKitWebFrame* frame, gpointer data)
-{
- numberOfFramesCreated++;
-}
-
-static gboolean createFrameSignalTestTimeout(gpointer data)
-{
- g_assert_cmpint(numberOfFramesCreated, ==, 2);
- g_main_loop_quit((GMainLoop*) data);
- return FALSE;
-}
-
-static void test_webkit_web_frame_created_signal(void)
-{
- GtkWidget* webView;
- GtkWidget* window;
- GMainLoop* loop = g_main_loop_new(NULL, TRUE);
-
- window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-
- webView = webkit_web_view_new();
- g_signal_connect(webView, "frame-created", G_CALLBACK(createFrameSignalTestFrameCreatedCallback), loop);
-
- // We want to ensure that exactly two create-frame signals are
- // fired and no more, so we set a timeout here. There does not appear
- // to be a simple way via the API to figure out when all frames have
- // loaded.
- g_timeout_add(500, createFrameSignalTestTimeout, loop);
-
- gtk_container_add(GTK_CONTAINER(window), webView);
- gtk_widget_show(window);
- gtk_widget_show(webView);
-
- webkit_web_view_load_string(WEBKIT_WEB_VIEW(webView),
- "<html><body>Frames!"
- "<iframe></iframe>"
- "<iframe></iframe>"
- "</body></html>",
- "text/html", "utf-8", "file://");
- g_main_loop_run(loop);
-}
-
-static void test_webkit_web_frame_create_destroy(void)
-{
- GtkWidget *webView;
- GtkWidget *window;
-
- g_test_bug("21837");
- webView = webkit_web_view_new();
- g_object_ref_sink(webView);
- g_assert_cmpint(G_OBJECT(webView)->ref_count, ==, 1);
- // This crashed with the original version
- g_object_unref(webView);
-
- g_test_bug("25042");
- window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- webView = webkit_web_view_new();
- gtk_container_add(GTK_CONTAINER(window), webView);
- gtk_widget_show(window);
- gtk_widget_show(webView);
- gtk_widget_destroy(webView);
-}
-
-static void test_webkit_web_frame_lifetime(void)
-{
- WebKitWebView* webView;
- WebKitWebFrame* webFrame;
- g_test_bug("21837");
-
- webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(webView);
- g_assert_cmpint(G_OBJECT(webView)->ref_count, ==, 1);
- webFrame = webkit_web_view_get_main_frame(webView);
- g_assert_cmpint(G_OBJECT(webFrame)->ref_count, ==, 1);
-
- // Add dummy reference on the WebKitWebFrame to keep it alive
- g_object_ref(webFrame);
- g_assert_cmpint(G_OBJECT(webFrame)->ref_count, ==, 2);
-
- // This crashed with the original version
- g_object_unref(webView);
-
- // Make sure that the frame got deleted as well. We did this
- // by adding an extra ref on the WebKitWebFrame and we should
- // be the one holding the last reference.
- g_assert_cmpint(G_OBJECT(webFrame)->ref_count, ==, 1);
- g_object_unref(webFrame);
-}
-
-static gboolean print_requested_cb(WebKitWebView* webView, WebKitWebFrame* webFrame, GMainLoop* loop)
-{
- g_object_set_data(G_OBJECT(webView), "signal-handled", GINT_TO_POINTER(TRUE));
- g_main_loop_quit(loop);
- return TRUE;
-}
-
-static void print_timeout(GMainLoop* loop)
-{
- if (g_main_loop_is_running(loop))
- g_main_loop_quit(loop);
-}
-
-static void test_webkit_web_frame_printing(void)
-{
- WebKitWebView* webView;
-
- webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(webView);
- g_assert_cmpint(G_OBJECT(webView)->ref_count, ==, 1);
-
- webkit_web_view_load_string(webView,
- "<html><body><h1>WebKitGTK+!</h1></body></html>",
- "text/html",
- "utf-8",
- "file://");
-
- GMainLoop* loop = g_main_loop_new(NULL, TRUE);
-
- // Does javascript print() work correctly?
- g_signal_connect(webView, "print-requested",
- G_CALLBACK(print_requested_cb),
- loop);
-
- g_object_set_data(G_OBJECT(webView), "signal-handled", GINT_TO_POINTER(FALSE));
- webkit_web_view_execute_script (webView, "print();");
-
- // Give javascriptcore some time to process the print request, but
- // prepare a timeout to avoid it running forever in case the signal is
- // never emitted.
- g_timeout_add(1000, (GSourceFunc)print_timeout, loop);
- g_main_loop_run(loop);
-
- g_assert_cmpint(GPOINTER_TO_INT(g_object_get_data(G_OBJECT(webView), "signal-handled")), ==, TRUE);
-
- // Does printing directly to a file?
- GError *error = NULL;
- gchar* temporaryFilename = NULL;
- gint fd = g_file_open_tmp ("webkit-testwebframe-XXXXXX", &temporaryFilename, &error);
- close(fd);
-
- if (error) {
- g_critical("Failed to open a temporary file for writing: %s.", error->message);
- g_error_free(error);
- goto cleanup;
- }
-
- // We delete the file, so that we can easily figure out that the
- // file got printed;
- if (g_unlink(temporaryFilename) == -1) {
- g_warning("Failed to delete the temporary file: %s.\nThis may cause the test to be bogus.", g_strerror(errno));
- }
-
- WebKitWebFrame* webFrame = webkit_web_view_get_main_frame(webView);
- GtkPrintOperation* operation = gtk_print_operation_new();
- GtkPrintOperationAction action = GTK_PRINT_OPERATION_ACTION_EXPORT;
- GtkPrintOperationResult result;
-
- gtk_print_operation_set_export_filename(operation, temporaryFilename);
- result = webkit_web_frame_print_full (webFrame, operation, action, NULL);
-
- g_assert_cmpint(result, ==, GTK_PRINT_OPERATION_RESULT_APPLY);
- g_assert_cmpint(g_file_test(temporaryFilename, G_FILE_TEST_IS_REGULAR), ==, TRUE);
-
- g_unlink(temporaryFilename);
- g_object_unref(operation);
-cleanup:
- g_object_unref(webView);
- g_free(temporaryFilename);
-}
-
-static void test_webkit_web_frame_response()
-{
- WebKitWebFrame* frame = g_object_new(WEBKIT_TYPE_WEB_FRAME, NULL);
- WebKitNetworkResponse* response = webkit_web_frame_get_network_response(frame);
- g_assert(!response);
- g_object_unref(frame);
-}
-
-int main(int argc, char** argv)
-{
- gtk_test_init(&argc, &argv, NULL);
-
- g_test_bug_base("https://bugs.webkit.org/");
- g_test_add_func("/webkit/webview/create_destroy", test_webkit_web_frame_create_destroy);
- g_test_add_func("/webkit/webview/frame-created_signal", test_webkit_web_frame_created_signal);
- g_test_add_func("/webkit/webframe/lifetime", test_webkit_web_frame_lifetime);
- g_test_add_func("/webkit/webview/printing", test_webkit_web_frame_printing);
- g_test_add_func("/webkit/webview/response", test_webkit_web_frame_response);
- return g_test_run ();
-}
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebhistoryitem.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebhistoryitem.c
deleted file mode 100644
index 82e191c20..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebhistoryitem.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2009 Jan Michael Alonzo
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include <glib.h>
-#include <gtk/gtk.h>
-#include <webkit/webkit.h>
-
-typedef struct {
- WebKitWebHistoryItem* item;
-} WebHistoryItemFixture;
-
-static void web_history_item_fixture_setup(WebHistoryItemFixture* fixture,
- gconstpointer data)
-{
- fixture->item = webkit_web_history_item_new_with_data("http://example.com/", "Example1");
- g_assert_cmpint(G_OBJECT(fixture->item)->ref_count, == , 1);
- g_assert(fixture->item != NULL);
-}
-
-static void web_history_item_fixture_teardown(WebHistoryItemFixture* fixture,
- gconstpointer data)
-{
- g_assert(fixture->item != NULL);
- g_assert_cmpint(G_OBJECT(fixture->item)->ref_count, ==, 1);
-}
-
-static void test_webkit_web_history_item_get_data(WebHistoryItemFixture* fixture,
- gconstpointer data)
-{
- g_assert_cmpstr(webkit_web_history_item_get_title(fixture->item), ==, "Example1");
- g_assert_cmpstr(webkit_web_history_item_get_uri(fixture->item), ==, "http://example.com/");
-}
-
-static void test_webkit_web_history_item_alternate_title(WebHistoryItemFixture* fixture,
- gconstpointer data)
-{
- webkit_web_history_item_set_alternate_title(fixture->item, "Alternate title");
- g_assert_cmpstr(webkit_web_history_item_get_alternate_title(fixture->item), ==, "Alternate title");
-}
-
-int main(int argc, char** argv)
-{
- gtk_test_init(&argc, &argv, NULL);
-
- g_test_bug_base("https://bugs.webkit.org/");
- g_test_add("/webkit/webhistoryitem/get_data",
- WebHistoryItemFixture, 0, web_history_item_fixture_setup,
- test_webkit_web_history_item_get_data, web_history_item_fixture_teardown);
- g_test_add("/webkit/webhistoryitem/alternate_title",
- WebHistoryItemFixture, 0, web_history_item_fixture_setup,
- test_webkit_web_history_item_alternate_title, web_history_item_fixture_teardown);
- return g_test_run ();
-}
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebinspector.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebinspector.c
deleted file mode 100644
index a74382ff3..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebinspector.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2012 Gustavo Noronha Silva <gns@gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include "test_utils.h"
-
-#include <string.h>
-#include <glib.h>
-#include <gtk/gtk.h>
-#include <webkit/webkit.h>
-
-GMainLoop *loop;
-GtkWidget *window;
-
-static gboolean quitLoop(gpointer data)
-{
- g_main_loop_quit(loop);
- return TRUE;
-}
-
-/* Ignore simple translation-related messages and upgrade other
- * messages to warnings.
- */
-static gboolean consoleMessageCallback(WebKitWebView* webView, const char* message, unsigned int line, const char* sourceId)
-{
- if (strstr(message, "Localized string") || strstr(message, "Protocol Error: the message is for non-existing domain 'Profiler'") ||
- strstr(message, "Didn't find a TreeElement for a representedObject"))
- return TRUE;
-
- g_warning("Console: %s @%d: %s\n", sourceId, line, message);
- return TRUE;
-}
-
-static WebKitWebView* inspectElementCallback(WebKitWebInspector *inspector, WebKitWebView *inspectedWebView, int *timesElementInspected)
-{
- *timesElementInspected = *timesElementInspected + 1;
-
- window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-
- GtkWidget *newWebView = webkit_web_view_new();
- gtk_container_add(GTK_CONTAINER(window), newWebView);
-
- g_signal_connect(newWebView, "console-message",
- G_CALLBACK(consoleMessageCallback), NULL);
-
- return WEBKIT_WEB_VIEW(newWebView);
-}
-
-static gboolean closeInspector(WebKitWebInspector *inspector, int *timesClosed)
-{
- *timesClosed = *timesClosed + 1;
-
- gtk_widget_destroy(window);
- return TRUE;
-}
-
-static gboolean showInspector(WebKitWebInspector *inspector, gpointer data)
-{
- g_idle_add(quitLoop, NULL);
- return TRUE;
-}
-
-static void loadFinished(WebKitWebView *webView, WebKitWebFrame *frame, gboolean *isLoadFinished)
-{
- *isLoadFinished = TRUE;
- if (g_main_loop_is_running(loop))
- g_main_loop_quit(loop);
-}
-
-static void test_webkit_web_inspector_close_and_inspect()
-{
- WebKitWebView *webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- loop = g_main_loop_new(NULL, TRUE);
-
- gboolean isLoadFinished = FALSE;
- g_signal_connect(webView, "load-finished", G_CALLBACK(loadFinished), &isLoadFinished);
- webkit_web_view_load_string(webView,
- "<html><body><p>woohoo</p></body></html>",
- "text/html", "UTF-8", "file://");
- if (!isLoadFinished)
- g_main_loop_run(loop);
-
- g_object_set(webkit_web_view_get_settings(webView), "enable-developer-extras", TRUE, NULL);
- WebKitWebInspector *inspector = webkit_web_view_get_inspector(webView);
-
- int timesElementInspected = 0;
- int timesClosed = 0;
- g_object_connect(inspector,
- "signal::inspect-web-view", G_CALLBACK(inspectElementCallback), &timesElementInspected,
- "signal::show-window", G_CALLBACK(showInspector), NULL,
- "signal::close-window", G_CALLBACK(closeInspector), &timesClosed,
- NULL);
-
- webkit_web_inspector_inspect_coordinates(inspector, 0.0, 0.0);
- g_assert_cmpint(timesElementInspected, ==, 1);
-
- g_main_loop_run(loop);
-
- webkit_web_inspector_close(inspector);
- g_assert_cmpint(timesClosed, ==, 1);
-
- webkit_web_inspector_inspect_coordinates(inspector, 0.0, 0.0);
- g_assert_cmpint(timesElementInspected, ==, 2);
-
- g_main_loop_run(loop);
-
- gtk_widget_destroy(GTK_WIDGET(webView));
- g_assert_cmpint(timesClosed, ==, 2);
-
- g_main_loop_unref(loop);
-}
-
-static void test_webkit_web_inspector_destroy_inspected_web_view()
-{
- WebKitWebView *webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- loop = g_main_loop_new(NULL, TRUE);
-
- gboolean isLoadFinished = FALSE;
- g_signal_connect(webView, "load-finished", G_CALLBACK(loadFinished), &isLoadFinished);
- webkit_web_view_load_string(webView,
- "<html><body><p>woohoo</p></body></html>",
- "text/html", "UTF-8", "file://");
- if (!isLoadFinished)
- g_main_loop_run(loop);
-
- g_object_set(webkit_web_view_get_settings(webView), "enable-developer-extras", TRUE, NULL);
- WebKitWebInspector *inspector = webkit_web_view_get_inspector(webView);
-
- int timesElementInspected = 0;
- int timesClosed = 0;
- g_object_connect(inspector,
- "signal::inspect-web-view", G_CALLBACK(inspectElementCallback), &timesElementInspected,
- "signal::show-window", G_CALLBACK(showInspector), NULL,
- "signal::close-window", G_CALLBACK(closeInspector), &timesClosed,
- NULL);
-
- webkit_web_inspector_inspect_coordinates(inspector, 0.0, 0.0);
- g_assert_cmpint(timesElementInspected, ==, 1);
-
- g_main_loop_run(loop);
-
- gtk_widget_destroy(GTK_WIDGET(webView));
- g_assert_cmpint(timesClosed, ==, 1);
-
- g_main_loop_unref(loop);
-}
-
-int main(int argc, char** argv)
-{
- gtk_test_init(&argc, &argv, NULL);
-
- g_test_bug_base("https://bugs.webkit.org/");
- g_test_add_func("/webkit/webinspector/destroy-inspected-web-view", test_webkit_web_inspector_destroy_inspected_web_view);
- g_test_add_func("/webkit/webinspector/close-and-inspect", test_webkit_web_inspector_close_and_inspect);
-
- return g_test_run();
-}
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebplugindatabase.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebplugindatabase.c
deleted file mode 100644
index 652811b13..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebplugindatabase.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2010 Igalia S.L.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include <errno.h>
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <gtk/gtk.h>
-#include <webkit/webkit.h>
-
-/* This function is not public, so we need an extern declaration */
-extern void webkit_web_settings_add_extra_plugin_directory(WebKitWebView* view, const gchar* directory);
-
-static void test_webkit_web_plugin_database_get_plugins()
-{
- WebKitWebView* view = WEBKIT_WEB_VIEW(webkit_web_view_new());
- WebKitWebPluginDatabase* database;
- GSList* pluginList, *p;
- gboolean found = FALSE;
- gboolean enabled = FALSE;
-
- webkit_web_settings_add_extra_plugin_directory(view, TEST_PLUGIN_DIR);
- g_object_ref_sink(G_OBJECT(view));
-
- database = webkit_get_web_plugin_database();
- pluginList = webkit_web_plugin_database_get_plugins(database);
- for (p = pluginList; p; p = p->next) {
- WebKitWebPlugin* plugin = (WebKitWebPlugin*)p->data;
- if (!g_strcmp0(webkit_web_plugin_get_name(plugin), "WebKit Test PlugIn") &&
- !g_strcmp0(webkit_web_plugin_get_description(plugin), "Simple Netscape® plug-in that handles test content for WebKit")) {
- found = TRUE;
- enabled = webkit_web_plugin_get_enabled(plugin);
- webkit_web_plugin_set_enabled(plugin, FALSE);
- }
- }
- webkit_web_plugin_database_plugins_list_free(pluginList);
- g_assert(found);
- g_assert(enabled);
-
- webkit_web_plugin_database_refresh(database);
- pluginList = webkit_web_plugin_database_get_plugins(database);
-
- for (p = pluginList; p; p = p->next) {
- WebKitWebPlugin* plugin = (WebKitWebPlugin*)p->data;
- if (!g_strcmp0(webkit_web_plugin_get_name(plugin), "WebKit Test PlugIn") &&
- !g_strcmp0(webkit_web_plugin_get_description(plugin), "Simple Netscape® plug-in that handles test content for WebKit"))
- enabled = webkit_web_plugin_get_enabled(plugin);
- }
- webkit_web_plugin_database_plugins_list_free(pluginList);
- g_assert(!enabled);
-
- g_object_unref(view);
-}
-
-int main(int argc, char** argv)
-{
- gtk_test_init(&argc, &argv, NULL);
-
- g_test_bug_base("https://bugs.webkit.org/");
- g_test_add_func("/webkit/webplugindatabase/getplugins", test_webkit_web_plugin_database_get_plugins);
- return g_test_run ();
-}
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebresource.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebresource.c
deleted file mode 100644
index 35d09476d..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebresource.c
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * Copyright (C) 2009 Jan Michael Alonzo
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include <glib.h>
-#include <gtk/gtk.h>
-#include <libsoup/soup.h>
-#include <string.h>
-#include <webkit/webkit.h>
-
-#define INDEX_HTML "<html></html>"
-#define MAIN_HTML "<html><head><script language=\"javascript\" src=\"/javascript.js\"></script></head><body><h1>hah</h1></html>"
-#define JAVASCRIPT "function blah () { var a = 1; }"
-
-GMainLoop* loop;
-SoupSession *session;
-char *base_uri;
-WebKitWebResource* main_resource;
-WebKitWebResource* sub_resource;
-
-typedef struct {
- WebKitWebResource* webResource;
- WebKitWebView* webView;
-} WebResourceFixture;
-
-/* For real request testing */
-static void
-server_callback (SoupServer *server, SoupMessage *msg,
- const char *path, GHashTable *query,
- SoupClientContext *context, gpointer data)
-{
- if (msg->method != SOUP_METHOD_GET) {
- soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
- return;
- }
-
- soup_message_set_status (msg, SOUP_STATUS_OK);
-
- /* Redirect */
- if (g_str_equal (path, "/")) {
- soup_message_set_status (msg, SOUP_STATUS_MOVED_PERMANENTLY);
-
- soup_message_headers_append (msg->response_headers,
- "Location", "/index.html");
- } else if (g_str_equal (path, "/index.html")) {
- soup_message_body_append (msg->response_body,
- SOUP_MEMORY_COPY,
- INDEX_HTML,
- strlen (INDEX_HTML));
- } else if (g_str_equal (path, "/main.html")) {
- soup_message_body_append (msg->response_body,
- SOUP_MEMORY_COPY,
- MAIN_HTML,
- strlen (MAIN_HTML));
- } else if (g_str_equal (path, "/javascript.js")) {
- soup_message_body_append (msg->response_body,
- SOUP_MEMORY_COPY,
- JAVASCRIPT,
- strlen (JAVASCRIPT));
- }
-
-
- soup_message_body_complete (msg->response_body);
-}
-
-static void web_resource_fixture_setup(WebResourceFixture* fixture, gconstpointer data)
-{
- fixture->webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(fixture->webView);
- const gchar* webData = "<html></html>";
- fixture->webResource = webkit_web_resource_new(webData, strlen(webData), "http://example.com/", "text/html", "utf8", "Example.com");
- g_assert(fixture->webResource);
-}
-
-static void web_resource_fixture_teardown(WebResourceFixture* fixture, gconstpointer data)
-{
- g_assert(fixture->webResource);
- g_object_unref(fixture->webResource);
- g_object_unref(fixture->webView);
-}
-
-static void test_webkit_web_resource_get_url(WebResourceFixture* fixture, gconstpointer data)
-{
- gchar* url;
- g_object_get(G_OBJECT(fixture->webResource), "uri", &url, NULL);
- g_assert_cmpstr(url, ==, "http://example.com/");
- g_assert_cmpstr(webkit_web_resource_get_uri(fixture->webResource) ,==,"http://example.com/");
- g_free(url);
-}
-
-static void test_webkit_web_resource_get_data(WebResourceFixture* fixture, gconstpointer data)
-{
- GString* charData = webkit_web_resource_get_data(fixture->webResource);
- g_assert_cmpstr(charData->str, ==, "<html></html>");
-}
-
-static void test_webkit_web_resource_get_mime_type(WebResourceFixture* fixture, gconstpointer data)
-{
- gchar* mime_type;
- g_object_get(G_OBJECT(fixture->webResource), "mime-type", &mime_type, NULL);
- g_assert_cmpstr(mime_type, ==, "text/html");
- g_assert_cmpstr(webkit_web_resource_get_mime_type(fixture->webResource),==,"text/html");
- g_free(mime_type);
-}
-
-static void test_webkit_web_resource_get_encoding(WebResourceFixture* fixture, gconstpointer data)
-{
- gchar* text_encoding;
- g_object_get(G_OBJECT(fixture->webResource), "encoding", &text_encoding, NULL);
- g_assert_cmpstr(text_encoding, ==, "utf8");
- g_assert_cmpstr(webkit_web_resource_get_encoding(fixture->webResource),==,"utf8");
- g_free(text_encoding);
-}
-
-static void test_webkit_web_resource_get_frame_name(WebResourceFixture* fixture, gconstpointer data)
-{
- gchar* frame_name;
- g_object_get(G_OBJECT(fixture->webResource), "frame-name", &frame_name, NULL);
- g_assert_cmpstr(frame_name, ==, "Example.com");
- g_assert_cmpstr(webkit_web_resource_get_frame_name(fixture->webResource),==,"Example.com");
- g_free(frame_name);
-}
-
-static void resource_request_starting_cb(WebKitWebView* web_view, WebKitWebFrame* web_frame, WebKitWebResource* web_resource, WebKitNetworkRequest* request, WebKitNetworkResponse* response, gpointer data)
-{
- gint* been_there = data;
- *been_there = *been_there + 1;
-
- if (*been_there == 1) {
- g_assert(!main_resource);
- main_resource = g_object_ref(web_resource);
-
- g_assert_cmpstr(webkit_web_resource_get_uri(web_resource), ==, base_uri);
-
- /* This should be a redirect, so the response must be NULL */
- g_assert(!response);
- } else if (*been_there == 2) {
- char* uri = g_strdup_printf("%sindex.html", base_uri);
-
- g_assert_cmpstr(webkit_web_resource_get_uri(web_resource), ==, uri);
-
- /* Cancel the request. */
- webkit_network_request_set_uri(request, "about:blank");
-
- g_free(uri);
- }
-}
-
-static void notify_load_status_cb(WebKitWebView* web_view, GParamSpec* pspec, gpointer data)
-{
- if (webkit_web_view_get_load_status(web_view) == WEBKIT_LOAD_FINISHED) {
- gboolean* been_there = data;
- *been_there = TRUE;
-
- g_assert_cmpstr(webkit_web_view_get_uri(web_view), ==, "about:blank");
-
- g_main_loop_quit(loop);
- }
-}
-
-static void test_web_resource_loading()
-{
- WebKitWebView* web_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
- gint been_to_resource_request_starting = 0;
- gboolean been_to_load_finished = FALSE;
- WebKitWebFrame* web_frame;
- WebKitWebDataSource* data_source;
-
- loop = g_main_loop_new(NULL, TRUE);
-
- g_object_ref_sink(web_view);
-
- g_signal_connect(web_view, "resource-request-starting",
- G_CALLBACK(resource_request_starting_cb),
- &been_to_resource_request_starting);
-
- g_signal_connect(web_view, "notify::load-status",
- G_CALLBACK(notify_load_status_cb),
- &been_to_load_finished);
-
- webkit_web_view_load_uri(web_view, base_uri);
-
- /* We won't get finished immediately, because of the redirect */
- g_main_loop_run(loop);
-
- web_frame = webkit_web_view_get_main_frame(web_view);
- data_source = webkit_web_frame_get_data_source(web_frame);
-
- g_assert(main_resource);
- g_assert(webkit_web_data_source_get_main_resource(data_source) == main_resource);
- g_object_unref(main_resource);
-
- g_assert_cmpint(been_to_resource_request_starting, ==, 2);
- g_assert_cmpint(been_to_load_finished, ==, TRUE);
-
- g_object_unref(web_view);
- g_main_loop_unref(loop);
-}
-
-static void resource_request_starting_sub_cb(WebKitWebView* web_view, WebKitWebFrame* web_frame, WebKitWebResource* web_resource, WebKitNetworkRequest* request, WebKitNetworkResponse* response, gpointer data)
-{
- if (!main_resource)
- main_resource = g_object_ref(web_resource);
- else if (!sub_resource)
- sub_resource = g_object_ref(web_resource);
-}
-
-static void notify_load_status_sub_cb(WebKitWebView* web_view, GParamSpec* pspec, gpointer data)
-{
- if (webkit_web_view_get_load_status(web_view) == WEBKIT_LOAD_FINISHED)
- g_main_loop_quit(loop);
-}
-
-static gboolean idle_quit_loop_cb(gpointer data)
-{
- g_main_loop_quit(loop);
- return FALSE;
-}
-
-static void test_web_resource_sub_resource_loading()
-{
- WebKitWebView* web_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
- WebKitWebFrame* web_frame;
- WebKitWebDataSource* data_source;
- GList* sub_resources;
- char* uri = g_strdup_printf("%smain.html", base_uri);
-
- main_resource = NULL;
-
- loop = g_main_loop_new(NULL, TRUE);
-
- g_object_ref_sink(web_view);
-
- g_signal_connect(web_view, "resource-request-starting",
- G_CALLBACK(resource_request_starting_sub_cb),
- NULL);
-
- g_signal_connect(web_view, "notify::load-status",
- G_CALLBACK(notify_load_status_sub_cb),
- NULL);
-
- webkit_web_view_load_uri(web_view, uri);
-
- g_main_loop_run(loop);
-
- /* The main resource should be loaded; now let's wait for the sub-resource to load */
- g_idle_add(idle_quit_loop_cb, NULL);
- g_main_loop_run(loop);
-
- g_assert(main_resource && sub_resource);
- g_assert(main_resource != sub_resource);
-
- web_frame = webkit_web_view_get_main_frame(web_view);
- data_source = webkit_web_frame_get_data_source(web_frame);
-
- g_assert(webkit_web_data_source_get_main_resource(data_source) == main_resource);
- g_object_unref(main_resource);
-
- sub_resources = webkit_web_data_source_get_subresources(data_source);
- // Expected resources: javascripts.js, favicon.ico
- g_assert(sub_resources);
- g_assert(sub_resources->next);
- g_assert(!sub_resources->next->next);
-
- // Test that the object we got from the data source is the same
- // that went through resource-request-starting. Note that the order is
- // not important (and not guaranteed since the resources are stored in a
- // hashtable).
- g_assert(WEBKIT_WEB_RESOURCE(sub_resources->data) == sub_resource
- || WEBKIT_WEB_RESOURCE(sub_resources->next->data) == sub_resource);
-
- g_object_unref(web_view);
- g_main_loop_unref(loop);
-}
-
-int main(int argc, char** argv)
-{
- SoupServer* server;
- SoupURI* soup_uri;
-
- gtk_test_init(&argc, &argv, NULL);
-
- // Get rid of runtime warnings about deprecated properties and signals, since they break the tests.
- g_setenv("G_ENABLE_DIAGNOSTIC", "0", TRUE);
-
- server = soup_server_new(SOUP_SERVER_PORT, 0, NULL);
- soup_server_run_async(server);
-
- soup_server_add_handler(server, NULL, server_callback, NULL, NULL);
-
- soup_uri = soup_uri_new("http://127.0.0.1/");
- soup_uri_set_port(soup_uri, soup_server_get_port(server));
-
- base_uri = soup_uri_to_string(soup_uri, FALSE);
- soup_uri_free(soup_uri);
-
- g_test_bug_base("https://bugs.webkit.org/");
- g_test_add("/webkit/webresource/get_url",
- WebResourceFixture, 0, web_resource_fixture_setup,
- test_webkit_web_resource_get_url, web_resource_fixture_teardown);
- g_test_add("/webkit/webresource/get_mime_type",
- WebResourceFixture, 0, web_resource_fixture_setup,
- test_webkit_web_resource_get_mime_type, web_resource_fixture_teardown);
- g_test_add("/webkit/webresource/get_text_encoding_name",
- WebResourceFixture, 0, web_resource_fixture_setup,
- test_webkit_web_resource_get_encoding, web_resource_fixture_teardown);
- g_test_add("/webkit/webresource/get_frame_name",
- WebResourceFixture, 0, web_resource_fixture_setup,
- test_webkit_web_resource_get_frame_name, web_resource_fixture_teardown);
- g_test_add("/webkit/webresource/get_data",
- WebResourceFixture, 0, web_resource_fixture_setup,
- test_webkit_web_resource_get_data, web_resource_fixture_teardown);
-
- g_test_add_func("/webkit/webresource/loading", test_web_resource_loading);
- g_test_add_func("/webkit/webresource/sub_resource_loading", test_web_resource_sub_resource_loading);
-
- return g_test_run ();
-}
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebsettings.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebsettings.c
deleted file mode 100644
index e557e133c..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebsettings.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2009 Jan Michael Alonzo
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include <glib.h>
-#include <gtk/gtk.h>
-#include <webkit/webkit.h>
-
-static void test_webkit_web_settings_copy(void)
-{
- WebKitWebSettings *settings = webkit_web_settings_new();
-
- // Set some non-default settings to verify that settings are properly copied.
- g_object_set(settings,
- "enable-webgl", TRUE,
- "enable-fullscreen", TRUE,
- "auto-load-images", FALSE,
- "default-encoding", "utf-8",
- "enable-mediasource", TRUE,
- NULL);
-
- WebKitWebSettings *copy = webkit_web_settings_copy(settings);
-
- gboolean enableWebGL = FALSE;
- gboolean enableFullscreen = FALSE;
- gboolean autoLoadImages = FALSE;
- gboolean enableMediaSource = FALSE;
- char *defaultEncoding = 0;
- g_object_get(copy,
- "enable-fullscreen", &enableFullscreen,
- "enable-webgl", &enableWebGL,
- "auto-load-images", &autoLoadImages,
- "default-encoding", &defaultEncoding,
- "enable-mediasource", &enableMediaSource,
- NULL);
-
- g_assert(enableWebGL);
- g_assert(enableFullscreen);
- g_assert(!autoLoadImages);
- g_assert_cmpstr(defaultEncoding, ==, "utf-8");
- g_assert(enableMediaSource);
- g_free(defaultEncoding);
-}
-
-static void test_webkit_web_settings_user_agent(void)
-{
- WebKitWebSettings *settings;
- GtkWidget *webView;
- char *defaultUserAgent;
- char *userAgent = 0;
- g_test_bug("17375");
-
- webView = webkit_web_view_new();
- g_object_ref_sink(webView);
-
- settings = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(webView));
- defaultUserAgent = g_strdup(webkit_web_settings_get_user_agent(settings));
-
- g_assert(g_strstr_len(defaultUserAgent, -1, "Version/8.0 Safari/"));
- g_assert(g_strstr_len(defaultUserAgent, -1, "Version/8.0") < g_strstr_len(defaultUserAgent, -1, "Safari/"));
-
- // test a custom UA string
- userAgent = 0;
- g_object_set(settings, "user-agent", "testwebsettings/0.1", NULL);
- g_object_get(settings,"user-agent", &userAgent, NULL);
- g_assert_cmpstr(userAgent, ==, "testwebsettings/0.1");
- g_free(userAgent);
-
- // setting it to NULL or an empty value should give us the default UA string
- userAgent = 0;
- g_object_set(settings, "user-agent", 0, NULL);
- g_object_get(settings,"user-agent", &userAgent, NULL);
- g_assert_cmpstr(userAgent, ==, defaultUserAgent);
- g_free(userAgent);
-
- userAgent = 0;
- g_object_set(settings, "user-agent", "", NULL);
- g_object_get(settings,"user-agent", &userAgent, NULL);
- g_assert_cmpstr(userAgent, ==, defaultUserAgent);
- g_free(userAgent);
-
- g_free(defaultUserAgent);
- g_object_unref(webView);
-}
-
-int main(int argc, char **argv)
-{
- gtk_test_init(&argc, &argv, NULL);
-
- g_test_bug_base("https://bugs.webkit.org/");
- g_test_add_func("/webkit/websettings/user_agent", test_webkit_web_settings_user_agent);
- g_test_add_func("/webkit/websettings/copy", test_webkit_web_settings_copy);
- return g_test_run ();
-}
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebview.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebview.c
deleted file mode 100644
index 86057867c..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testwebview.c
+++ /dev/null
@@ -1,749 +0,0 @@
-/*
- * Copyright (C) 2008 Holger Hans Peter Freyther
- * Copyright (C) 2009, 2010 Collabora Ltd.
- * Copyright (C) 2012 Igalia S.L.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include "test_utils.h"
-
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <gdk/gdk.h>
-#include <gdk/gdkkeysyms.h>
-#include <gtk/gtk.h>
-#include <webkit/webkit.h>
-
-GMainLoop* loop;
-SoupSession *session;
-char* base_uri;
-
-/* For real request testing */
-static void
-server_callback(SoupServer* server, SoupMessage* msg,
- const char* path, GHashTable* query,
- SoupClientContext* context, gpointer data)
-{
- if (msg->method != SOUP_METHOD_GET) {
- soup_message_set_status(msg, SOUP_STATUS_NOT_IMPLEMENTED);
- return;
- }
-
- soup_message_set_status(msg, SOUP_STATUS_OK);
-
- if (g_str_equal(path, "/favicon.ico")) {
- char* contents;
- gsize length;
- GError* error = NULL;
-
- g_file_get_contents("blank.ico", &contents, &length, &error);
- g_assert(!error);
-
- soup_message_body_append(msg->response_body, SOUP_MEMORY_TAKE, contents, length);
- } else if (g_str_equal(path, "/bigdiv.html")) {
- char* contents = g_strdup("<html><body><a id=\"link\" href=\"http://abc.def\">test</a><div style=\"background-color: green; height: 1200px;\"></div></body></html>");
- soup_message_body_append(msg->response_body, SOUP_MEMORY_TAKE, contents, strlen(contents));
- } else if (g_str_equal(path, "/iframe.html")) {
- char* contents = g_strdup("<html><body id=\"some-content\"><div style=\"background-color: green; height: 50px;\"></div><iframe src=\"bigdiv.html\"></iframe></body></html>");
- soup_message_body_append(msg->response_body, SOUP_MEMORY_TAKE, contents, strlen(contents));
- } else {
- char* contents = g_strdup("<html><body>test</body></html>");
- soup_message_body_append(msg->response_body, SOUP_MEMORY_TAKE, contents, strlen(contents));
- }
-
- soup_message_body_complete(msg->response_body);
-}
-
-static void idle_quit_loop_cb(WebKitWebView* web_view, GParamSpec* pspec, gpointer data)
-{
- if (webkit_web_view_get_load_status(web_view) == WEBKIT_LOAD_FINISHED ||
- webkit_web_view_get_load_status(web_view) == WEBKIT_LOAD_FAILED)
- g_main_loop_quit(loop);
-}
-
-static gboolean timeout_cb(gpointer data)
-{
- g_error("Didn't get icon-uri before timing out.");
- return FALSE;
-}
-
-static void icon_uri_changed_cb(WebKitWebView* web_view, GParamSpec* pspec, gpointer data)
-{
- char* expected_uri;
-
- g_assert_cmpstr(g_param_spec_get_name(pspec), ==, "icon-uri");
-
- expected_uri = g_strdup_printf("%sfavicon.ico", base_uri);
- g_assert_cmpstr(webkit_web_view_get_icon_uri(web_view), ==, expected_uri);
- g_free(expected_uri);
-
- g_main_loop_quit(loop);
-}
-
-static void icon_loaded_cb(WebKitWebView* web_view, char* icon_uri, gpointer data)
-{
- gboolean* been_here = (gboolean*)data;
- char* expected_uri = g_strdup_printf("%sfavicon.ico", base_uri);
- g_assert_cmpstr(icon_uri, ==, expected_uri);
- g_free(expected_uri);
-
- g_assert_cmpstr(icon_uri, ==, webkit_web_view_get_icon_uri(web_view));
-
- *been_here = TRUE;
-}
-
-static void test_webkit_web_view_icon_uri()
-{
- gboolean been_to_icon_loaded = FALSE;
- WebKitWebView* view = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_object_ref_sink(G_OBJECT(view));
-
- loop = g_main_loop_new(NULL, TRUE);
-
- g_object_connect(G_OBJECT(view),
- "signal::notify::icon-uri", icon_uri_changed_cb, NULL,
- "signal::icon-loaded", icon_loaded_cb, &been_to_icon_loaded,
- NULL);
-
- webkit_web_view_load_uri(view, base_uri);
-
- guint timeout_id = g_timeout_add(500, timeout_cb, 0);
-
- g_main_loop_run(loop);
-
- g_source_remove(timeout_id);
-
- g_assert(been_to_icon_loaded);
-
- g_object_unref(view);
-}
-
-static gboolean map_event_cb(GtkWidget *widget, GdkEvent* event, gpointer data)
-{
- GMainLoop* loop = (GMainLoop*)data;
- g_main_loop_quit(loop);
-
- return FALSE;
-}
-
-static gboolean quit_after_short_delay_cb(gpointer data)
-{
- g_main_loop_quit((GMainLoop*)data);
- return FALSE;
-}
-
-static void test_webkit_web_view_grab_focus()
-{
- char* uri = g_strconcat(base_uri, "iframe.html", NULL);
- GtkWidget* window = gtk_window_new(GTK_WINDOW_POPUP);
- GtkWidget* scrolled_window = gtk_scrolled_window_new(NULL, NULL);
- WebKitWebView* view = WEBKIT_WEB_VIEW(webkit_web_view_new());
- GtkAdjustment* adjustment;
-
- gtk_window_set_default_size(GTK_WINDOW(window), 400, 200);
-
- gtk_container_add(GTK_CONTAINER(window), scrolled_window);
- gtk_container_add(GTK_CONTAINER(scrolled_window), GTK_WIDGET(view));
-
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-
- loop = g_main_loop_new(NULL, TRUE);
-
- g_signal_connect(view, "notify::load-status", G_CALLBACK(idle_quit_loop_cb), NULL);
-
- /* Wait for window to show up */
- gtk_widget_show_all(window);
- g_signal_connect(window, "map-event",
- G_CALLBACK(map_event_cb), loop);
- g_main_loop_run(loop);
-
- /* Load a page with a big div that will cause scrollbars to appear */
- webkit_web_view_load_uri(view, uri);
- g_main_loop_run(loop);
-
- adjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scrolled_window));
- g_assert_cmpfloat(gtk_adjustment_get_value(adjustment), ==, 0.0);
-
- /* Since webkit_web_view_execute_script does not return a value,
- it is impossible to know if an inner document has focus after
- a node of it was focused via .focus() method.
- The code below is an workaround: if the node has focus, a scroll
- action is performed and afterward it is checked if the adjustment
- has to be different from 0.
- */
- char script[] = "var innerDoc = document.defaultView.frames[0].document; \
- innerDoc.getElementById(\"link\").focus(); \
- if (innerDoc.hasFocus()) \
- window.scrollBy(0, 100);";
-
- /* Focus an element using JavaScript */
- webkit_web_view_execute_script(view, script);
-
- /* Adjustments update asynchronously, so we must wait a bit. */
- g_timeout_add(100, quit_after_short_delay_cb, loop);
- g_main_loop_run(loop);
-
- /* Make sure the ScrolledWindow noticed the scroll */
- g_assert_cmpfloat(gtk_adjustment_get_value(adjustment), !=, 0.0);
-
- g_free(uri);
- gtk_widget_destroy(window);
-}
-
-static void do_test_webkit_web_view_adjustments(gboolean with_page_cache)
-{
- char* effective_uri = g_strconcat(base_uri, "bigdiv.html", NULL);
- char* second_uri = g_strconcat(base_uri, "iframe.html", NULL);
- GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- GtkWidget* scrolled_window = gtk_scrolled_window_new(NULL, NULL);
- WebKitWebView* view = WEBKIT_WEB_VIEW(webkit_web_view_new());
- GtkAdjustment* adjustment;
- double lower;
- double upper;
-
- if (with_page_cache) {
- WebKitWebSettings* settings = webkit_web_view_get_settings(view);
- g_object_set(settings, "enable-page-cache", TRUE, NULL);
- }
-
- gtk_window_set_default_size(GTK_WINDOW(window), 400, 200);
-
- gtk_container_add(GTK_CONTAINER(window), scrolled_window);
- gtk_container_add(GTK_CONTAINER(scrolled_window), GTK_WIDGET(view));
-
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-
- loop = g_main_loop_new(NULL, TRUE);
-
- g_object_connect(G_OBJECT(view),
- "signal::notify::load-status", idle_quit_loop_cb, NULL,
- NULL);
-
- /* Wait for window to show up */
- gtk_widget_show_all(window);
- g_signal_connect(window, "map-event",
- G_CALLBACK(map_event_cb), loop);
- g_main_loop_run(loop);
-
- /* Load a page with a big div that will cause scrollbars to appear */
- webkit_web_view_load_uri(view, effective_uri);
- g_main_loop_run(loop);
-
- /* Adjustments update asynchronously, so we must wait a bit. */
- g_timeout_add(100, quit_after_short_delay_cb, loop);
- g_main_loop_run(loop);
-
- adjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scrolled_window));
- g_assert_cmpfloat(gtk_adjustment_get_value(adjustment), ==, 0.0);
-
- lower = gtk_adjustment_get_lower(adjustment);
- upper = gtk_adjustment_get_upper(adjustment);
-
- /* Scroll the view using JavaScript */
- webkit_web_view_execute_script(view, "window.scrollBy(0, 100)");
-
- /* Adjustments update asynchronously, so we must wait a bit. */
- g_timeout_add(100, quit_after_short_delay_cb, loop);
- g_main_loop_run(loop);
-
- /* Make sure the ScrolledWindow noticed the scroll */
- g_assert_cmpfloat(gtk_adjustment_get_value(adjustment), ==, 100.0);
-
- /* Load a second URI */
- webkit_web_view_load_uri(view, second_uri);
- g_main_loop_run(loop);
-
- /* The page loaded but the adjustments may not be updated yet. Wait a bit. */
- g_timeout_add(100, quit_after_short_delay_cb, loop);
- g_main_loop_run(loop);
-
- /* Make sure the scrollbar has been reset */
- g_assert_cmpfloat(gtk_adjustment_get_value(adjustment), ==, 0.0);
-
- /* Go back */
- webkit_web_view_go_back(view);
-
- /* When using page cache, go_back will return syncronously */
- if (!with_page_cache)
- g_main_loop_run(loop);
-
- /* Make sure GTK+ has time to process the changes in size, for the adjusments */
- while (gtk_events_pending())
- gtk_main_iteration();
-
- /* Make sure upper and lower bounds have been restored correctly */
- g_assert_cmpfloat(lower, ==, gtk_adjustment_get_lower(adjustment));
- g_assert_cmpfloat(upper, ==, gtk_adjustment_get_upper(adjustment));
- g_assert_cmpfloat(gtk_adjustment_get_value(adjustment), ==, 100.0);
-
- g_free(effective_uri);
- g_free(second_uri);
-
- gtk_widget_destroy(window);
-}
-
-static void test_webkit_web_view_adjustments()
-{
- /* Test this with page cache disabled, and enabled. */
- do_test_webkit_web_view_adjustments(FALSE);
- do_test_webkit_web_view_adjustments(TRUE);
-}
-
-gboolean delayed_destroy(gpointer data)
-{
- gtk_widget_destroy(GTK_WIDGET(data));
- g_main_loop_quit(loop);
- return FALSE;
-}
-
-static void test_webkit_web_view_destroy()
-{
- GtkWidget* window;
- GtkWidget* web_view;
-
- window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- web_view = webkit_web_view_new();
-
- gtk_container_add(GTK_CONTAINER(window), web_view);
-
- gtk_widget_show_all(window);
-
- loop = g_main_loop_new(NULL, TRUE);
-
- g_signal_connect(window, "map-event",
- G_CALLBACK(map_event_cb), loop);
- g_main_loop_run(loop);
-
- g_idle_add(delayed_destroy, web_view);
- g_main_loop_run(loop);
-
- gtk_widget_destroy(window);
-}
-
-static void test_webkit_web_view_window_features()
-{
- GtkWidget* window;
- GtkWidget* web_view;
-
- window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- web_view = webkit_web_view_new();
-
- gtk_container_add(GTK_CONTAINER(window), web_view);
-
- gtk_widget_show_all(window);
-
- loop = g_main_loop_new(NULL, TRUE);
-
- g_signal_connect(window, "map-event",
- G_CALLBACK(map_event_cb), loop);
- g_main_loop_run(loop);
-
- /* Bug #36144 */
- g_object_set(G_OBJECT(web_view), "window-features", NULL, NULL);
-
- gtk_widget_destroy(window);
-}
-
-static void test_webkit_web_view_in_offscreen_window_does_not_crash()
-{
- loop = g_main_loop_new(NULL, TRUE);
-
- GtkWidget *window = gtk_offscreen_window_new();
- GtkWidget *web_view = webkit_web_view_new();
-
- gtk_container_add(GTK_CONTAINER(window), web_view);
- gtk_widget_show_all(window);
- g_signal_connect(web_view, "notify::load-status", G_CALLBACK(idle_quit_loop_cb), NULL);
- webkit_web_view_load_uri(WEBKIT_WEB_VIEW(web_view), base_uri);
-
- g_main_loop_run(loop);
-
- gtk_widget_destroy(window);
- g_main_loop_unref(loop);
-}
-
-static void test_webkit_web_view_does_not_steal_focus()
-{
- loop = g_main_loop_new(NULL, TRUE);
-
- GtkWidget *window = gtk_offscreen_window_new();
- GtkWidget *webView = webkit_web_view_new();
- GtkWidget *entry = gtk_entry_new();
-
-#ifdef GTK_API_VERSION_2
- GtkWidget *box = gtk_hbox_new(FALSE, 0);
-#else
- GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
-#endif
-
- gtk_container_add(GTK_CONTAINER(box), webView);
- gtk_container_add(GTK_CONTAINER(box), entry);
- gtk_container_add(GTK_CONTAINER(window), box);
- gtk_widget_show_all(window);
-
- gtk_widget_grab_focus(entry);
- g_assert(gtk_widget_is_focus(entry));
-
- g_signal_connect(webView, "notify::load-status", G_CALLBACK(idle_quit_loop_cb), NULL);
- webkit_web_view_load_html_string(WEBKIT_WEB_VIEW(webView),
- "<html><body>"
- " <input id=\"entry\" type=\"text\"/>"
- " <script>"
- " document.getElementById(\"entry\").focus();"
- " </script>"
- "</body></html>", "file://");
-
- g_main_loop_run(loop);
-
- g_assert(gtk_widget_is_focus(entry));
-
- gtk_widget_destroy(window);
- g_main_loop_unref(loop);
-}
-
-static gboolean emitKeyStroke(WebKitWebView* webView)
-{
- GdkEvent* pressEvent = gdk_event_new(GDK_KEY_PRESS);
- pressEvent->key.keyval = GDK_KEY_f;
- GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(webView));
- pressEvent->key.window = window;
- g_object_ref(pressEvent->key.window);
-
-#ifndef GTK_API_VERSION_2
- GdkDeviceManager* manager = gdk_display_get_device_manager(gdk_window_get_display(window));
- gdk_event_set_device(pressEvent, gdk_device_manager_get_client_pointer(manager));
-#endif
-
- // When synthesizing an event, an invalid hardware_keycode value
- // can cause it to be badly processed by Gtk+.
- GdkKeymapKey* keys;
- gint n_keys;
- if (gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), GDK_KEY_f, &keys, &n_keys)) {
- pressEvent->key.hardware_keycode = keys[0].keycode;
- g_free(keys);
- }
-
- GdkEvent* releaseEvent = gdk_event_copy(pressEvent);
- gtk_main_do_event(pressEvent);
- gdk_event_free(pressEvent);
- releaseEvent->key.type = GDK_KEY_RELEASE;
- gtk_main_do_event(releaseEvent);
- gdk_event_free(releaseEvent);
-
- return FALSE;
-}
-
-static gboolean entering_fullscreen_cb(WebKitWebView* webView, GObject* element, gboolean blocked)
-{
- if (blocked)
- g_main_loop_quit(loop);
- else
- g_timeout_add(200, (GSourceFunc) emitKeyStroke, webView);
- return blocked;
-}
-
-static gboolean leaving_fullscreen_cb(WebKitWebView* webView, GObject* element, gpointer data)
-{
- g_main_loop_quit(loop);
- return FALSE;
-}
-
-static void test_webkit_web_view_fullscreen(gconstpointer blocked)
-{
- GtkWidget* window;
- GtkWidget* web_view;
- WebKitWebSettings *settings;
-
- window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- web_view = webkit_web_view_new();
-
- settings = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(web_view));
- g_object_set(settings, "enable-fullscreen", TRUE, NULL);
- webkit_web_view_set_settings(WEBKIT_WEB_VIEW(web_view), settings);
-
- gtk_container_add(GTK_CONTAINER(window), web_view);
-
- gtk_widget_show_all(window);
-
- loop = g_main_loop_new(NULL, TRUE);
-
- g_signal_connect(web_view, "entering-fullscreen", G_CALLBACK(entering_fullscreen_cb), (gpointer) blocked);
- g_signal_connect(web_view, "leaving-fullscreen", G_CALLBACK(leaving_fullscreen_cb), NULL);
-
- webkit_web_view_load_string(WEBKIT_WEB_VIEW(web_view), "<html><body>"
- "<script>"
- "var eventName = 'keypress';"
- "document.addEventListener(eventName, function () {"
- " document.documentElement.webkitRequestFullScreen();"
- "}, false);"
- "</script></body></html>", NULL, NULL, NULL);
-
- g_timeout_add(100, (GSourceFunc) emitKeyStroke, WEBKIT_WEB_VIEW(web_view));
- g_main_loop_run(loop);
-
- gtk_widget_destroy(window);
-}
-
-static gboolean checkMimeTypeForFilter(GtkFileFilter* filter, const gchar* mimeType)
-{
- GtkFileFilterInfo filter_info;
- filter_info.contains = GTK_FILE_FILTER_MIME_TYPE;
- filter_info.mime_type = mimeType;
- return gtk_file_filter_filter(filter, &filter_info);
-}
-
-static gboolean runFileChooserCbNoMultiselNoMime(WebKitWebView* webview, WebKitFileChooserRequest* request, gpointer data)
-{
- g_assert(!webkit_file_chooser_request_get_select_multiple(request));
-
- const gchar* const* mimeTypes = webkit_file_chooser_request_get_mime_types(request);
- g_assert(!mimeTypes);
- GtkFileFilter* filter = webkit_file_chooser_request_get_mime_types_filter(request);
- g_assert(!filter);
-
- const gchar* const* selectedFiles = webkit_file_chooser_request_get_selected_files(request);
- g_assert(!selectedFiles);
-
- g_main_loop_quit(loop);
- return TRUE;
-}
-
-static gboolean runFileChooserCbMultiselNoMime(WebKitWebView* webview, WebKitFileChooserRequest* request, gpointer data)
-{
- g_assert(webkit_file_chooser_request_get_select_multiple(request));
-
- const gchar* const* mimeTypes = webkit_file_chooser_request_get_mime_types(request);
- g_assert(!mimeTypes);
- GtkFileFilter* filter = webkit_file_chooser_request_get_mime_types_filter(request);
- g_assert(!filter);
- const gchar* const* selectedFiles = webkit_file_chooser_request_get_selected_files(request);
- g_assert(!selectedFiles);
-
- // Select some files.
- const gchar* filesToSelect[4] = { "/foo", "/foo/bar", "/foo/bar/baz", 0 };
- webkit_file_chooser_request_select_files(request, filesToSelect);
-
- // Check the files that have been just selected.
- selectedFiles = webkit_file_chooser_request_get_selected_files(request);
- g_assert(selectedFiles);
- g_assert_cmpstr(selectedFiles[0], ==, "/foo");
- g_assert_cmpstr(selectedFiles[1], ==, "/foo/bar");
- g_assert_cmpstr(selectedFiles[2], ==, "/foo/bar/baz");
- g_assert(!selectedFiles[3]);
-
- g_main_loop_quit(loop);
- return TRUE;
-}
-
-static gboolean runFileChooserCbSelectionRetained(WebKitWebView* webview, WebKitFileChooserRequest* request, gpointer data)
-{
- const gchar* const* selectedFiles = webkit_file_chooser_request_get_selected_files(request);
- g_assert(selectedFiles);
- g_assert_cmpstr(selectedFiles[0], ==, "/foo");
- g_assert_cmpstr(selectedFiles[1], ==, "/foo/bar");
- g_assert_cmpstr(selectedFiles[2], ==, "/foo/bar/baz");
- g_assert(!selectedFiles[3]);
-
- g_main_loop_quit(loop);
- return TRUE;
-}
-
-static gboolean runFileChooserCbNoMultiselAcceptTypes(WebKitWebView* webview, WebKitFileChooserRequest* request, gpointer data)
-{
- g_assert(!webkit_file_chooser_request_get_select_multiple(request));
-
- const gchar* const* mimeTypes = webkit_file_chooser_request_get_mime_types(request);
- g_assert(mimeTypes);
- g_assert_cmpstr(mimeTypes[0], ==, "audio/*");
- g_assert_cmpstr(mimeTypes[1], ==, "video/*");
- g_assert_cmpstr(mimeTypes[2], ==, "image/*");
- g_assert(!mimeTypes[3]);
-
- GtkFileFilter* filter = webkit_file_chooser_request_get_mime_types_filter(request);
- g_assert(GTK_IS_FILE_FILTER(filter));
- g_assert(checkMimeTypeForFilter(filter, "audio/*"));
- g_assert(checkMimeTypeForFilter(filter, "video/*"));
- g_assert(checkMimeTypeForFilter(filter, "image/*"));
-
- const gchar* const* selectedFiles = webkit_file_chooser_request_get_selected_files(request);
- g_assert(!selectedFiles);
-
- g_main_loop_quit(loop);
- return TRUE;
-}
-
-void doMouseButtonEvent(GtkWidget* widget, GdkEventType eventType, int x, int y, unsigned int button, unsigned int modifiers)
-{
- g_assert(gtk_widget_get_realized(widget));
-
- GdkEvent* event = gdk_event_new(eventType);
- event->button.window = gtk_widget_get_window(widget);
- g_object_ref(event->button.window);
-
- event->button.time = GDK_CURRENT_TIME;
- event->button.x = x;
- event->button.y = y;
- event->button.axes = 0;
- event->button.state = modifiers;
- event->button.button = button;
-
-#ifndef GTK_API_VERSION_2
- event->button.device = gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(gtk_widget_get_display(widget)));
-#endif
-
- int xRoot, yRoot;
- gdk_window_get_root_coords(gtk_widget_get_window(widget), x, y, &xRoot, &yRoot);
- event->button.x_root = xRoot;
- event->button.y_root = yRoot;
- gtk_main_do_event(event);
-}
-
-static void clickMouseButton(GtkWidget* widget, int x, int y, unsigned int button, unsigned int modifiers)
-{
- doMouseButtonEvent(widget, GDK_BUTTON_PRESS, x, y, button, modifiers);
- doMouseButtonEvent(widget, GDK_BUTTON_RELEASE, x, y, button, modifiers);
-}
-
-static gboolean clickMouseButtonAndWaitForFileChooserRequest(WebKitWebView* webView)
-{
- clickMouseButton(GTK_WIDGET(webView), 5, 5, 1, 0);
- return TRUE;
-}
-
-static void test_webkit_web_view_file_chooser()
-{
- const gchar* htmlFormatBase = "<html><body>"
- "<input style='position:absolute;left:0;top:0;margin:0;padding:0' type='file' %s/>"
- "</body></html>";
-
- GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- GtkWidget* webView = webkit_web_view_new();
- gtk_container_add(GTK_CONTAINER(window), webView);
- gtk_widget_show_all(window);
-
- loop = g_main_loop_new(NULL, TRUE);
-
- // Multiple selections not allowed, no MIME filtering.
- gulong handler = g_signal_connect(webView, "run-file-chooser", G_CALLBACK(runFileChooserCbNoMultiselNoMime), NULL);
- gchar* htmlFormat = g_strdup_printf(htmlFormatBase, "");
- webkit_web_view_load_string(WEBKIT_WEB_VIEW(webView), htmlFormat, NULL, NULL, NULL);
- g_free(htmlFormat);
-
- g_timeout_add(100, (GSourceFunc) clickMouseButtonAndWaitForFileChooserRequest, WEBKIT_WEB_VIEW(webView));
- g_main_loop_run(loop);
-
- g_signal_handler_disconnect(webView, handler);
-
- // Multiple selections allowed, no MIME filtering, some pre-selected files.
- handler = g_signal_connect(webView, "run-file-chooser", G_CALLBACK(runFileChooserCbMultiselNoMime), NULL);
- htmlFormat = g_strdup_printf(htmlFormatBase, "multiple");
- webkit_web_view_load_string(WEBKIT_WEB_VIEW(webView), htmlFormat, NULL, NULL, NULL);
- g_free(htmlFormat);
-
- g_timeout_add(100, (GSourceFunc) clickMouseButtonAndWaitForFileChooserRequest, WEBKIT_WEB_VIEW(webView));
- g_main_loop_run(loop);
-
- g_signal_handler_disconnect(webView, handler);
-
- // Perform another request to check if the list of files selected
- // in the previous step appears now as part of the new request.
- handler = g_signal_connect(webView, "run-file-chooser", G_CALLBACK(runFileChooserCbSelectionRetained), NULL);
- g_timeout_add(100, (GSourceFunc) clickMouseButtonAndWaitForFileChooserRequest, WEBKIT_WEB_VIEW(webView));
- g_main_loop_run(loop);
-
- g_signal_handler_disconnect(webView, handler);
-
- // Multiple selections not allowed, only accept images, audio and video files.
- handler = g_signal_connect(webView, "run-file-chooser", G_CALLBACK(runFileChooserCbNoMultiselAcceptTypes), NULL);
- htmlFormat = g_strdup_printf(htmlFormatBase, "accept='audio/*,video/*,image/*'");
- webkit_web_view_load_string(WEBKIT_WEB_VIEW(webView), htmlFormat, NULL, NULL, NULL);
- g_free(htmlFormat);
-
- g_timeout_add(100, (GSourceFunc) clickMouseButtonAndWaitForFileChooserRequest, WEBKIT_WEB_VIEW(webView));
- g_main_loop_run(loop);
-
- g_signal_handler_disconnect(webView, handler);
- gtk_widget_destroy(window);
-}
-
-static void test_webkit_web_view_source_mode()
-{
- GtkWidget* web_view;
-
- web_view = webkit_web_view_new();
-
- webkit_web_view_load_string(WEBKIT_WEB_VIEW(web_view), "<html><body></body></html>", NULL, NULL, NULL);
-
- g_assert(!webkit_web_view_get_view_source_mode(WEBKIT_WEB_VIEW(web_view)));
-
- webkit_web_view_set_view_source_mode(WEBKIT_WEB_VIEW(web_view), TRUE);
-
- g_assert(webkit_web_view_get_view_source_mode(WEBKIT_WEB_VIEW(web_view)));
-
- webkit_web_view_set_view_source_mode(WEBKIT_WEB_VIEW(web_view), FALSE);
-
- g_assert(!webkit_web_view_get_view_source_mode(WEBKIT_WEB_VIEW(web_view)));
-
- gtk_widget_destroy(web_view);
-}
-
-int main(int argc, char** argv)
-{
- SoupServer* server;
- SoupURI* soup_uri;
-
- gtk_test_init(&argc, &argv, NULL);
-
- // Get rid of runtime warnings about deprecated properties and signals, since they break the tests.
- g_setenv("G_ENABLE_DIAGNOSTIC", "0", TRUE);
-
- /* Hopefully make test independent of the path it's called from. */
- testutils_relative_chdir("Tools/TestWebKitAPI/Tests/WebKitGtk/resources/test.html", argv[0]);
-
- server = soup_server_new(SOUP_SERVER_PORT, 0, NULL);
- soup_server_run_async(server);
-
- soup_server_add_handler(server, NULL, server_callback, NULL, NULL);
-
- soup_uri = soup_uri_new("http://127.0.0.1/");
- soup_uri_set_port(soup_uri, soup_server_get_port(server));
-
- base_uri = soup_uri_to_string(soup_uri, FALSE);
- soup_uri_free(soup_uri);
-
- g_test_bug_base("https://bugs.webkit.org/");
- g_test_add_func("/webkit/webview/icon-uri", test_webkit_web_view_icon_uri);
- g_test_add_func("/webkit/webview/adjustments", test_webkit_web_view_adjustments);
- g_test_add_func("/webkit/webview/destroy", test_webkit_web_view_destroy);
- g_test_add_func("/webkit/webview/grab_focus", test_webkit_web_view_grab_focus);
- g_test_add_func("/webkit/webview/window-features", test_webkit_web_view_window_features);
- g_test_add_func("/webkit/webview/webview-in-offscreen-window-does-not-crash", test_webkit_web_view_in_offscreen_window_does_not_crash);
- g_test_add_func("/webkit/webview/webview-does-not-steal-focus", test_webkit_web_view_does_not_steal_focus);
- g_test_add_data_func("/webkit/webview/fullscreen", GINT_TO_POINTER(FALSE), test_webkit_web_view_fullscreen);
- g_test_add_data_func("/webkit/webview/fullscreen-blocked", GINT_TO_POINTER(TRUE), test_webkit_web_view_fullscreen);
- g_test_add_func("/webkit/webview/file-chooser", test_webkit_web_view_file_chooser);
- g_test_add_func("/webkit/webview/source-mode", test_webkit_web_view_source_mode);
-
- return g_test_run ();
-}
diff --git a/Tools/TestWebKitAPI/Tests/WebKitGtk/testwindow.c b/Tools/TestWebKitAPI/Tests/WebKitGtk/testwindow.c
deleted file mode 100644
index 5eda47b12..000000000
--- a/Tools/TestWebKitAPI/Tests/WebKitGtk/testwindow.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2009 Collabora Ltd.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include <gtk/gtk.h>
-#include <webkit/webkit.h>
-
-static void notify_load_status_cb(WebKitWebView* web_view, GParamSpec* pspec, gpointer data)
-{
- if (webkit_web_view_get_load_status(web_view) == WEBKIT_LOAD_FINISHED) {
- GMainLoop* loop = (GMainLoop*)data;
-
- g_main_loop_quit(loop);
- }
-}
-
-static void test_webkit_window_scrollbar_policy(void)
-{
- GMainLoop* loop;
- GtkWidget* scrolledWindow;
- GtkWidget* webView;
- WebKitWebFrame* mainFrame;
- GtkPolicyType horizontalPolicy;
- GtkPolicyType verticalPolicy;
-
- loop = g_main_loop_new(NULL, TRUE);
-
- scrolledWindow = gtk_scrolled_window_new(NULL, NULL);
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledWindow),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-
- webView = webkit_web_view_new();
- g_object_ref_sink(webView);
-
- g_signal_connect(webView, "notify::load-status",
- G_CALLBACK(notify_load_status_cb), loop);
-
- gtk_container_add(GTK_CONTAINER(scrolledWindow), webView);
-
- mainFrame = webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(webView));
-
- /* Test we correctly apply policy for not having scrollbars; This
- * case is special, because we turn the policy from NEVER to
- * AUTOMATIC, since we cannot easily represent the same thing
- * using GtkScrolledWindow */
- webkit_web_view_load_html_string(WEBKIT_WEB_VIEW(webView),
- "<html><body>WebKit!</body><script>document.getElementsByTagName('body')[0].style.overflow = 'hidden';</script></html>",
- "file://");
-
- g_main_loop_run(loop);
-
- gtk_scrolled_window_get_policy(GTK_SCROLLED_WINDOW(scrolledWindow),
- &horizontalPolicy, &verticalPolicy);
-
- g_assert(horizontalPolicy == GTK_POLICY_AUTOMATIC);
- g_assert(verticalPolicy == GTK_POLICY_AUTOMATIC);
-
- g_assert(GTK_POLICY_NEVER == webkit_web_frame_get_horizontal_scrollbar_policy(mainFrame));
- g_assert(GTK_POLICY_NEVER == webkit_web_frame_get_vertical_scrollbar_policy(mainFrame));
-
- /* Test we correctly apply policy for always having scrollbars */
- webkit_web_view_load_html_string(WEBKIT_WEB_VIEW(webView),
- "<html><body>WebKit!</body><script>document.getElementsByTagName('body')[0].style.overflow = 'scroll';</script></html>",
- "file://");
-
- g_main_loop_run(loop);
-
- gtk_scrolled_window_get_policy(GTK_SCROLLED_WINDOW(scrolledWindow),
- &horizontalPolicy, &verticalPolicy);
-
- g_assert(horizontalPolicy == GTK_POLICY_ALWAYS);
- g_assert(verticalPolicy == GTK_POLICY_ALWAYS);
-
- g_assert(horizontalPolicy == webkit_web_frame_get_horizontal_scrollbar_policy(mainFrame));
- g_assert(verticalPolicy == webkit_web_frame_get_vertical_scrollbar_policy(mainFrame));
-
- /* Test we correctly apply policy for having scrollbars when needed */
- webkit_web_view_load_html_string(WEBKIT_WEB_VIEW(webView),
- "<html><body>WebKit!</body><script>document.getElementsByTagName('body')[0].style.overflow = 'auto';</script></html>",
- "file://");
-
- g_main_loop_run(loop);
-
- gtk_scrolled_window_get_policy(GTK_SCROLLED_WINDOW(scrolledWindow),
- &horizontalPolicy, &verticalPolicy);
-
- g_assert(horizontalPolicy == GTK_POLICY_AUTOMATIC);
- g_assert(verticalPolicy == GTK_POLICY_AUTOMATIC);
-
- g_assert(horizontalPolicy == webkit_web_frame_get_horizontal_scrollbar_policy(mainFrame));
- g_assert(verticalPolicy == webkit_web_frame_get_vertical_scrollbar_policy(mainFrame));
-
- g_object_unref(webView);
-}
-
-int main(int argc, char** argv)
-{
- gtk_test_init(&argc, &argv, NULL);
-
- g_test_bug_base("https://bugs.webkit.org/");
- g_test_add_func("/webkit/window/scrollbar_policy", test_webkit_window_scrollbar_policy);
- return g_test_run ();
-}
diff --git a/Tools/TestWebKitAPI/TestsController.cpp b/Tools/TestWebKitAPI/TestsController.cpp
index 29dcc714e..913305d7b 100644
--- a/Tools/TestWebKitAPI/TestsController.cpp
+++ b/Tools/TestWebKitAPI/TestsController.cpp
@@ -30,9 +30,33 @@
namespace TestWebKitAPI {
-TestsController& TestsController::shared()
+class Printer : public ::testing::EmptyTestEventListener {
+ virtual void OnTestPartResult(const ::testing::TestPartResult& test_part_result)
+ {
+ if (!test_part_result.failed())
+ return;
+
+ std::stringstream stream;
+ stream << "\n" << test_part_result.file_name() << ":" << test_part_result.line_number() << "\n" << test_part_result.summary() << "\n\n";
+ failures += stream.str();
+ }
+
+ virtual void OnTestEnd(const ::testing::TestInfo& test_info)
+ {
+ if (test_info.result()->Passed())
+ std::cout << "**PASS** " << test_info.test_case_name() << "." << test_info.name() << "\n";
+ else
+ std::cout << "**FAIL** " << test_info.test_case_name() << "." << test_info.name() << "\n" << failures;
+
+ failures = std::string();
+ }
+
+ std::string failures;
+};
+
+TestsController& TestsController::singleton()
{
- static TestsController& shared = *new TestsController;
+ static NeverDestroyed<TestsController> shared;
return shared;
}
@@ -48,6 +72,11 @@ TestsController::TestsController()
bool TestsController::run(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
+
+ ::testing::TestEventListeners& listeners = ::testing::UnitTest::GetInstance()->listeners();
+ delete listeners.Release(listeners.default_result_printer());
+ listeners.Append(new Printer);
+
return !RUN_ALL_TESTS();
}
diff --git a/Tools/TestWebKitAPI/TestsController.h b/Tools/TestWebKitAPI/TestsController.h
index c73e3ac4d..ea8496853 100644
--- a/Tools/TestWebKitAPI/TestsController.h
+++ b/Tools/TestWebKitAPI/TestsController.h
@@ -26,17 +26,21 @@
#ifndef TestsController_h
#define TestsController_h
+#include <wtf/NeverDestroyed.h>
+
namespace TestWebKitAPI {
class TestsController {
public:
- static TestsController& shared();
+ static TestsController& singleton();
bool run(int argc, char** argv);
private:
TestsController();
~TestsController();
+
+ friend class WTF::NeverDestroyed<TestsController>;
};
} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Utilities.h b/Tools/TestWebKitAPI/Utilities.h
new file mode 100644
index 000000000..f77d25c71
--- /dev/null
+++ b/Tools/TestWebKitAPI/Utilities.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+namespace TestWebKitAPI {
+namespace Util {
+
+// Runs a platform runloop until the 'done' is true.
+void run(bool* done);
+void sleep(double seconds);
+
+} // namespace Util
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/WKWebViewConfigurationExtras.h b/Tools/TestWebKitAPI/WKWebViewConfigurationExtras.h
new file mode 100644
index 000000000..782da85d4
--- /dev/null
+++ b/Tools/TestWebKitAPI/WKWebViewConfigurationExtras.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <WebKit/WKWebViewConfiguration.h>
+
+#if WK_API_ENABLED
+
+@interface WKWebViewConfiguration (TestWebKitAPIExtras)
++ (instancetype)testwebkitapi_configurationWithTestPlugInClassName:(NSString *)className;
+@end
+
+#endif // WK_API_ENABLED
diff --git a/Tools/TestWebKitAPI/WTFStringUtilities.h b/Tools/TestWebKitAPI/WTFStringUtilities.h
index 29a876788..ecba9c4b2 100644
--- a/Tools/TestWebKitAPI/WTFStringUtilities.h
+++ b/Tools/TestWebKitAPI/WTFStringUtilities.h
@@ -28,8 +28,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef WTFStringUtilities_h
-#define WTFStringUtilities_h
+#pragma once
#include <wtf/Assertions.h>
#include <wtf/text/CString.h>
@@ -45,4 +44,12 @@ inline std::ostream& operator<<(std::ostream& os, const String& string)
}
-#endif // WTFStringUtilities_h
+template<size_t length>
+static String utf16String(const char16_t (&url)[length])
+{
+ StringBuilder builder;
+ builder.reserveCapacity(length - 1);
+ for (size_t i = 0; i < length - 1; ++i)
+ builder.append(static_cast<UChar>(url[i]));
+ return builder.toString();
+}
diff --git a/Tools/TestWebKitAPI/config.h b/Tools/TestWebKitAPI/config.h
index 0fb19e1c3..c5ce18bc0 100644
--- a/Tools/TestWebKitAPI/config.h
+++ b/Tools/TestWebKitAPI/config.h
@@ -23,17 +23,14 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H
-#ifdef BUILDING_WITH_CMAKE
+#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H && defined(BUILDING_WITH_CMAKE)
#include "cmakeconfig.h"
-#else
-#include "autotoolsconfig.h"
-#endif
#endif
-#include <wtf/Platform.h>
-#include <wtf/ExportMacros.h>
#include <runtime/JSExportMacros.h>
+#ifndef BUILDING_JSCONLY__
+#include <WebCore/PlatformExportMacros.h>
+#endif
#if defined(__APPLE__) && __APPLE__
@@ -52,24 +49,24 @@
#endif
#if PLATFORM(WIN_CAIRO)
-#undef WTF_USE_CG
-#define WTF_USE_CAIRO 1
-#define WTF_USE_CURL 1
+#undef USE_CG
+#define USE_CAIRO 1
+#define USE_CURL 1
#ifndef _WINSOCKAPI_
#define _WINSOCKAPI_ // Prevent inclusion of winsock.h in windows.h
#endif
-#elif !OS(WINCE)
-#define WTF_USE_CG 1
-#undef WTF_USE_CAIRO
-#undef WTF_USE_CURL
+#else
+#define USE_CG 1
+#undef USE_CAIRO
+#undef USE_CURL
#endif
#endif // PLATFORM(WIN)
#include <stdint.h>
-#if !PLATFORM(IOS) && !PLATFORM(WIN) && !(PLATFORM(GTK) && !defined(BUILDING_WEBKIT2__))
-#include <WebKit2/WebKit2_C.h>
+#if !PLATFORM(IOS) && !PLATFORM(WIN) && !defined(BUILDING_JSCONLY__)
+#include <WebKit/WebKit2_C.h>
#endif
#ifdef __clang__
@@ -87,6 +84,13 @@
#pragma clang diagnostic pop
#endif
-#if PLATFORM(MAC) && defined(__OBJC__)
+#if PLATFORM(COCOA) && defined(__OBJC__)
+// FIXME: Get Cocoa tests working with CMake on Mac.
+#if !defined(BUILDING_WITH_CMAKE)
#import <WebKit/WebKit.h>
#endif
+#endif
+
+#if !PLATFORM(IOS) && !defined(BUILDING_JSCONLY__)
+#define WK_HAVE_C_SPI 1
+#endif
diff --git a/Tools/TestWebKitAPI/gtk/PlatformUtilitiesGtk.cpp b/Tools/TestWebKitAPI/gtk/PlatformUtilitiesGtk.cpp
index ee65dcab2..f7b231fcc 100644
--- a/Tools/TestWebKitAPI/gtk/PlatformUtilitiesGtk.cpp
+++ b/Tools/TestWebKitAPI/gtk/PlatformUtilitiesGtk.cpp
@@ -27,8 +27,8 @@
#include "PlatformUtilities.h"
#include <gtk/gtk.h>
-#include <wtf/gobject/GRefPtr.h>
-#include <wtf/gobject/GUniquePtr.h>
+#include <wtf/glib/GRefPtr.h>
+#include <wtf/glib/GUniquePtr.h>
namespace TestWebKitAPI {
namespace Util {
@@ -68,7 +68,7 @@ static char* getFilenameFromEnvironmentVariableAsUTF8(const char* variableName)
WKStringRef createInjectedBundlePath()
{
GUniquePtr<char> injectedBundlePath(getFilenameFromEnvironmentVariableAsUTF8("TEST_WEBKIT_API_WEBKIT2_INJECTED_BUNDLE_PATH"));
- GUniquePtr<char> injectedBundleFilename(g_build_filename(injectedBundlePath.get(), "libTestWebKitAPIInjectedBundle.la", nullptr));
+ GUniquePtr<char> injectedBundleFilename(g_build_filename(injectedBundlePath.get(), "libTestWebKitAPIInjectedBundle.so", nullptr));
return WKStringCreateWithUTF8CString(injectedBundleFilename.get());
}
diff --git a/Tools/TestWebKitAPI/gtk/PlatformWebViewGtk.cpp b/Tools/TestWebKitAPI/gtk/PlatformWebViewGtk.cpp
index 03160419e..0feb2b54a 100644
--- a/Tools/TestWebKitAPI/gtk/PlatformWebViewGtk.cpp
+++ b/Tools/TestWebKitAPI/gtk/PlatformWebViewGtk.cpp
@@ -27,18 +27,35 @@
#include "PlatformWebView.h"
#include <WebCore/GUniquePtrGtk.h>
+#include <WebKit/WKRetainPtr.h>
+#include <WebKit/WKView.h>
#include <gtk/gtk.h>
-#include <wtf/gobject/GUniquePtr.h>
+#include <wtf/glib/GUniquePtr.h>
namespace TestWebKitAPI {
PlatformWebView::PlatformWebView(WKContextRef contextRef, WKPageGroupRef pageGroupRef)
{
- m_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- m_view = WKViewCreate(contextRef, pageGroupRef);
- gtk_container_add(GTK_CONTAINER(m_window), GTK_WIDGET(m_view));
- gtk_widget_show(GTK_WIDGET(m_view));
- gtk_widget_show(m_window);
+ WKRetainPtr<WKPageConfigurationRef> configuration = adoptWK(WKPageConfigurationCreate());
+ WKPageConfigurationSetContext(configuration.get(), contextRef);
+ WKPageConfigurationSetPageGroup(configuration.get(), pageGroupRef);
+
+ initialize(configuration.get());
+}
+
+PlatformWebView::PlatformWebView(WKPageConfigurationRef configuration)
+{
+ initialize(configuration);
+}
+
+PlatformWebView::PlatformWebView(WKPageRef relatedPage)
+{
+ WKRetainPtr<WKPageConfigurationRef> configuration = adoptWK(WKPageConfigurationCreate());
+ WKPageConfigurationSetContext(configuration.get(), WKPageGetContext(relatedPage));
+ WKPageConfigurationSetPageGroup(configuration.get(), WKPageGetPageGroup(relatedPage));
+ WKPageConfigurationSetRelatedPage(configuration.get(), relatedPage);
+
+ initialize(configuration.get());
}
PlatformWebView::~PlatformWebView()
@@ -46,6 +63,15 @@ PlatformWebView::~PlatformWebView()
gtk_widget_destroy(m_window);
}
+void PlatformWebView::initialize(WKPageConfigurationRef configuration)
+{
+ m_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ m_view = WKViewCreate(configuration);
+ gtk_container_add(GTK_CONTAINER(m_window), GTK_WIDGET(m_view));
+ gtk_widget_show(GTK_WIDGET(m_view));
+ gtk_widget_show(m_window);
+}
+
WKPageRef PlatformWebView::page() const
{
return WKViewGetPage(m_view);
@@ -122,7 +148,7 @@ void PlatformWebView::simulateRightClick(unsigned x, unsigned y)
doMouseButtonEvent(viewWidget, GDK_BUTTON_RELEASE, x, y, 3);
}
-void PlatformWebView::simulateMouseMove(unsigned x, unsigned y)
+void PlatformWebView::simulateMouseMove(unsigned x, unsigned y, WKEventModifiers)
{
GUniquePtr<GdkEvent> event(gdk_event_new(GDK_MOTION_NOTIFY));
event->motion.x = x;
diff --git a/Tools/TestWebKitAPI/gtk/WebKit2Gtk/LoadTrackingTest.cpp b/Tools/TestWebKitAPI/gtk/WebKit2Gtk/LoadTrackingTest.cpp
index 211fa8b82..4a260b812 100644
--- a/Tools/TestWebKitAPI/gtk/WebKit2Gtk/LoadTrackingTest.cpp
+++ b/Tools/TestWebKitAPI/gtk/WebKit2Gtk/LoadTrackingTest.cpp
@@ -39,7 +39,7 @@ static void loadChangedCallback(WebKitWebView* webView, WebKitLoadEvent loadEven
break;
case WEBKIT_LOAD_COMMITTED: {
g_assert(webkit_web_view_is_loading(webView));
- g_assert_cmpstr(test->m_activeURI.data(), ==, webkit_web_view_get_uri(webView));
+ test->m_activeURI = webkit_web_view_get_uri(webView);
// Check that on committed we always have a main resource with a response.
WebKitWebResource* resource = webkit_web_view_get_main_resource(webView);
@@ -50,9 +50,15 @@ static void loadChangedCallback(WebKitWebView* webView, WebKitLoadEvent loadEven
break;
}
case WEBKIT_LOAD_FINISHED:
- g_assert(!webkit_web_view_is_loading(webView));
- if (!test->m_loadFailed)
+ if (!test->m_loadFailed) {
+ g_assert(!webkit_web_view_is_loading(webView));
g_assert_cmpstr(test->m_activeURI.data(), ==, webkit_web_view_get_uri(webView));
+ } else if (!g_error_matches(test->m_error.get(), WEBKIT_NETWORK_ERROR, WEBKIT_NETWORK_ERROR_CANCELLED)) {
+ // When a new load is started before the previous one has finished, we receive the load-finished signal
+ // of the ongoing load while we already have a provisional URL for the new load. This is the only case
+ // where isloading is true when the load has finished.
+ g_assert(!webkit_web_view_is_loading(webView));
+ }
test->loadFinished();
break;
default:
@@ -63,19 +69,24 @@ static void loadChangedCallback(WebKitWebView* webView, WebKitLoadEvent loadEven
static void loadFailedCallback(WebKitWebView* webView, WebKitLoadEvent loadEvent, const char* failingURI, GError* error, LoadTrackingTest* test)
{
test->m_loadFailed = true;
+
+ g_assert(error);
test->m_error.reset(g_error_copy(error));
+ if (!g_error_matches(error, WEBKIT_NETWORK_ERROR, WEBKIT_NETWORK_ERROR_CANCELLED)) {
+ // When a new load is started before the previous one has finished, we receive the load-failed signal
+ // of the ongoing load while we already have a provisional URL for the new load. This is the only case
+ // where is-loading is true when the load has failed.
+ g_assert(!webkit_web_view_is_loading(webView));
+ }
+
switch (loadEvent) {
case WEBKIT_LOAD_STARTED:
- g_assert(!webkit_web_view_is_loading(webView));
- g_assert_cmpstr(test->m_activeURI.data(), ==, webkit_web_view_get_uri(webView));
- g_assert(error);
+ g_assert_cmpstr(test->m_activeURI.data(), ==, failingURI);
test->provisionalLoadFailed(failingURI, error);
break;
case WEBKIT_LOAD_COMMITTED:
- g_assert(!webkit_web_view_is_loading(webView));
g_assert_cmpstr(test->m_activeURI.data(), ==, webkit_web_view_get_uri(webView));
- g_assert(error);
test->loadFailed(failingURI, error);
break;
default:
@@ -83,6 +94,16 @@ static void loadFailedCallback(WebKitWebView* webView, WebKitLoadEvent loadEvent
}
}
+static gboolean loadFailedWithTLSErrorsCallback(WebKitWebView* webView, const char* failingURI, GTlsCertificate* certificate, GTlsCertificateFlags tlsErrors, LoadTrackingTest* test)
+{
+ test->m_loadFailed = true;
+ g_assert(!webkit_web_view_is_loading(webView));
+ g_assert_cmpstr(test->m_activeURI.data(), ==, failingURI);
+ g_assert(G_IS_TLS_CERTIFICATE(certificate));
+ g_assert(tlsErrors);
+ return test->loadFailedWithTLSErrors(failingURI, certificate, tlsErrors);
+}
+
static void estimatedProgressChangedCallback(GObject*, GParamSpec*, LoadTrackingTest* test)
{
test->estimatedProgressChanged();
@@ -94,6 +115,7 @@ LoadTrackingTest::LoadTrackingTest()
{
g_signal_connect(m_webView, "load-changed", G_CALLBACK(loadChangedCallback), this);
g_signal_connect(m_webView, "load-failed", G_CALLBACK(loadFailedCallback), this);
+ g_signal_connect(m_webView, "load-failed-with-tls-errors", G_CALLBACK(loadFailedWithTLSErrorsCallback), this);
g_signal_connect(m_webView, "notify::estimated-load-progress", G_CALLBACK(estimatedProgressChangedCallback), this);
g_assert(!webkit_web_view_get_uri(m_webView));
@@ -143,6 +165,12 @@ void LoadTrackingTest::loadFailed(const gchar* failingURI, GError* error)
m_loadEvents.append(LoadFailed);
}
+bool LoadTrackingTest::loadFailedWithTLSErrors(const gchar* /*failingURI*/, GTlsCertificate*, GTlsCertificateFlags)
+{
+ m_loadEvents.append(LoadFailedWithTLSErrors);
+ return false;
+}
+
void LoadTrackingTest::estimatedProgressChanged()
{
double progress = webkit_web_view_get_estimated_load_progress(m_webView);
@@ -152,56 +180,57 @@ void LoadTrackingTest::estimatedProgressChanged()
void LoadTrackingTest::loadURI(const char* uri)
{
- m_loadEvents.clear();
- m_estimatedProgress = 0;
- m_error.reset();
+ reset();
WebViewTest::loadURI(uri);
}
void LoadTrackingTest::loadHtml(const char* html, const char* baseURI)
{
- m_loadEvents.clear();
- m_estimatedProgress = 0;
- m_error.reset();
+ reset();
WebViewTest::loadHtml(html, baseURI);
}
void LoadTrackingTest::loadPlainText(const char* plainText)
{
- m_loadEvents.clear();
- m_estimatedProgress = 0;
- m_error.reset();
+ reset();
WebViewTest::loadPlainText(plainText);
}
+void LoadTrackingTest::loadBytes(GBytes* bytes, const char* mimeType, const char* encoding, const char* baseURI)
+{
+ reset();
+ WebViewTest::loadBytes(bytes, mimeType, encoding, baseURI);
+}
+
void LoadTrackingTest::loadRequest(WebKitURIRequest* request)
{
- m_loadEvents.clear();
- m_estimatedProgress = 0;
- m_error.reset();
+ reset();
WebViewTest::loadRequest(request);
}
void LoadTrackingTest::reload()
{
- m_loadEvents.clear();
- m_estimatedProgress = 0;
- m_error.reset();
+ reset();
webkit_web_view_reload(m_webView);
}
void LoadTrackingTest::goBack()
{
- m_loadEvents.clear();
- m_estimatedProgress = 0;
- m_error.reset();
+ reset();
WebViewTest::goBack();
}
void LoadTrackingTest::goForward()
{
+ reset();
+ WebViewTest::goForward();
+}
+
+void LoadTrackingTest::reset()
+{
+ m_runLoadUntilCompletion = false;
+ m_loadFailed = false;
m_loadEvents.clear();
m_estimatedProgress = 0;
m_error.reset();
- WebViewTest::goForward();
}
diff --git a/Tools/TestWebKitAPI/gtk/WebKit2Gtk/LoadTrackingTest.h b/Tools/TestWebKitAPI/gtk/WebKit2Gtk/LoadTrackingTest.h
index d0ed1e57f..d6f3129b0 100644
--- a/Tools/TestWebKitAPI/gtk/WebKit2Gtk/LoadTrackingTest.h
+++ b/Tools/TestWebKitAPI/gtk/WebKit2Gtk/LoadTrackingTest.h
@@ -34,6 +34,7 @@ public:
virtual void provisionalLoadStarted();
virtual void provisionalLoadReceivedServerRedirect();
virtual void provisionalLoadFailed(const gchar* failingURI, GError*);
+ virtual bool loadFailedWithTLSErrors(const gchar* failingURI, GTlsCertificate*, GTlsCertificateFlags);
virtual void loadCommitted();
virtual void loadFinished();
virtual void loadFailed(const char* failingURI, GError*);
@@ -43,9 +44,11 @@ public:
void loadHtml(const char* html, const char* baseURI);
void loadPlainText(const char* plainText);
void loadRequest(WebKitURIRequest*);
+ void loadBytes(GBytes*, const char* mimeType, const char* encoding, const char* baseURI);
void reload();
void goBack();
void goForward();
+ void reset();
void setRedirectURI(const char* uri) { m_redirectURI = uri; }
@@ -55,7 +58,8 @@ public:
ProvisionalLoadFailed,
LoadCommitted,
LoadFinished,
- LoadFailed
+ LoadFailed,
+ LoadFailedWithTLSErrors
};
bool m_runLoadUntilCompletion;
bool m_loadFailed;
diff --git a/Tools/TestWebKitAPI/gtk/WebKit2Gtk/TestMain.cpp b/Tools/TestWebKitAPI/gtk/WebKit2Gtk/TestMain.cpp
index 61331a3d3..80809400d 100644
--- a/Tools/TestWebKitAPI/gtk/WebKit2Gtk/TestMain.cpp
+++ b/Tools/TestWebKitAPI/gtk/WebKit2Gtk/TestMain.cpp
@@ -22,12 +22,19 @@
#include <glib/gstdio.h>
#include <gtk/gtk.h>
-#include <webkit2/webkit2.h>
-#include <wtf/gobject/GUniquePtr.h>
+
+uint32_t Test::s_webExtensionID = 0;
void beforeAll();
void afterAll();
+static GUniquePtr<char> testDataDirectory(g_dir_make_tmp("WebKit2GtkTests-XXXXXX", nullptr));
+
+const char* Test::dataDirectory()
+{
+ return testDataDirectory.get();
+}
+
static void registerGResource(void)
{
GUniquePtr<char> resourcesPath(g_build_filename(WEBKIT_EXEC_PATH, "TestWebKitAPI", "WebKit2Gtk", "resources", "webkit2gtk-tests-resources.gresource", nullptr));
@@ -45,7 +52,10 @@ static void removeNonEmptyDirectory(const char* directoryPath)
const char* fileName;
while ((fileName = g_dir_read_name(directory))) {
GUniquePtr<char> filePath(g_build_filename(directoryPath, fileName, nullptr));
- g_unlink(filePath.get());
+ if (g_file_test(filePath.get(), G_FILE_TEST_IS_DIR))
+ removeNonEmptyDirectory(filePath.get());
+ else
+ g_unlink(filePath.get());
}
g_dir_close(directory);
g_rmdir(directoryPath);
@@ -66,15 +76,12 @@ int main(int argc, char** argv)
registerGResource();
- GUniquePtr<char> diskCacheTempDirectory(g_dir_make_tmp("WebKit2TestsDiskCache-XXXXXX", 0));
- g_assert(diskCacheTempDirectory.get());
- webkit_web_context_set_disk_cache_directory(webkit_web_context_get_default(), diskCacheTempDirectory.get());
-
beforeAll();
int returnValue = g_test_run();
afterAll();
- removeNonEmptyDirectory(diskCacheTempDirectory.get());
+ removeNonEmptyDirectory(testDataDirectory.get());
return returnValue;
}
+
diff --git a/Tools/TestWebKitAPI/gtk/WebKit2Gtk/TestMain.h b/Tools/TestWebKitAPI/gtk/WebKit2Gtk/TestMain.h
index 9fab0b2ff..f68af2a96 100644
--- a/Tools/TestWebKitAPI/gtk/WebKit2Gtk/TestMain.h
+++ b/Tools/TestWebKitAPI/gtk/WebKit2Gtk/TestMain.h
@@ -22,8 +22,10 @@
#include <cairo.h>
#include <glib-object.h>
+#include <webkit2/webkit2.h>
#include <wtf/HashSet.h>
-#include <wtf/gobject/GUniquePtr.h>
+#include <wtf/glib/GRefPtr.h>
+#include <wtf/glib/GUniquePtr.h>
#include <wtf/text/CString.h>
#define MAKE_GLIB_TEST_FIXTURE(ClassName) \
@@ -41,6 +43,25 @@
g_test_add(testPath.get(), ClassName, 0, ClassName::setUp, testFunc, ClassName::tearDown); \
}
+#define MAKE_GLIB_TEST_FIXTURE_WITH_SETUP_TEARDOWN(ClassName, setup, teardown) \
+ static void setUp(ClassName* fixture, gconstpointer data) \
+ { \
+ if (setup) \
+ setup(); \
+ new (fixture) ClassName; \
+ } \
+ static void tearDown(ClassName* fixture, gconstpointer data) \
+ { \
+ fixture->~ClassName(); \
+ if (teardown) \
+ teardown(); \
+ } \
+ static void add(const char* suiteName, const char* testName, void (*testFunc)(ClassName*, const void*)) \
+ { \
+ GUniquePtr<gchar> testPath(g_strdup_printf("/webkit2/%s/%s", suiteName, testName)); \
+ g_test_add(testPath.get(), ClassName, 0, ClassName::setUp, testFunc, ClassName::tearDown); \
+ }
+
#define ASSERT_CMP_CSTRING(s1, cmp, s2) \
do { \
CString __s1 = (s1); \
@@ -56,8 +77,33 @@ class Test {
public:
MAKE_GLIB_TEST_FIXTURE(Test);
+ static const char* dataDirectory();
+
+ static void initializeWebExtensionsCallback(WebKitWebContext* context, Test* test)
+ {
+ test->initializeWebExtensions();
+ }
+
+ Test()
+ {
+ GUniquePtr<char> localStorageDirectory(g_build_filename(dataDirectory(), "local-storage", nullptr));
+ GUniquePtr<char> indexedDBDirectory(g_build_filename(dataDirectory(), "indexeddb", nullptr));
+ GUniquePtr<char> diskCacheDirectory(g_build_filename(dataDirectory(), "disk-cache", nullptr));
+ GUniquePtr<char> applicationCacheDirectory(g_build_filename(dataDirectory(), "appcache", nullptr));
+ GUniquePtr<char> webSQLDirectory(g_build_filename(dataDirectory(), "websql", nullptr));
+ GRefPtr<WebKitWebsiteDataManager> websiteDataManager = adoptGRef(webkit_website_data_manager_new(
+ "local-storage-directory", localStorageDirectory.get(), "indexeddb-directory", indexedDBDirectory.get(),
+ "disk-cache-directory", diskCacheDirectory.get(), "offline-application-cache-directory", applicationCacheDirectory.get(),
+ "websql-directory", webSQLDirectory.get(), nullptr));
+
+ m_webContext = adoptGRef(webkit_web_context_new_with_website_data_manager(websiteDataManager.get()));
+ g_signal_connect(m_webContext.get(), "initialize-web-extensions", G_CALLBACK(initializeWebExtensionsCallback), this);
+ }
+
~Test()
{
+ g_signal_handlers_disconnect_matched(m_webContext.get(), G_SIGNAL_MATCH_DATA, 0, 0, nullptr, nullptr, this);
+ m_webContext = nullptr;
if (m_watchedObjects.isEmpty())
return;
@@ -70,6 +116,12 @@ public:
g_assert(m_watchedObjects.isEmpty());
}
+ virtual void initializeWebExtensions()
+ {
+ webkit_web_context_set_web_extensions_directory(m_webContext.get(), WEBKIT_TEST_WEB_EXTENSIONS_DIR);
+ webkit_web_context_set_web_extensions_initialization_user_data(m_webContext.get(), g_variant_new_uint32(++s_webExtensionID));
+ }
+
static void objectFinalized(Test* test, GObject* finalizedObject)
{
test->m_watchedObjects.remove(finalizedObject);
@@ -81,16 +133,24 @@ public:
g_object_weak_ref(object, reinterpret_cast<GWeakNotify>(objectFinalized), this);
}
- static CString getWebKit1TestResoucesDir()
- {
- GUniquePtr<char> resourcesDir(g_build_filename(WEBKIT_SRC_DIR, "Tools", "TestWebKitAPI", "Tests", "WebKitGtk", "resources", nullptr));
- return resourcesDir.get();
- }
- static CString getResourcesDir()
+ enum ResourcesDir {
+ WebKit2GTKResources,
+ WebKit2Resources,
+ };
+
+ static CString getResourcesDir(ResourcesDir resourcesDir = WebKit2GTKResources)
{
- GUniquePtr<char> resourcesDir(g_build_filename(WEBKIT_SRC_DIR, "Tools", "TestWebKitAPI", "Tests", "WebKit2Gtk", "resources", nullptr));
- return resourcesDir.get();
+ switch (resourcesDir) {
+ case WebKit2GTKResources: {
+ GUniquePtr<char> resourcesDir(g_build_filename(WEBKIT_SRC_DIR, "Tools", "TestWebKitAPI", "Tests", "WebKit2Gtk", "resources", nullptr));
+ return resourcesDir.get();
+ }
+ case WebKit2Resources: {
+ GUniquePtr<char> resourcesDir(g_build_filename(WEBKIT_SRC_DIR, "Tools", "TestWebKitAPI", "Tests", "WebKit2", nullptr));
+ return resourcesDir.get();
+ }
+ }
}
void addLogFatalFlag(unsigned flag)
@@ -119,6 +179,8 @@ public:
}
HashSet<GObject*> m_watchedObjects;
+ GRefPtr<WebKitWebContext> m_webContext;
+ static uint32_t s_webExtensionID;
};
#endif // TestMain_h
diff --git a/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestBus.cpp b/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestBus.cpp
index 35bcf1bd6..88456ce4f 100644
--- a/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestBus.cpp
+++ b/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestBus.cpp
@@ -20,53 +20,23 @@
#include "config.h"
#include "WebKitTestBus.h"
-#include <wtf/gobject/GUniquePtr.h>
-#include <wtf/text/WTFString.h>
-
WebKitTestBus::WebKitTestBus()
- : m_pid(-1)
+ : m_bus(adoptGRef(g_test_dbus_new(G_TEST_DBUS_NONE)))
{
}
-bool WebKitTestBus::run()
+WebKitTestBus::~WebKitTestBus()
{
- // FIXME: Use GTestDBus when we bump glib to 2.34.
- GUniquePtr<char> dbusLaunch(g_find_program_in_path("dbus-launch"));
- if (!dbusLaunch) {
- g_warning("Error starting DBUS daemon: dbus-launch not found in path");
- return false;
- }
-
- GUniqueOutPtr<char> output;
- GUniqueOutPtr<GError> error;
- if (!g_spawn_command_line_sync(dbusLaunch.get(), &output.outPtr(), 0, 0, &error.outPtr())) {
- g_warning("Error starting DBUS daemon: %s", error->message);
- return false;
- }
-
- String outputString = String::fromUTF8(output.get());
- Vector<String> lines;
- outputString.split(UChar('\n'), /* allowEmptyEntries */ false, lines);
- for (size_t i = 0; i < lines.size(); ++i) {
- char** keyValue = g_strsplit(lines[i].utf8().data(), "=", 2);
- g_assert_cmpuint(g_strv_length(keyValue), ==, 2);
- if (!g_strcmp0(keyValue[0], "DBUS_SESSION_BUS_ADDRESS")) {
- m_address = keyValue[1];
- g_setenv("DBUS_SESSION_BUS_ADDRESS", keyValue[1], TRUE);
- } else if (!g_strcmp0(keyValue[0], "DBUS_SESSION_BUS_PID"))
- m_pid = g_ascii_strtoll(keyValue[1], 0, 10);
- g_strfreev(keyValue);
- }
-
- return m_pid > 0;
+ g_test_dbus_down(m_bus.get());
}
-WebKitTestBus::~WebKitTestBus()
+bool WebKitTestBus::run()
{
- g_unsetenv("DBUS_SESSION_BUS_ADDRESS");
-
- if (m_pid != -1)
- kill(m_pid, SIGTERM);
+ CString display = g_getenv("DISPLAY");
+ g_test_dbus_up(m_bus.get());
+ m_address = g_test_dbus_get_bus_address(m_bus.get());
+ g_setenv("DISPLAY", display.data(), FALSE);
+ return !m_address.isNull();
}
GDBusConnection* WebKitTestBus::getOrCreateConnection()
@@ -77,7 +47,8 @@ GDBusConnection* WebKitTestBus::getOrCreateConnection()
g_assert(!m_address.isNull());
m_connection = adoptGRef(g_dbus_connection_new_for_address_sync(m_address.data(),
static_cast<GDBusConnectionFlags>(G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT | G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION),
- 0, 0, 0));
+ nullptr, nullptr, nullptr));
+ g_assert(m_connection.get());
return m_connection.get();
}
@@ -88,19 +59,19 @@ static void onNameAppeared(GDBusConnection*, const char*, const char*, gpointer
GDBusProxy* WebKitTestBus::createProxy(const char* serviceName, const char* objectPath, const char* interfaceName, GMainLoop* mainLoop)
{
- unsigned watcherID = g_bus_watch_name_on_connection(getOrCreateConnection(), serviceName, G_BUS_NAME_WATCHER_FLAGS_NONE, onNameAppeared, 0, mainLoop, 0);
+ unsigned watcherID = g_bus_watch_name_on_connection(getOrCreateConnection(), serviceName, G_BUS_NAME_WATCHER_FLAGS_NONE, onNameAppeared, nullptr, mainLoop, nullptr);
g_main_loop_run(mainLoop);
g_bus_unwatch_name(watcherID);
GDBusProxy* proxy = g_dbus_proxy_new_sync(
connection(),
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
- 0, // GDBusInterfaceInfo
+ nullptr, // GDBusInterfaceInfo
serviceName,
objectPath,
interfaceName,
- 0, // GCancellable
- 0);
+ nullptr, // GCancellable
+ nullptr);
g_assert(proxy);
return proxy;
}
diff --git a/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestBus.h b/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestBus.h
index b9f856b27..b8a8e6041 100644
--- a/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestBus.h
+++ b/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestBus.h
@@ -21,13 +21,13 @@
#define WebKitTestBus_h
#include <gio/gio.h>
-#include <wtf/gobject/GRefPtr.h>
+#include <wtf/glib/GRefPtr.h>
#include <wtf/text/CString.h>
class WebKitTestBus {
public:
WebKitTestBus();
- virtual ~WebKitTestBus();
+ ~WebKitTestBus();
bool run();
GDBusProxy* createProxy(const char* serviceName, const char* objectPath, const char* interfaceName, GMainLoop*);
@@ -36,7 +36,7 @@ public:
private:
GDBusConnection* getOrCreateConnection();
- pid_t m_pid;
+ GRefPtr<GTestDBus> m_bus;
CString m_address;
GRefPtr<GDBusConnection> m_connection;
};
diff --git a/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestServer.cpp b/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestServer.cpp
index 8736771fa..de9466c39 100644
--- a/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestServer.cpp
+++ b/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestServer.cpp
@@ -21,13 +21,19 @@
#include "WebKitTestServer.h"
#include "TestMain.h"
-#include <wtf/gobject/GUniquePtr.h>
+#include <wtf/Threading.h>
+#include <wtf/glib/GUniquePtr.h>
-WebKitTestServer::WebKitTestServer(ServerType type)
+WebKitTestServer::WebKitTestServer(ServerOptions options)
{
+ if (options & ServerRunInThread) {
+ WTF::initializeThreading();
+ m_queue = WorkQueue::create("WebKitTestServer");
+ }
+
GUniquePtr<char> sslCertificateFile;
GUniquePtr<char> sslKeyFile;
- if (type == ServerHTTPS) {
+ if (options & ServerHTTPS) {
CString resourcesDir = Test::getResourcesDir();
sslCertificateFile.reset(g_build_filename(resourcesDir.data(), "test-cert.pem", NULL));
sslKeyFile.reset(g_build_filename(resourcesDir.data(), "test-key.pem", NULL));
@@ -37,9 +43,10 @@ WebKitTestServer::WebKitTestServer(ServerType type)
soup_address_resolve_sync(address.get(), 0);
m_soupServer = adoptGRef(soup_server_new(SOUP_SERVER_INTERFACE, address.get(),
+ SOUP_SERVER_ASYNC_CONTEXT, m_queue ? m_queue->runLoop().mainContext() : nullptr,
SOUP_SERVER_SSL_CERT_FILE, sslCertificateFile.get(),
SOUP_SERVER_SSL_KEY_FILE, sslKeyFile.get(), nullptr));
- m_baseURI = type == ServerHTTPS ? soup_uri_new("https://127.0.0.1/") : soup_uri_new("http://127.0.0.1/");
+ m_baseURI = options & ServerHTTPS ? soup_uri_new("https://127.0.0.1/") : soup_uri_new("http://127.0.0.1/");
soup_uri_set_port(m_baseURI, soup_server_get_port(m_soupServer.get()));
}
@@ -50,8 +57,15 @@ WebKitTestServer::~WebKitTestServer()
void WebKitTestServer::run(SoupServerCallback serverCallback)
{
- soup_server_run_async(m_soupServer.get());
- soup_server_add_handler(m_soupServer.get(), 0, serverCallback, 0, 0);
+ if (m_queue) {
+ m_queue->dispatch([this, serverCallback] {
+ soup_server_run_async(m_soupServer.get());
+ soup_server_add_handler(m_soupServer.get(), nullptr, serverCallback, nullptr, nullptr);
+ });
+ } else {
+ soup_server_run_async(m_soupServer.get());
+ soup_server_add_handler(m_soupServer.get(), nullptr, serverCallback, nullptr, nullptr);
+ }
}
CString WebKitTestServer::getURIForPath(const char* path)
diff --git a/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestServer.h b/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestServer.h
index 502f7fad0..58f019fab 100644
--- a/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestServer.h
+++ b/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestServer.h
@@ -22,18 +22,20 @@
#include <libsoup/soup.h>
#include <webkit2/webkit2.h>
-#include <wtf/gobject/GRefPtr.h>
+#include <wtf/WorkQueue.h>
+#include <wtf/glib/GRefPtr.h>
#include <wtf/text/CString.h>
class WebKitTestServer {
public:
- enum ServerType {
- ServerHTTP,
- ServerHTTPS
+ enum ServerOptions {
+ ServerHTTP = 0,
+ ServerHTTPS = 1 << 1,
+ ServerRunInThread = 1 << 2,
};
- WebKitTestServer(ServerType = ServerHTTP);
+ WebKitTestServer(ServerOptions = ServerHTTP);
virtual ~WebKitTestServer();
SoupURI* baseURI() { return m_baseURI; }
@@ -44,6 +46,7 @@ public:
private:
GRefPtr<SoupServer> m_soupServer;
SoupURI* m_baseURI;
+ RefPtr<WorkQueue> m_queue;
};
#endif // WebKitTestServer_h
diff --git a/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebViewTest.cpp b/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebViewTest.cpp
index f08bb4694..7071910e4 100644
--- a/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebViewTest.cpp
+++ b/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebViewTest.cpp
@@ -24,15 +24,15 @@
#include <JavaScriptCore/JSRetainPtr.h>
#include <WebCore/GUniquePtrGtk.h>
+bool WebViewTest::shouldInitializeWebViewInConstructor = true;
+
WebViewTest::WebViewTest()
- : m_webView(WEBKIT_WEB_VIEW(g_object_ref_sink(webkit_web_view_new())))
- , m_mainLoop(g_main_loop_new(0, TRUE))
- , m_parentWindow(0)
- , m_javascriptResult(0)
- , m_resourceDataSize(0)
- , m_surface(0)
+ : m_userContentManager(adoptGRef(webkit_user_content_manager_new()))
+ , m_mainLoop(g_main_loop_new(nullptr, TRUE))
{
- assertObjectIsDeletedWhenTestFinishes(G_OBJECT(m_webView));
+ if (shouldInitializeWebViewInConstructor)
+ initializeWebView();
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(m_userContentManager.get()));
}
WebViewTest::~WebViewTest()
@@ -47,10 +47,31 @@ WebViewTest::~WebViewTest()
g_main_loop_unref(m_mainLoop);
}
+void WebViewTest::initializeWebView()
+{
+ g_assert(!m_webView);
+ m_webView = WEBKIT_WEB_VIEW(g_object_ref_sink(g_object_new(WEBKIT_TYPE_WEB_VIEW, "web-context", m_webContext.get(), "user-content-manager", m_userContentManager.get(), nullptr)));
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(m_webView));
+
+ g_signal_connect(m_webView, "web-process-crashed", G_CALLBACK(WebViewTest::webProcessCrashed), this);
+}
+
+gboolean WebViewTest::webProcessCrashed(WebKitWebView*, WebViewTest* test)
+{
+ if (test->m_expectedWebProcessCrash) {
+ test->m_expectedWebProcessCrash = false;
+ return FALSE;
+ }
+ g_assert_not_reached();
+ return TRUE;
+}
+
void WebViewTest::loadURI(const char* uri)
{
m_activeURI = uri;
webkit_web_view_load_uri(m_webView, uri);
+ g_assert(webkit_web_view_is_loading(m_webView));
+ g_assert_cmpstr(webkit_web_view_get_uri(m_webView), ==, m_activeURI.data());
}
void WebViewTest::loadHtml(const char* html, const char* baseURI)
@@ -60,29 +81,49 @@ void WebViewTest::loadHtml(const char* html, const char* baseURI)
else
m_activeURI = baseURI;
webkit_web_view_load_html(m_webView, html, baseURI);
+ g_assert(webkit_web_view_is_loading(m_webView));
+ g_assert_cmpstr(webkit_web_view_get_uri(m_webView), ==, m_activeURI.data());
}
void WebViewTest::loadPlainText(const char* plainText)
{
m_activeURI = "about:blank";
webkit_web_view_load_plain_text(m_webView, plainText);
+ g_assert(webkit_web_view_is_loading(m_webView));
+ g_assert_cmpstr(webkit_web_view_get_uri(m_webView), ==, m_activeURI.data());
+}
+
+void WebViewTest::loadBytes(GBytes* bytes, const char* mimeType, const char* encoding, const char* baseURI)
+{
+ if (!baseURI)
+ m_activeURI = "about:blank";
+ else
+ m_activeURI = baseURI;
+ webkit_web_view_load_bytes(m_webView, bytes, mimeType, encoding, baseURI);
+ g_assert(webkit_web_view_is_loading(m_webView));
+ g_assert_cmpstr(webkit_web_view_get_uri(m_webView), ==, m_activeURI.data());
}
void WebViewTest::loadRequest(WebKitURIRequest* request)
{
m_activeURI = webkit_uri_request_get_uri(request);
webkit_web_view_load_request(m_webView, request);
+ g_assert(webkit_web_view_is_loading(m_webView));
+ g_assert_cmpstr(webkit_web_view_get_uri(m_webView), ==, m_activeURI.data());
}
void WebViewTest::loadAlternateHTML(const char* html, const char* contentURI, const char* baseURI)
{
m_activeURI = contentURI;
webkit_web_view_load_alternate_html(m_webView, html, contentURI, baseURI);
+ g_assert(webkit_web_view_is_loading(m_webView));
+ g_assert_cmpstr(webkit_web_view_get_uri(m_webView), ==, m_activeURI.data());
}
void WebViewTest::goBack()
{
- if (webkit_web_view_can_go_back(m_webView)) {
+ bool canGoBack = webkit_web_view_can_go_back(m_webView);
+ if (canGoBack) {
WebKitBackForwardList* list = webkit_web_view_get_back_forward_list(m_webView);
WebKitBackForwardListItem* item = webkit_back_forward_list_get_nth_item(list, -1);
m_activeURI = webkit_back_forward_list_item_get_original_uri(item);
@@ -90,11 +131,16 @@ void WebViewTest::goBack()
// Call go_back even when can_go_back returns FALSE to check nothing happens.
webkit_web_view_go_back(m_webView);
+ if (canGoBack) {
+ g_assert(webkit_web_view_is_loading(m_webView));
+ g_assert_cmpstr(webkit_web_view_get_uri(m_webView), ==, m_activeURI.data());
+ }
}
void WebViewTest::goForward()
{
- if (webkit_web_view_can_go_forward(m_webView)) {
+ bool canGoForward = webkit_web_view_can_go_forward(m_webView);
+ if (canGoForward) {
WebKitBackForwardList* list = webkit_web_view_get_back_forward_list(m_webView);
WebKitBackForwardListItem* item = webkit_back_forward_list_get_nth_item(list, 1);
m_activeURI = webkit_back_forward_list_item_get_original_uri(item);
@@ -102,12 +148,18 @@ void WebViewTest::goForward()
// Call go_forward even when can_go_forward returns FALSE to check nothing happens.
webkit_web_view_go_forward(m_webView);
+ if (canGoForward) {
+ g_assert(webkit_web_view_is_loading(m_webView));
+ g_assert_cmpstr(webkit_web_view_get_uri(m_webView), ==, m_activeURI.data());
+ }
}
void WebViewTest::goToBackForwardListItem(WebKitBackForwardListItem* item)
{
m_activeURI = webkit_back_forward_list_item_get_original_uri(item);
webkit_web_view_go_to_back_forward_list_item(m_webView, item);
+ g_assert(webkit_web_view_is_loading(m_webView));
+ g_assert_cmpstr(webkit_web_view_get_uri(m_webView), ==, m_activeURI.data());
}
void WebViewTest::quitMainLoop()
@@ -122,15 +174,12 @@ void WebViewTest::quitMainLoopAfterProcessingPendingEvents()
quitMainLoop();
}
-static gboolean quitMainLoopIdleCallback(WebViewTest* test)
-{
- test->quitMainLoop();
- return FALSE;
-}
-
void WebViewTest::wait(double seconds)
{
- g_timeout_add_seconds(seconds, reinterpret_cast<GSourceFunc>(quitMainLoopIdleCallback), this);
+ g_timeout_add(seconds * 1000, [](gpointer userData) -> gboolean {
+ static_cast<WebViewTest*>(userData)->quitMainLoop();
+ return G_SOURCE_REMOVE;
+ }, this);
g_main_loop_run(m_mainLoop);
}
@@ -217,6 +266,16 @@ void WebViewTest::selectAll()
webkit_web_view_execute_editing_command(m_webView, "SelectAll");
}
+bool WebViewTest::isEditable()
+{
+ return webkit_web_view_is_editable(m_webView);
+}
+
+void WebViewTest::setEditable(bool editable)
+{
+ webkit_web_view_set_editable(m_webView, editable);
+}
+
static void resourceGetDataCallback(GObject* object, GAsyncResult* result, gpointer userData)
{
size_t dataSize;
@@ -274,6 +333,15 @@ void WebViewTest::clickMouseButton(int x, int y, unsigned button, unsigned mouse
doMouseButtonEvent(GDK_BUTTON_RELEASE, x, y, button, mouseModifiers);
}
+void WebViewTest::emitPopupMenuSignal()
+{
+ GtkWidget* viewWidget = GTK_WIDGET(m_webView);
+ g_assert(gtk_widget_get_realized(viewWidget));
+
+ gboolean handled;
+ g_signal_emit_by_name(viewWidget, "popup-menu", &handled);
+}
+
void WebViewTest::keyStroke(unsigned keyVal, unsigned keyModifiers)
{
g_assert(m_parentWindow);
diff --git a/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebViewTest.h b/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebViewTest.h
index 93a78a4d7..cfcc6c7dc 100644
--- a/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebViewTest.h
+++ b/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebViewTest.h
@@ -31,10 +31,14 @@ public:
WebViewTest();
virtual ~WebViewTest();
+ static bool shouldInitializeWebViewInConstructor;
+ void initializeWebView();
+
virtual void loadURI(const char* uri);
virtual void loadHtml(const char* html, const char* baseURI);
virtual void loadPlainText(const char* plainText);
virtual void loadRequest(WebKitURIRequest*);
+ virtual void loadBytes(GBytes*, const char* mimeType, const char* encoding, const char* baseURI);
void loadAlternateHTML(const char* html, const char* contentURI, const char* baseURI);
void goBack();
void goForward();
@@ -52,10 +56,15 @@ public:
void selectAll();
const char* mainResourceData(size_t& mainResourceDataSize);
+ bool isEditable();
+ void setEditable(bool);
+
void mouseMoveTo(int x, int y, unsigned mouseModifiers = 0);
void clickMouseButton(int x, int y, unsigned button = 1, unsigned mouseModifiers = 0);
void keyStroke(unsigned keyVal, unsigned keyModifiers = 0);
+ void emitPopupMenuSignal();
+
WebKitJavascriptResult* runJavaScriptAndWaitUntilFinished(const char* javascript, GError**);
WebKitJavascriptResult* runJavaScriptFromGResourceAndWaitUntilFinished(const char* resource, GError**);
@@ -70,16 +79,24 @@ public:
bool runWebProcessTest(const char* suiteName, const char* testName);
- WebKitWebView* m_webView;
+ // Prohibit overrides because this is called when the web view is created
+ // in our constructor, before a derived class's vtable is ready.
+ void initializeWebExtensions() final { Test::initializeWebExtensions(); }
+
+ static gboolean webProcessCrashed(WebKitWebView*, WebViewTest*);
+
+ GRefPtr<WebKitUserContentManager> m_userContentManager;
+ WebKitWebView* m_webView { nullptr };
GMainLoop* m_mainLoop;
CString m_activeURI;
- GtkWidget* m_parentWindow;
+ GtkWidget* m_parentWindow { nullptr };
CString m_expectedTitle;
- WebKitJavascriptResult* m_javascriptResult;
- GError** m_javascriptError;
- GUniquePtr<char> m_resourceData;
- size_t m_resourceDataSize;
- cairo_surface_t* m_surface;
+ WebKitJavascriptResult* m_javascriptResult { nullptr };
+ GError** m_javascriptError { nullptr };
+ GUniquePtr<char> m_resourceData { nullptr };
+ size_t m_resourceDataSize { 0 };
+ cairo_surface_t* m_surface { nullptr };
+ bool m_expectedWebProcessCrash { false };
private:
void doMouseButtonEvent(GdkEventType, int, int, unsigned, unsigned);
diff --git a/Tools/TestWebKitAPI/gtk/main.cpp b/Tools/TestWebKitAPI/gtk/main.cpp
index 1b7fef64f..2c6856595 100644
--- a/Tools/TestWebKitAPI/gtk/main.cpp
+++ b/Tools/TestWebKitAPI/gtk/main.cpp
@@ -32,5 +32,5 @@ int main(int argc, char** argv)
{
gtk_init(&argc, &argv);
- return TestWebKitAPI::TestsController::shared().run(argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE;
+ return TestWebKitAPI::TestsController::singleton().run(argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE;
}
diff --git a/Tools/TestWebKitAPI/jsconly/PlatformUtilitiesJSCOnly.cpp b/Tools/TestWebKitAPI/jsconly/PlatformUtilitiesJSCOnly.cpp
new file mode 100644
index 000000000..41dc6b920
--- /dev/null
+++ b/Tools/TestWebKitAPI/jsconly/PlatformUtilitiesJSCOnly.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 Yusuke Suzuki <utatane.tea@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PlatformUtilities.h"
+
+#include <wtf/CurrentTime.h>
+#include <wtf/RunLoop.h>
+
+#if USE(GLIB_EVENT_LOOP)
+#include <glib.h>
+#include <wtf/glib/GRefPtr.h>
+#endif
+
+namespace TestWebKitAPI {
+namespace Util {
+
+void run(bool* done)
+{
+ while (!*done) {
+#if USE(GLIB_EVENT_LOOP)
+ g_main_context_iteration(RunLoop::current().mainContext(), false);
+#else
+ WTF::RunLoop::iterate();
+#endif
+ }
+}
+
+void sleep(double seconds)
+{
+ WTF::sleep(seconds);
+}
+
+} // namespace Util
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/jsconly/main.cpp b/Tools/TestWebKitAPI/jsconly/main.cpp
new file mode 100644
index 000000000..22b12cf4b
--- /dev/null
+++ b/Tools/TestWebKitAPI/jsconly/main.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 Yusuke Suzuki <utatane.tea@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "TestsController.h"
+
+int main(int argc, char** argv)
+{
+ return TestWebKitAPI::TestsController::singleton().run(argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/Tools/WebKitTestRunner/CMakeLists.txt b/Tools/WebKitTestRunner/CMakeLists.txt
new file mode 100644
index 000000000..fb7d52339
--- /dev/null
+++ b/Tools/WebKitTestRunner/CMakeLists.txt
@@ -0,0 +1,121 @@
+set(WEBKIT_TESTRUNNER_DIR "${TOOLS_DIR}/WebKitTestRunner")
+set(WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR "${TOOLS_DIR}/WebKitTestRunner/InjectedBundle")
+set(WEBKIT_TESTRUNNER_SHARED_DIR "${TOOLS_DIR}/TestRunnerShared/")
+set(WEBKIT_TESTRUNNER_UISCRIPTCONTEXT_DIR "${WEBKIT_TESTRUNNER_SHARED_DIR}/UIScriptContext")
+set(WEBKIT_TESTRUNNER_BINDINGS_DIR "${WEBKIT_TESTRUNNER_SHARED_DIR}/Bindings")
+
+file(MAKE_DIRECTORY ${DERIVED_SOURCES_DIR}/InjectedBundle)
+file(MAKE_DIRECTORY ${DERIVED_SOURCES_DIR}/UIScriptContext)
+
+set(WebKitTestRunner_SOURCES
+ ${WEBKIT_TESTRUNNER_DIR}/CyclicRedundancyCheck.cpp
+ ${WEBKIT_TESTRUNNER_DIR}/GeolocationProviderMock.cpp
+ ${WEBKIT_TESTRUNNER_DIR}/Options.cpp
+ ${WEBKIT_TESTRUNNER_DIR}/PixelDumpSupport.cpp
+ ${WEBKIT_TESTRUNNER_DIR}/TestController.cpp
+ ${WEBKIT_TESTRUNNER_DIR}/TestInvocation.cpp
+ ${WEBKIT_TESTRUNNER_DIR}/TestOptions.cpp
+ ${WEBKIT_TESTRUNNER_DIR}/WebNotificationProvider.cpp
+ ${WEBKIT_TESTRUNNER_DIR}/WorkQueueManager.cpp
+ ${WEBKIT_TESTRUNNER_UISCRIPTCONTEXT_DIR}/UIScriptContext.cpp
+ ${WEBKIT_TESTRUNNER_UISCRIPTCONTEXT_DIR}/UIScriptController.cpp
+ ${WEBKIT_TESTRUNNER_BINDINGS_DIR}/JSWrapper.cpp
+)
+
+set(WebKitTestRunner_LIBRARIES
+ JavaScriptCore
+ WebCoreTestSupport
+ WebKit2
+)
+
+set(WebKitTestRunner_INCLUDE_DIRECTORIES
+ ${WEBKIT_TESTRUNNER_DIR}
+ ${WEBKIT_TESTRUNNER_DIR}/InjectedBundle
+ ${WEBKIT_TESTRUNNER_DIR}/InjectedBundle/Bindings
+ ${WEBKIT_TESTRUNNER_DIR}/InjectedBundle/atk
+ ${WEBKIT_TESTRUNNER_UISCRIPTCONTEXT_DIR}
+ ${WEBKIT_TESTRUNNER_BINDINGS_DIR}
+ ${WEBCORE_DIR}/testing/js
+ ${WEBKIT2_DIR}/Platform/IPC
+ ${WEBKIT2_DIR}/Shared
+ ${WEBKIT2_DIR}/Shared/API/c
+ ${WEBKIT2_DIR}/Shared/Plugins
+ ${WEBKIT2_DIR}/UIProcess
+ ${WEBKIT2_DIR}/UIProcess/API/C/soup
+ ${WEBKIT2_DIR}/WebProcess/InjectedBundle
+ ${WEBKIT2_DIR}/WebProcess/InjectedBundle/API/c
+ ${DERIVED_SOURCES_DIR}/InjectedBundle
+ ${DERIVED_SOURCES_DIR}/UIScriptContext
+ ${CMAKE_SOURCE_DIR}/Source
+)
+
+set(WebKitTestRunner_SYSTEM_INCLUDE_DIRECTORIES
+ ${LIBSOUP_INCLUDE_DIRS}
+ ${ICU_INCLUDE_DIRS}
+)
+
+set(WebKitTestRunnerInjectedBundle_SOURCES
+ ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/AccessibilityController.cpp
+ ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/AccessibilityTextMarker.cpp
+ ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/AccessibilityTextMarkerRange.cpp
+ ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/AccessibilityUIElement.cpp
+ ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/EventSendingController.cpp
+ ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/GCController.cpp
+ ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/InjectedBundle.cpp
+ ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/InjectedBundleMain.cpp
+ ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/InjectedBundlePage.cpp
+ ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/TestRunner.cpp
+ ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/TextInputController.cpp
+
+ ${WEBKIT_TESTRUNNER_BINDINGS_DIR}/JSWrapper.cpp
+)
+
+set(WebKitTestRunnerInjectedBundle_IDL_FILES
+ "${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/Bindings/AccessibilityController.idl"
+ "${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/Bindings/AccessibilityTextMarker.idl"
+ "${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/Bindings/AccessibilityTextMarkerRange.idl"
+ "${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/Bindings/AccessibilityUIElement.idl"
+ "${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/Bindings/EventSendingController.idl"
+ "${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/Bindings/GCController.idl"
+ "${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/Bindings/TestRunner.idl"
+ "${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/Bindings/TextInputController.idl"
+)
+
+set(WebKitTestRunner_IDL_FILES
+ "${WEBKIT_TESTRUNNER_UISCRIPTCONTEXT_DIR}/Bindings/UIScriptController.idl"
+)
+
+GENERATE_BINDINGS(WebKitTestRunnerInjectedBundleBindings
+ OUTPUT_SOURCE WebKitTestRunnerInjectedBundle_SOURCES
+ INPUT_FILES ${WebKitTestRunnerInjectedBundle_IDL_FILES}
+ BASE_DIR ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/Bindings
+ IDL_INCLUDES ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/Bindings
+ FEATURES ${FEATURE_DEFINES_WITH_SPACE_SEPARATOR}
+ DESTINATION ${DERIVED_SOURCES_DIR}/InjectedBundle
+ GENERATOR TestRunner)
+
+GENERATE_BINDINGS(WebKitTestRunnerBindings
+ OUTPUT_SOURCE WebKitTestRunner_SOURCES
+ INPUT_FILES ${WebKitTestRunner_IDL_FILES}
+ BASE_DIR ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/Bindings
+ IDL_INCLUDES ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/Bindings
+ FEATURES ${FEATURE_DEFINES_WITH_SPACE_SEPARATOR}
+ DESTINATION ${DERIVED_SOURCES_DIR}/UIScriptContext
+ GENERATOR TestRunner)
+
+WEBKIT_INCLUDE_CONFIG_FILES_IF_EXISTS()
+
+include_directories(${WebKitTestRunner_INCLUDE_DIRECTORIES})
+include_directories(SYSTEM ${WebKitTestRunner_SYSTEM_INCLUDE_DIRECTORIES})
+
+add_library(TestRunnerInjectedBundle SHARED ${WebKitTestRunnerInjectedBundle_SOURCES})
+target_link_libraries(TestRunnerInjectedBundle ${WebKitTestRunner_LIBRARIES})
+add_dependencies(TestRunnerInjectedBundle WebKitTestRunnerInjectedBundleBindings)
+
+add_executable(WebKitTestRunner ${WebKitTestRunner_SOURCES})
+target_link_libraries(WebKitTestRunner ${WebKitTestRunner_LIBRARIES})
+add_dependencies(WebKitTestRunner WebKitTestRunnerBindings)
+
+if (NOT APPLE)
+ add_dependencies(WebKit2 ${ForwardingHeadersForWebKitTestRunner_NAME})
+endif () \ No newline at end of file
diff --git a/Tools/WebKitTestRunner/DerivedSources.make b/Tools/WebKitTestRunner/DerivedSources.make
new file mode 100644
index 000000000..4a2b1790f
--- /dev/null
+++ b/Tools/WebKitTestRunner/DerivedSources.make
@@ -0,0 +1,62 @@
+# Copyright (C) 2010 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+VPATH = \
+ $(WebKitTestRunner)/InjectedBundle/Bindings \
+ $(WebKitTestRunner)/../TestRunnerShared/UIScriptContext/Bindings \
+#
+
+INJECTED_BUNDLE_INTERFACES = \
+ AccessibilityController \
+ AccessibilityTextMarker \
+ AccessibilityTextMarkerRange \
+ AccessibilityUIElement \
+ EventSendingController \
+ GCController \
+ TestRunner \
+ TextInputController \
+#
+
+UICONTEXT_INTERFACES = \
+ UIScriptController \
+#
+
+SCRIPTS = \
+ $(WebCoreScripts)/CodeGenerator.pm \
+ $(WebKitTestRunner)/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm \
+ $(WebCoreScripts)/IDLParser.pm \
+ $(WebCoreScripts)/generate-bindings.pl \
+#
+
+.PHONY : all
+
+JS%.h JS%.cpp : %.idl $(SCRIPTS)
+ @echo Generating bindings for $*...
+ @perl -I $(WebCoreScripts) -I $(WebKitTestRunner)/InjectedBundle/Bindings -I $(WebKitTestRunner)/UIScriptContext/Bindings $(WebCoreScripts)/generate-bindings.pl --defines "" --include InjectedBundle/Bindings --include UIScriptContext/Bindings --outputDir . --generator TestRunner $<
+
+all : \
+ $(INJECTED_BUNDLE_INTERFACES:%=JS%.h) \
+ $(INJECTED_BUNDLE_INTERFACES:%=JS%.cpp) \
+ $(UICONTEXT_INTERFACES:%=JS%.h) \
+ $(UICONTEXT_INTERFACES:%=JS%.cpp) \
+#
diff --git a/Tools/WebKitTestRunner/EventSenderProxy.h b/Tools/WebKitTestRunner/EventSenderProxy.h
index db2c58b0d..70d94014c 100644
--- a/Tools/WebKitTestRunner/EventSenderProxy.h
+++ b/Tools/WebKitTestRunner/EventSenderProxy.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2014 Apple Inc. All rights reserved.
* Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
*
* Redistribution and use in source and binary forms, with or without
@@ -29,6 +29,7 @@
#include <wtf/Deque.h>
#include <wtf/HashMap.h>
+#include <wtf/RetainPtr.h>
#include <wtf/Vector.h>
#if PLATFORM(GTK)
@@ -36,7 +37,11 @@
#include <gdk/gdk.h>
#include <wtf/HashSet.h>
#elif PLATFORM(EFL)
-#include <WebKit2/EWebKit2.h>
+#include "EWebKit2.h"
+#endif
+
+#if PLATFORM(COCOA)
+OBJC_CLASS NSEvent;
#endif
namespace WTR {
@@ -58,8 +63,15 @@ public:
void mouseDown(unsigned button, WKEventModifiers);
void mouseUp(unsigned button, WKEventModifiers);
+ void mouseForceDown();
+ void mouseForceUp();
+ void mouseForceChanged(float);
+ void mouseForceClick();
+ void startAndCancelMouseForceClick();
void mouseMoveTo(double x, double y);
void mouseScrollBy(int x, int y);
+ void mouseScrollByWithWheelAndMomentumPhases(int x, int y, int phase, int momentum);
+ void swipeGestureWithWheelAndMomentumPhases(int x, int y, int phase, int momentum);
void continuousMouseScrollBy(int x, int y, bool paged);
void leapForward(int milliseconds);
@@ -91,8 +103,17 @@ private:
void replaySavedEvents();
#endif
+ void sendMouseDownToStartPressureEvents();
+#if PLATFORM(COCOA)
+ enum class PressureChangeDirection { Increasing, Decreasing };
+ RetainPtr<NSEvent> beginPressureEvent(int stage);
+ RetainPtr<NSEvent> pressureChangeEvent(int stage, PressureChangeDirection);
+ RetainPtr<NSEvent> pressureChangeEvent(int stage, float pressure, PressureChangeDirection);
+#endif
+
#if PLATFORM(GTK)
void sendOrQueueEvent(GdkEvent*);
+ void dispatchEvent(GdkEvent*);
GdkEvent* createMouseButtonEvent(GdkEventType, unsigned button, WKEventModifiers);
GUniquePtr<GdkEvent> createTouchEvent(GdkEventType, int id);
void sendUpdatedTouchEvents();
@@ -111,7 +132,7 @@ private:
double m_clickTime;
WKPoint m_clickPosition;
WKEventMouseButton m_clickButton;
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
int eventNumber;
#elif PLATFORM(GTK)
Deque<WTREventQueueItem> m_eventQueue;
diff --git a/Tools/WebKitTestRunner/FontWithFeatures.otf b/Tools/WebKitTestRunner/FontWithFeatures.otf
new file mode 100644
index 000000000..3e5069995
--- /dev/null
+++ b/Tools/WebKitTestRunner/FontWithFeatures.otf
Binary files differ
diff --git a/Tools/WebKitTestRunner/FontWithFeatures.ttf b/Tools/WebKitTestRunner/FontWithFeatures.ttf
new file mode 100644
index 000000000..42c332a13
--- /dev/null
+++ b/Tools/WebKitTestRunner/FontWithFeatures.ttf
Binary files differ
diff --git a/Tools/WebKitTestRunner/GNUmakefile.am b/Tools/WebKitTestRunner/GNUmakefile.am
deleted file mode 100644
index 28a2d5747..000000000
--- a/Tools/WebKitTestRunner/GNUmakefile.am
+++ /dev/null
@@ -1,175 +0,0 @@
-
-stamp-webkittestrunner-forwarding-headers: $(WebKit2)/Scripts/generate-forwarding-headers.pl $(Programs_WebKitTestRunner_SOURCES) $(Libraries_libTestRunnerInjectedBundle_la_SOURCES)
- $(AM_V_GEN)$(PERL) $< $(srcdir)/Tools/WebKitTestRunner $(GENSOURCES_WEBKIT2)/include gtk \
- && echo timestamp > $(@F)
-
-BUILT_SOURCES += $(top_builddir)/stamp-webkittestrunner-forwarding-headers
-
-if ENABLE_WEBKIT2
-noinst_PROGRAMS += \
- Programs/WebKitTestRunner
-endif
-
-Programs_WebKitTestRunner_SOURCES = \
- Tools/WebKitTestRunner/EventSenderProxy.h \
- Tools/WebKitTestRunner/gtk/main.cpp \
- Tools/WebKitTestRunner/gtk/EventSenderProxyGtk.cpp \
- Tools/WebKitTestRunner/gtk/PlatformWebViewGtk.cpp \
- Tools/WebKitTestRunner/gtk/TestControllerGtk.cpp \
- Tools/WebKitTestRunner/cairo/TestInvocationCairo.cpp \
- Tools/WebKitTestRunner/CyclicRedundancyCheck.cpp \
- Tools/WebKitTestRunner/CyclicRedundancyCheck.h \
- Tools/WebKitTestRunner/GeolocationProviderMock.cpp \
- Tools/WebKitTestRunner/GeolocationProviderMock.h \
- Tools/WebKitTestRunner/Options.cpp \
- Tools/WebKitTestRunner/Options.h \
- Tools/WebKitTestRunner/PixelDumpSupport.cpp \
- Tools/WebKitTestRunner/PixelDumpSupport.h \
- Tools/WebKitTestRunner/PlatformWebView.h \
- Tools/WebKitTestRunner/StringFunctions.h \
- Tools/WebKitTestRunner/TestController.cpp \
- Tools/WebKitTestRunner/TestController.h \
- Tools/WebKitTestRunner/TestInvocation.cpp \
- Tools/WebKitTestRunner/TestInvocation.h \
- Tools/WebKitTestRunner/WebNotificationProvider.cpp \
- Tools/WebKitTestRunner/WebNotificationProvider.h \
- Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h \
- Tools/WebKitTestRunner/WorkQueueManager.cpp \
- Tools/WebKitTestRunner/WorkQueueManager.h
-
-Programs_WebKitTestRunner_CPPFLAGS = \
- -include Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h \
- -I$(srcdir)/Tools/WebKitTestRunner \
- -I$(srcdir)/Source/WebCore/platform/gtk \
- -I$(top_builddir)/DerivedSources/WebKit2/include \
- $(global_cppflags) \
- $(javascriptcore_cppflags) \
- $(webcore_cppflags) \
- $(CAIRO_CFLAGS) \
- $(GTK_CFLAGS) \
- $(LIBSOUP_CFLAGS)
-Programs_WebKitTestRunner_CXXFLAGS = $(global_cxxflags)
-Programs_WebKitTestRunner_CFLAGS = $(global_cflags)
-
-Programs_WebKitTestRunner_LDADD = \
- libjavascriptcoregtk-@WEBKITGTK_API_MAJOR_VERSION@.@WEBKITGTK_API_MINOR_VERSION@.la \
- libwebkit2gtk-@WEBKITGTK_API_MAJOR_VERSION@.@WEBKITGTK_API_MINOR_VERSION@.la \
- $(CAIRO_LIBS) \
- $(GTK_LIBS) \
- $(GLIB_LIBS) \
- $(LIBSOUP_LIBS) \
- $(FREETYPE_LIBS) \
- $(WINMM_LIBS) \
- $(XRENDER_LIBS) \
- $(XT_LIBS)
-
-Programs_WebKitTestRunner_LDFLAGS = \
- -no-install
-
-# The InjectedBundle library allows the render process to load harness code.
-if ENABLE_WEBKIT2
-noinst_LTLIBRARIES += Libraries/libTestRunnerInjectedBundle.la
-endif
-
-webkittestrunner_built_sources += \
- DerivedSources/InjectedBundle/JSAccessibilityController.cpp \
- DerivedSources/InjectedBundle/JSAccessibilityTextMarker.cpp \
- DerivedSources/InjectedBundle/JSAccessibilityTextMarkerRange.cpp \
- DerivedSources/InjectedBundle/JSAccessibilityUIElement.cpp \
- DerivedSources/InjectedBundle/JSEventSendingController.cpp \
- DerivedSources/InjectedBundle/JSGCController.cpp \
- DerivedSources/InjectedBundle/JSTestRunner.cpp \
- DerivedSources/InjectedBundle/JSTextInputController.cpp
-nodist_Libraries_libTestRunnerInjectedBundle_la_SOURCES = $(webkittestrunner_built_sources)
-BUILT_SOURCES += $(webkittestrunner_built_sources)
-
-Libraries_libTestRunnerInjectedBundle_la_SOURCES = \
- Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.cpp \
- Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.h \
- Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarker.cpp \
- Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarker.h \
- Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarkerRange.cpp \
- Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarkerRange.h \
- Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp \
- Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h \
- Tools/WebKitTestRunner/InjectedBundle/ActivateFonts.h \
- Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityControllerAtk.cpp \
- Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.cpp \
- Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.h \
- Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp \
- Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrappable.h \
- Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.cpp \
- Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.h \
- Tools/WebKitTestRunner/InjectedBundle/EventSendingController.cpp \
- Tools/WebKitTestRunner/InjectedBundle/EventSendingController.h \
- Tools/WebKitTestRunner/InjectedBundle/GCController.cpp \
- Tools/WebKitTestRunner/InjectedBundle/GCController.h \
- Tools/WebKitTestRunner/InjectedBundle/gtk/ActivateFontsGtk.cpp \
- Tools/WebKitTestRunner/InjectedBundle/gtk/InjectedBundleGtk.cpp \
- Tools/WebKitTestRunner/InjectedBundle/gtk/InjectedBundleUtilities.cpp \
- Tools/WebKitTestRunner/InjectedBundle/gtk/InjectedBundleUtilities.h \
- Tools/WebKitTestRunner/InjectedBundle/gtk/TestRunnerGtk.cpp \
- Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp \
- Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h \
- Tools/WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp \
- Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp \
- Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h \
- Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp \
- Tools/WebKitTestRunner/InjectedBundle/TestRunner.h \
- Tools/WebKitTestRunner/InjectedBundle/TextInputController.cpp \
- Tools/WebKitTestRunner/InjectedBundle/TextInputController.h
-
-Libraries_libTestRunnerInjectedBundle_la_LIBADD = \
- libWebCoreInternals.la
-
-Libraries_libTestRunnerInjectedBundle_la_LDFLAGS = \
- -rpath ${shell pwd}/$(top_builddir)/../unix/TestNetscapePlugin/.libs \
- $(no_undefined) \
- -avoid-version \
- -module
-
-Libraries_libTestRunnerInjectedBundle_la_CPPFLAGS = \
- -DFONTS_CONF_DIR=\"${shell pwd}/${srcdir}/Tools/DumpRenderTree/gtk/fonts\" \
- -DTOP_LEVEL_DIR=\"${shell pwd}/${srcdir}\" \
- -include Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h \
- -I$(srcdir)/Tools/WebKitTestRunner \
- -I$(srcdir)/Tools/WebKitTestRunner/InjectedBundle \
- -I$(srcdir)/Tools/WebKitTestRunner/InjectedBundle/Bindings \
- -I$(srcdir)/Tools/WebKitTestRunner/InjectedBundle/atk \
- -I$(srcdir)/Source/WebCore/testing/js \
- -I$(top_builddir)/DerivedSources/InjectedBundle \
- -I$(top_builddir)/DerivedSources/WebKit2/include \
- $(global_cppflags) \
- $(javascriptcore_cppflags) \
- $(webcore_cppflags) \
- $(CAIRO_CFLAGS) \
- $(GLIB_CFLAGS) \
- $(GTK_CFLAGS) \
- $(LIBSOUP_CFLAGS)
-Libraries_libTestRunnerInjectedBundle_la_CXXFLAGS = $(global_cxxflags)
-Libraries_libTestRunnerInjectedBundle_la_CFLAGS = $(global_cflags)
-
-code_generation_dependencies = \
- Tools/WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm \
- Source/WebCore/bindings/scripts/CodeGenerator.pm \
- Source/WebCore/bindings/scripts/IDLParser.pm \
- Source/WebCore/bindings/scripts/InFilesParser.pm \
- Source/WebCore/bindings/scripts/generate-bindings.pl
-
-DerivedSources/InjectedBundle/JS%.cpp: Tools/WebKitTestRunner/InjectedBundle/Bindings/%.idl $(code_generation_dependencies)
- $(AM_V_GEN)$(PERL) \
- -I $(srcdir)/Source/WebCore/bindings/scripts \
- -I $(srcdir)/Tools/WebKitTestRunner/InjectedBundle/Bindings \
- $(srcdir)/Source/WebCore/bindings/scripts/generate-bindings.pl \
- --defines "$(feature_defines)" --generator TestRunner \
- --include $(srcdir)/Tools/InjectedBundle/Bindings \
- --outputDir $(top_builddir)/DerivedSources/InjectedBundle \
- $<
-
-EXTRA_DIST += \
- $(srcdir)/Tools/WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm \
- $(srcdir)/Source/WebCore/bindings/scripts/CodeGenerator.pm \
- $(srcdir)/Source/WebCore/bindings/scripts/IDLParser.pm \
- $(srcdir)/Source/WebCore/bindings/scripts/InFilesParser.pm \
- $(srcdir)/Source/WebCore/bindings/scripts/generate-bindings.pl \
- $(shell ls $(srcdir)/Tools/WebKitTestRunner/InjectedBundle/Bindings/*.idl)
diff --git a/Tools/WebKitTestRunner/GeolocationProviderMock.cpp b/Tools/WebKitTestRunner/GeolocationProviderMock.cpp
index 9120258c7..ad4164966 100644
--- a/Tools/WebKitTestRunner/GeolocationProviderMock.cpp
+++ b/Tools/WebKitTestRunner/GeolocationProviderMock.cpp
@@ -26,7 +26,7 @@
#include "config.h"
#include "GeolocationProviderMock.h"
-#include <WebKit2/WKGeolocationManager.h>
+#include <WebKit/WKGeolocationManager.h>
#include <string.h>
#include <wtf/Assertions.h>
#include <wtf/CurrentTime.h>
@@ -52,7 +52,7 @@ GeolocationProviderMock::GeolocationProviderMock(WKContextRef context)
m_geolocationManager = WKContextGetGeolocationManager(context);
WKGeolocationProviderV1 providerCallback;
- memset(&providerCallback, 0, sizeof(WKGeolocationProvider));
+ memset(&providerCallback, 0, sizeof(WKGeolocationProviderV1));
providerCallback.base.version = 1;
providerCallback.base.clientInfo = this;
providerCallback.startUpdating = startUpdatingCallback;
diff --git a/Tools/WebKitTestRunner/GeolocationProviderMock.h b/Tools/WebKitTestRunner/GeolocationProviderMock.h
index ff5537e46..802223ec3 100644
--- a/Tools/WebKitTestRunner/GeolocationProviderMock.h
+++ b/Tools/WebKitTestRunner/GeolocationProviderMock.h
@@ -26,7 +26,7 @@
#ifndef GeolocationProviderMock_h
#define GeolocationProviderMock_h
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKRetainPtr.h>
namespace WTR {
@@ -41,6 +41,8 @@ public:
void startUpdating(WKGeolocationManagerRef);
void stopUpdating(WKGeolocationManagerRef);
+ bool isActive() const { return m_isActive; }
+
private:
void sendPositionIfNeeded();
void sendErrorIfNeeded();
diff --git a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.cpp b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.cpp
index f5d1bd58b..0a130d4e8 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.cpp
+++ b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.cpp
@@ -32,15 +32,15 @@
#include "JSAccessibilityController.h"
#include <JavaScriptCore/JSRetainPtr.h>
-#include <WebKit2/WKBundle.h>
-#include <WebKit2/WKBundlePage.h>
-#include <WebKit2/WKBundlePagePrivate.h>
+#include <WebKit/WKBundle.h>
+#include <WebKit/WKBundlePage.h>
+#include <WebKit/WKBundlePagePrivate.h>
namespace WTR {
-PassRefPtr<AccessibilityController> AccessibilityController::create()
+Ref<AccessibilityController> AccessibilityController::create()
{
- return adoptRef(new AccessibilityController);
+ return adoptRef(*new AccessibilityController);
}
AccessibilityController::AccessibilityController()
@@ -61,44 +61,43 @@ JSClassRef AccessibilityController::wrapperClass()
return JSAccessibilityController::accessibilityControllerClass();
}
+void AccessibilityController::enableEnhancedAccessibility(bool enable)
+{
+ WKAccessibilityEnableEnhancedAccessibility(enable);
+}
+
+bool AccessibilityController::enhancedAccessibilityEnabled()
+{
+ return WKAccessibilityEnhancedAccessibilityEnabled();
+}
+
#if !PLATFORM(GTK) && !PLATFORM(EFL)
-PassRefPtr<AccessibilityUIElement> AccessibilityController::rootElement()
+Ref<AccessibilityUIElement> AccessibilityController::rootElement()
{
- WKBundlePageRef page = InjectedBundle::shared().page()->page();
+ WKBundlePageRef page = InjectedBundle::singleton().page()->page();
void* root = WKAccessibilityRootObject(page);
return AccessibilityUIElement::create(static_cast<PlatformUIElement>(root));
}
-PassRefPtr<AccessibilityUIElement> AccessibilityController::focusedElement()
+Ref<AccessibilityUIElement> AccessibilityController::focusedElement()
{
- WKBundlePageRef page = InjectedBundle::shared().page()->page();
+ WKBundlePageRef page = InjectedBundle::singleton().page()->page();
void* root = WKAccessibilityFocusedObject(page);
return AccessibilityUIElement::create(static_cast<PlatformUIElement>(root));
}
#endif
-PassRefPtr<AccessibilityUIElement> AccessibilityController::elementAtPoint(int x, int y)
+RefPtr<AccessibilityUIElement> AccessibilityController::elementAtPoint(int x, int y)
{
- RefPtr<AccessibilityUIElement> uiElement = rootElement();
+ Ref<AccessibilityUIElement> uiElement = rootElement();
return uiElement->elementAtPoint(x, y);
}
-// Unsupported methods on various platforms.
-// As they're implemented on other platforms this list should be modified.
-#if (!PLATFORM(GTK) && !PLATFORM(MAC) && !PLATFORM(EFL)) || !HAVE(ACCESSIBILITY)
-bool AccessibilityController::addNotificationListener(JSValueRef) { return false; }
-bool AccessibilityController::removeNotificationListener() { return false; }
-PassRefPtr<AccessibilityUIElement> AccessibilityController::accessibleElementById(JSStringRef attribute) { return nullptr; }
-void AccessibilityController::logAccessibilityEvents() { }
-void AccessibilityController::resetToConsistentState() { }
-JSRetainPtr<JSStringRef> AccessibilityController::platformName() { return JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString("")); }
-#endif
-
#if !HAVE(ACCESSIBILITY) && (PLATFORM(GTK) || PLATFORM(EFL))
-PassRefPtr<AccessibilityUIElement> AccessibilityController::rootElement() { return nullptr; }
-PassRefPtr<AccessibilityUIElement> AccessibilityController::focusedElement() { return nullptr; }
+RefPtr<AccessibilityUIElement> AccessibilityController::rootElement() { return nullptr; }
+RefPtr<AccessibilityUIElement> AccessibilityController::focusedElement() { return nullptr; }
#endif
} // namespace WTR
diff --git a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.h b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.h
index 7ce1a45c3..5cf0d739c 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.h
+++ b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.h
@@ -23,14 +23,15 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef AccessibilityController_h
-#define AccessibilityController_h
+#pragma once
+
+#if HAVE(ACCESSIBILITY)
#include "AccessibilityUIElement.h"
#include "JSWrappable.h"
#include <JavaScriptCore/JSObjectRef.h>
#include <wtf/Platform.h>
-#if HAVE(ACCESSIBILITY) && (PLATFORM(GTK) || PLATFORM(EFL))
+#if PLATFORM(GTK) || PLATFORM(EFL)
#include "AccessibilityNotificationHandlerAtk.h"
#endif
@@ -38,19 +39,23 @@ namespace WTR {
class AccessibilityController : public JSWrappable {
public:
- static PassRefPtr<AccessibilityController> create();
+ static Ref<AccessibilityController> create();
~AccessibilityController();
void makeWindowObject(JSContextRef, JSObjectRef windowObject, JSValueRef* exception);
virtual JSClassRef wrapperClass();
+ // Enhanced accessibility.
+ void enableEnhancedAccessibility(bool);
+ bool enhancedAccessibilityEnabled();
+
JSRetainPtr<JSStringRef> platformName();
// Controller Methods - platform-independent implementations.
- PassRefPtr<AccessibilityUIElement> rootElement();
- PassRefPtr<AccessibilityUIElement> focusedElement();
- PassRefPtr<AccessibilityUIElement> elementAtPoint(int x, int y);
- PassRefPtr<AccessibilityUIElement> accessibleElementById(JSStringRef idAttribute);
+ Ref<AccessibilityUIElement> rootElement();
+ Ref<AccessibilityUIElement> focusedElement();
+ RefPtr<AccessibilityUIElement> elementAtPoint(int x, int y);
+ RefPtr<AccessibilityUIElement> accessibleElementById(JSStringRef idAttribute);
bool addNotificationListener(JSValueRef functionCallback);
bool removeNotificationListener();
@@ -59,22 +64,20 @@ public:
void logFocusEvents() { }
void logValueChangeEvents() { }
void logScrollingStartEvents() { }
- void logAccessibilityEvents();
+ void logAccessibilityEvents() { };
void resetToConsistentState();
private:
AccessibilityController();
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
RetainPtr<NotificationHandler> m_globalNotificationHandler;
-#endif
-
-#if HAVE(ACCESSIBILITY) && (PLATFORM(GTK) || PLATFORM(EFL))
+#else
RefPtr<AccessibilityNotificationHandler> m_globalNotificationHandler;
#endif
};
} // namespace WTR
-#endif // AccessibilityController_h
+#endif // HAVE(ACCESSIBILITY)
diff --git a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarker.cpp b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarker.cpp
index a7a4b7def..7e99fbb12 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarker.cpp
+++ b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarker.cpp
@@ -33,14 +33,14 @@
namespace WTR {
-PassRefPtr<AccessibilityTextMarker> AccessibilityTextMarker::create(PlatformTextMarker marker)
+Ref<AccessibilityTextMarker> AccessibilityTextMarker::create(PlatformTextMarker marker)
{
- return adoptRef(new AccessibilityTextMarker(marker));
+ return adoptRef(*new AccessibilityTextMarker(marker));
}
-PassRefPtr<AccessibilityTextMarker> AccessibilityTextMarker::create(const AccessibilityTextMarker& marker)
+Ref<AccessibilityTextMarker> AccessibilityTextMarker::create(const AccessibilityTextMarker& marker)
{
- return adoptRef(new AccessibilityTextMarker(marker));
+ return adoptRef(*new AccessibilityTextMarker(marker));
}
AccessibilityTextMarker::AccessibilityTextMarker(PlatformTextMarker marker)
@@ -60,7 +60,7 @@ AccessibilityTextMarker::~AccessibilityTextMarker()
PlatformTextMarker AccessibilityTextMarker::platformTextMarker() const
{
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
return m_textMarker.get();
#else
return m_textMarker;
diff --git a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarker.h b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarker.h
index c4d4d0481..041f81bc7 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarker.h
+++ b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarker.h
@@ -23,15 +23,14 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef AccessibilityTextMarker_h
-#define AccessibilityTextMarker_h
+#pragma once
#include "JSWrappable.h"
#include <JavaScriptCore/JSObjectRef.h>
-#include <wtf/PassRefPtr.h>
#include <wtf/Platform.h>
+#include <wtf/Ref.h>
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
#include <wtf/RetainPtr.h>
typedef CFTypeRef PlatformTextMarker;
#else
@@ -44,8 +43,8 @@ class AccessibilityUIElement;
class AccessibilityTextMarker : public JSWrappable {
public:
- static PassRefPtr<AccessibilityTextMarker> create(PlatformTextMarker);
- static PassRefPtr<AccessibilityTextMarker> create(const AccessibilityTextMarker&);
+ static Ref<AccessibilityTextMarker> create(PlatformTextMarker);
+ static Ref<AccessibilityTextMarker> create(const AccessibilityTextMarker&);
~AccessibilityTextMarker();
@@ -59,17 +58,15 @@ private:
AccessibilityTextMarker(PlatformTextMarker);
AccessibilityTextMarker(const AccessibilityTextMarker&);
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
RetainPtr<PlatformTextMarker> m_textMarker;
#else
PlatformTextMarker m_textMarker;
#endif
};
-#if !PLATFORM(MAC)
+#if !PLATFORM(COCOA)
inline bool AccessibilityTextMarker::isEqual(AccessibilityTextMarker*) { return false; }
#endif
} // namespace WTR
-
-#endif // AccessibilityTextMarker_h
diff --git a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarkerRange.cpp b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarkerRange.cpp
index 3613f3728..7444f3522 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarkerRange.cpp
+++ b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarkerRange.cpp
@@ -33,14 +33,14 @@
namespace WTR {
-PassRefPtr<AccessibilityTextMarkerRange> AccessibilityTextMarkerRange::create(PlatformTextMarkerRange markerRange)
+Ref<AccessibilityTextMarkerRange> AccessibilityTextMarkerRange::create(PlatformTextMarkerRange markerRange)
{
- return adoptRef(new AccessibilityTextMarkerRange(markerRange));
+ return adoptRef(*new AccessibilityTextMarkerRange(markerRange));
}
-PassRefPtr<AccessibilityTextMarkerRange> AccessibilityTextMarkerRange::create(const AccessibilityTextMarkerRange& markerRange)
+Ref<AccessibilityTextMarkerRange> AccessibilityTextMarkerRange::create(const AccessibilityTextMarkerRange& markerRange)
{
- return adoptRef(new AccessibilityTextMarkerRange(markerRange));
+ return adoptRef(*new AccessibilityTextMarkerRange(markerRange));
}
AccessibilityTextMarkerRange::AccessibilityTextMarkerRange(PlatformTextMarkerRange markerRange)
@@ -60,7 +60,7 @@ AccessibilityTextMarkerRange::~AccessibilityTextMarkerRange()
PlatformTextMarkerRange AccessibilityTextMarkerRange::platformTextMarkerRange() const
{
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
return m_textMarkerRange.get();
#else
return m_textMarkerRange;
diff --git a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarkerRange.h b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarkerRange.h
index e57a29cd7..18c18d48e 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarkerRange.h
+++ b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarkerRange.h
@@ -23,15 +23,14 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef AccessibilityTextMarkerRange_h
-#define AccessibilityTextMarkerRange_h
+#pragma once
#include "JSWrappable.h"
#include <JavaScriptCore/JSObjectRef.h>
-#include <wtf/PassRefPtr.h>
#include <wtf/Platform.h>
+#include <wtf/Ref.h>
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
#include <wtf/RetainPtr.h>
typedef CFTypeRef PlatformTextMarkerRange;
#else
@@ -42,8 +41,8 @@ namespace WTR {
class AccessibilityTextMarkerRange : public JSWrappable {
public:
- static PassRefPtr<AccessibilityTextMarkerRange> create(PlatformTextMarkerRange);
- static PassRefPtr<AccessibilityTextMarkerRange> create(const AccessibilityTextMarkerRange&);
+ static Ref<AccessibilityTextMarkerRange> create(PlatformTextMarkerRange);
+ static Ref<AccessibilityTextMarkerRange> create(const AccessibilityTextMarkerRange&);
~AccessibilityTextMarkerRange();
@@ -57,17 +56,15 @@ private:
AccessibilityTextMarkerRange(PlatformTextMarkerRange);
AccessibilityTextMarkerRange(const AccessibilityTextMarkerRange&);
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
RetainPtr<PlatformTextMarkerRange> m_textMarkerRange;
#else
PlatformTextMarkerRange m_textMarkerRange;
#endif
};
-#if !PLATFORM(MAC)
+#if !PLATFORM(COCOA)
inline bool AccessibilityTextMarkerRange::isEqual(AccessibilityTextMarkerRange*) { return false; }
#endif
} // namespace WTR
-
-#endif // AccessibilityTextMarkerRange_h
diff --git a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp
index 00e965ff3..233ff7d20 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp
+++ b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp
@@ -31,14 +31,14 @@
namespace WTR {
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::create(PlatformUIElement uiElement)
+Ref<AccessibilityUIElement> AccessibilityUIElement::create(PlatformUIElement uiElement)
{
- return adoptRef(new AccessibilityUIElement(uiElement));
+ return adoptRef(*new AccessibilityUIElement(uiElement));
}
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::create(const AccessibilityUIElement& uiElement)
+Ref<AccessibilityUIElement> AccessibilityUIElement::create(const AccessibilityUIElement& uiElement)
{
- return adoptRef(new AccessibilityUIElement(uiElement));
+ return adoptRef(*new AccessibilityUIElement(uiElement));
}
JSClassRef AccessibilityUIElement::wrapperClass()
@@ -53,154 +53,55 @@ bool AccessibilityUIElement::isValid() const
return m_element;
}
+// iOS specific methods
+#if !PLATFORM(IOS)
+JSRetainPtr<JSStringRef> AccessibilityUIElement::identifier() { return nullptr; }
+JSRetainPtr<JSStringRef> AccessibilityUIElement::traits() { return nullptr; }
+int AccessibilityUIElement::elementTextPosition() { return 0; }
+int AccessibilityUIElement::elementTextLength() { return 0; }
+JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForSelection() { return nullptr; }
+JSValueRef AccessibilityUIElement::elementsForRange(unsigned, unsigned) { return nullptr; }
+void AccessibilityUIElement::increaseTextSelection() { }
+void AccessibilityUIElement::decreaseTextSelection() { }
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::linkedElement() { return nullptr; }
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::headerElementAtIndex(unsigned) { return nullptr; }
+void AccessibilityUIElement::assistiveTechnologySimulatedFocus() { return; }
+bool AccessibilityUIElement::scrollPageUp() { return false; }
+bool AccessibilityUIElement::scrollPageDown() { return false; }
+bool AccessibilityUIElement::scrollPageLeft() { return false; }
+bool AccessibilityUIElement::scrollPageRight() { return false; }
+bool AccessibilityUIElement::hasContainedByFieldsetTrait() { return false; }
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::fieldsetAncestorElement() { return nullptr; }
+bool AccessibilityUIElement::isSearchField() const { return false; }
+bool AccessibilityUIElement::isTextArea() const { return false; }
+
+#endif
+
// Unsupported methods on various platforms. As they're implemented on other platforms this list should be modified.
#if (!PLATFORM(GTK) && !PLATFORM(EFL)) || !HAVE(ACCESSIBILITY)
-JSRetainPtr<JSStringRef> AccessibilityUIElement::characterAtOffset(int) { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::wordAtOffset(int) { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::lineAtOffset(int) { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::sentenceAtOffset(int) { return 0; }
+JSRetainPtr<JSStringRef> AccessibilityUIElement::characterAtOffset(int) { return nullptr; }
+JSRetainPtr<JSStringRef> AccessibilityUIElement::wordAtOffset(int) { return nullptr; }
+JSRetainPtr<JSStringRef> AccessibilityUIElement::lineAtOffset(int) { return nullptr; }
+JSRetainPtr<JSStringRef> AccessibilityUIElement::sentenceAtOffset(int) { return nullptr; }
#endif
-#if (!PLATFORM(MAC) && !PLATFORM(GTK) && !PLATFORM(EFL)) || !HAVE(ACCESSIBILITY)
-AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement) { }
-AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement&) { }
-AccessibilityUIElement::~AccessibilityUIElement() { }
-bool AccessibilityUIElement::isEqual(AccessibilityUIElement*) { return false; }
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::elementAtPoint(int, int) { return 0; }
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::childAtIndex(unsigned) { return 0; }
-unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement*) { return 0; }
-int AccessibilityUIElement::childrenCount() { return 0; }
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::titleUIElement() { return 0; }
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::parentElement() { return 0; }
-void AccessibilityUIElement::takeFocus() { }
-void AccessibilityUIElement::takeSelection() { }
-void AccessibilityUIElement::addSelection() { }
-void AccessibilityUIElement::removeSelection() { }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::allAttributes() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfLinkedUIElements() { return 0; }
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::linkedUIElementAtIndex(unsigned) { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfDocumentLinks() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfChildren() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::parameterizedAttributeNames() { return 0; }
-void AccessibilityUIElement::increment() { }
-void AccessibilityUIElement::decrement() { }
-void AccessibilityUIElement::showMenu() { }
-void AccessibilityUIElement::press() { }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::stringAttributeValue(JSStringRef) { return 0; }
-JSValueRef AccessibilityUIElement::uiElementArrayAttributeValue(JSStringRef) const { return nullptr; }
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementAttributeValue(JSStringRef) const { return 0; }
-double AccessibilityUIElement::numberAttributeValue(JSStringRef) { return 0; }
-bool AccessibilityUIElement::boolAttributeValue(JSStringRef) { return false; }
-bool AccessibilityUIElement::isAttributeSupported(JSStringRef) { return false; }
-bool AccessibilityUIElement::isAttributeSettable(JSStringRef) { return false; }
-bool AccessibilityUIElement::isPressActionSupported() { return false; }
-bool AccessibilityUIElement::isIncrementActionSupported() { return false; }
-bool AccessibilityUIElement::isDecrementActionSupported() { return false; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::role() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::subrole() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::roleDescription() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::title() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::description() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::language() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::stringValue() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::accessibilityValue() const { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::helpText() const { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::orientation() const { return 0; }
-double AccessibilityUIElement::x() { return 0; }
-double AccessibilityUIElement::y() { return 0; }
-double AccessibilityUIElement::width() { return 0; }
-double AccessibilityUIElement::height() { return 0; }
-double AccessibilityUIElement::intValue() const { return 0; }
-double AccessibilityUIElement::minValue() { return 0; }
-double AccessibilityUIElement::maxValue() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::valueDescription() { return 0; }
-int AccessibilityUIElement::insertionPointLineNumber() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::selectedTextRange() { return 0; }
-bool AccessibilityUIElement::isEnabled() { return false; }
-bool AccessibilityUIElement::isRequired() const { return false; }
-bool AccessibilityUIElement::isFocused() const { return false; }
-bool AccessibilityUIElement::isFocusable() const { return false; }
-bool AccessibilityUIElement::isSelected() const { return false; }
-bool AccessibilityUIElement::isSelectedOptionActive() const { return false; }
-bool AccessibilityUIElement::isSelectable() const { return false; }
-bool AccessibilityUIElement::isMultiSelectable() const { return false; }
-void AccessibilityUIElement::setSelectedChild(AccessibilityUIElement*) const { }
-unsigned AccessibilityUIElement::selectedChildrenCount() const { return 0; }
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedChildAtIndex(unsigned) const { return 0; }
-bool AccessibilityUIElement::isExpanded() const { return false; }
-bool AccessibilityUIElement::isChecked() const { return false; }
-bool AccessibilityUIElement::isIndeterminate() const { return false; }
-bool AccessibilityUIElement::isVisible() const { return false; }
-bool AccessibilityUIElement::isOffScreen() const { return false; }
-bool AccessibilityUIElement::isCollapsed() const { return false; }
-bool AccessibilityUIElement::isIgnored() const { return false; }
-bool AccessibilityUIElement::hasPopup() const { return false; }
-int AccessibilityUIElement::hierarchicalLevel() const { return 0; }
-double AccessibilityUIElement::clickPointX() { return 0; }
-double AccessibilityUIElement::clickPointY() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::documentEncoding() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::documentURI() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::url() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::speak() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfColumnHeaders() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfRowHeaders() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfColumns() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfRows() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfVisibleCells() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfHeader() { return 0; }
-int AccessibilityUIElement::indexInTable() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::rowIndexRange() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::columnIndexRange() { return 0; }
-int AccessibilityUIElement::rowCount() { return 0; }
-int AccessibilityUIElement::columnCount() { return 0; }
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedRowAtIndex(unsigned) { return 0; }
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedByRow() { return 0; }
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedRowAtIndex(unsigned) { return 0; }
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::rowAtIndex(unsigned) { return 0; }
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned) { return 0; }
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned) { return 0; }
-bool AccessibilityUIElement::ariaIsGrabbed() const { return false; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::ariaDropEffects() const { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::classList() const { return 0; }
-int AccessibilityUIElement::lineForIndex(int) { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForLine(int) { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForPosition(int, int) { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::boundsForRange(unsigned, unsigned) { return 0; }
-bool AccessibilityUIElement::setSelectedTextRange(unsigned, unsigned) { return false; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForRange(unsigned, unsigned) { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::attributedStringForRange(unsigned, unsigned) { return 0; }
-bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned, unsigned) { return false; }
-unsigned AccessibilityUIElement::uiElementCountForSearchPredicate(JSContextRef, AccessibilityUIElement*, bool, JSValueRef, JSStringRef, bool) { return 0; }
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef, AccessibilityUIElement*, bool, JSValueRef, JSStringRef, bool) { return 0; }
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::cellForColumnAndRow(unsigned, unsigned) { return 0; }
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::horizontalScrollbar() const { return 0; }
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::verticalScrollbar() const { return 0; }
-bool AccessibilityUIElement::addNotificationListener(JSValueRef) { return false; }
-bool AccessibilityUIElement::removeNotificationListener() { return false; }
-PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForElement(AccessibilityUIElement*) { return 0; }
-int AccessibilityUIElement::textMarkerRangeLength(AccessibilityTextMarkerRange*) { return 0; }
-PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForMarkers(AccessibilityTextMarker*, AccessibilityTextMarker*) { return 0; }
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange*) { return 0; }
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange*) { return 0; }
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::accessibilityElementForTextMarker(AccessibilityTextMarker*) { return 0; }
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForBounds(int x, int y, int width, int height) { return 0; }
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForBounds(int x, int y, int width, int height) { return 0; }
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForPoint(int, int) { return 0; }
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousTextMarker(AccessibilityTextMarker*) { return 0; }
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextTextMarker(AccessibilityTextMarker*) { return 0; }
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarker() { return 0; }
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarker() { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForTextMarkerRange(AccessibilityTextMarkerRange*) { return 0; }
-bool AccessibilityUIElement::attributedStringForTextMarkerRangeContainsAttribute(JSStringRef, AccessibilityTextMarkerRange*) { return false; }
-int AccessibilityUIElement::indexForTextMarker(AccessibilityTextMarker*) { return -1; }
-bool AccessibilityUIElement::isTextMarkerValid(AccessibilityTextMarker*) { return false; }
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForIndex(int) { return 0; }
-void AccessibilityUIElement::scrollToMakeVisible() { }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::supportedActions() const { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::mathPostscriptsDescription() const { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::mathPrescriptsDescription() const { return 0; }
-JSRetainPtr<JSStringRef> AccessibilityUIElement::pathDescription() const { return 0; }
+#if !PLATFORM(MAC) || !HAVE(ACCESSIBILITY)
+RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::selectedTextMarkerRange() { return nullptr; }
+void AccessibilityUIElement::resetSelectedTextMarkerRange() { }
+void AccessibilityUIElement::setBoolAttributeValue(JSStringRef, bool) { }
+#endif
+#if !PLATFORM(COCOA) || !HAVE(ACCESSIBILITY)
+RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*) { return nullptr; }
+RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*) { return nullptr; }
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*) { return nullptr; }
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*) { return nullptr; }
+RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker(AccessibilityTextMarker*) { return nullptr; }
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker(AccessibilityTextMarker*) { return nullptr; }
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker(AccessibilityTextMarker*) { return nullptr; }
+RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::sentenceTextMarkerRangeForTextMarker(AccessibilityTextMarker*) { return nullptr; }
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextSentenceEndTextMarkerForTextMarker(AccessibilityTextMarker*) { return nullptr; }
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousSentenceStartTextMarkerForTextMarker(AccessibilityTextMarker*) { return nullptr; }
#endif
} // namespace WTR
diff --git a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h
index 807b82446..5509af217 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h
+++ b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h
@@ -23,8 +23,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef AccessibilityUIElement_h
-#define AccessibilityUIElement_h
+#pragma once
#include "AccessibilityTextMarker.h"
#include "AccessibilityTextMarkerRange.h"
@@ -35,7 +34,7 @@
#include <wtf/Platform.h>
#include <wtf/Vector.h>
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
#ifdef __OBJC__
typedef id PlatformUIElement;
#else
@@ -44,13 +43,13 @@ typedef struct objc_object* PlatformUIElement;
#elif HAVE(ACCESSIBILITY) && (PLATFORM(GTK) || PLATFORM(EFL))
#include "AccessibilityNotificationHandlerAtk.h"
#include <atk/atk.h>
-#include <wtf/gobject/GRefPtr.h>
+#include <wtf/glib/GRefPtr.h>
typedef GRefPtr<AtkObject> PlatformUIElement;
#else
typedef void* PlatformUIElement;
#endif
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
#ifdef __OBJC__
typedef id NotificationHandler;
#else
@@ -62,8 +61,8 @@ namespace WTR {
class AccessibilityUIElement : public JSWrappable {
public:
- static PassRefPtr<AccessibilityUIElement> create(PlatformUIElement);
- static PassRefPtr<AccessibilityUIElement> create(const AccessibilityUIElement&);
+ static Ref<AccessibilityUIElement> create(PlatformUIElement);
+ static Ref<AccessibilityUIElement> create(const AccessibilityUIElement&);
~AccessibilityUIElement();
@@ -74,12 +73,12 @@ public:
bool isEqual(AccessibilityUIElement* otherElement);
- PassRefPtr<AccessibilityUIElement> elementAtPoint(int x, int y);
- PassRefPtr<AccessibilityUIElement> childAtIndex(unsigned);
+ RefPtr<AccessibilityUIElement> elementAtPoint(int x, int y);
+ RefPtr<AccessibilityUIElement> childAtIndex(unsigned);
unsigned indexOfChild(AccessibilityUIElement*);
int childrenCount();
- PassRefPtr<AccessibilityUIElement> titleUIElement();
- PassRefPtr<AccessibilityUIElement> parentElement();
+ RefPtr<AccessibilityUIElement> titleUIElement();
+ RefPtr<AccessibilityUIElement> parentElement();
void takeFocus();
void takeSelection();
@@ -89,7 +88,7 @@ public:
// Methods - platform-independent implementations
JSRetainPtr<JSStringRef> allAttributes();
JSRetainPtr<JSStringRef> attributesOfLinkedUIElements();
- PassRefPtr<AccessibilityUIElement> linkedUIElementAtIndex(unsigned);
+ RefPtr<AccessibilityUIElement> linkedUIElementAtIndex(unsigned);
JSRetainPtr<JSStringRef> attributesOfDocumentLinks();
JSRetainPtr<JSStringRef> attributesOfChildren();
@@ -103,8 +102,9 @@ public:
JSRetainPtr<JSStringRef> stringAttributeValue(JSStringRef attribute);
double numberAttributeValue(JSStringRef attribute);
JSValueRef uiElementArrayAttributeValue(JSStringRef attribute) const;
- PassRefPtr<AccessibilityUIElement> uiElementAttributeValue(JSStringRef attribute) const;
+ RefPtr<AccessibilityUIElement> uiElementAttributeValue(JSStringRef attribute) const;
bool boolAttributeValue(JSStringRef attribute);
+ void setBoolAttributeValue(JSStringRef attribute, bool value);
bool isAttributeSupported(JSStringRef attribute);
bool isAttributeSettable(JSStringRef attribute);
bool isPressActionSupported();
@@ -113,6 +113,7 @@ public:
JSRetainPtr<JSStringRef> role();
JSRetainPtr<JSStringRef> subrole();
JSRetainPtr<JSStringRef> roleDescription();
+ JSRetainPtr<JSStringRef> computedRoleString();
JSRetainPtr<JSStringRef> title();
JSRetainPtr<JSStringRef> description();
JSRetainPtr<JSStringRef> language();
@@ -140,8 +141,11 @@ public:
bool isSelectable() const;
bool isMultiSelectable() const;
void setSelectedChild(AccessibilityUIElement*) const;
+ void setSelectedChildAtIndex(unsigned) const;
+ void removeSelectionAtIndex(unsigned) const;
+ void clearSelectedChildren() const;
unsigned selectedChildrenCount() const;
- PassRefPtr<AccessibilityUIElement> selectedChildAtIndex(unsigned) const;
+ RefPtr<AccessibilityUIElement> selectedChildAtIndex(unsigned) const;
bool isValid() const;
bool isExpanded() const;
@@ -151,6 +155,8 @@ public:
bool isOffScreen() const;
bool isCollapsed() const;
bool isIgnored() const;
+ bool isSingleLine() const;
+ bool isMultiLine() const;
bool hasPopup() const;
int hierarchicalLevel() const;
double clickPointX();
@@ -179,14 +185,15 @@ public:
JSValueRef columnHeaders() const;
// Tree/Outline specific attributes
- PassRefPtr<AccessibilityUIElement> selectedRowAtIndex(unsigned);
- PassRefPtr<AccessibilityUIElement> disclosedByRow();
- PassRefPtr<AccessibilityUIElement> disclosedRowAtIndex(unsigned);
- PassRefPtr<AccessibilityUIElement> rowAtIndex(unsigned);
+ RefPtr<AccessibilityUIElement> selectedRowAtIndex(unsigned);
+ RefPtr<AccessibilityUIElement> disclosedByRow();
+ RefPtr<AccessibilityUIElement> disclosedRowAtIndex(unsigned);
+ RefPtr<AccessibilityUIElement> rowAtIndex(unsigned);
// ARIA specific
- PassRefPtr<AccessibilityUIElement> ariaOwnsElementAtIndex(unsigned);
- PassRefPtr<AccessibilityUIElement> ariaFlowToElementAtIndex(unsigned);
+ RefPtr<AccessibilityUIElement> ariaOwnsElementAtIndex(unsigned);
+ RefPtr<AccessibilityUIElement> ariaFlowToElementAtIndex(unsigned);
+ RefPtr<AccessibilityUIElement> ariaControlsElementAtIndex(unsigned);
// ARIA Drag and Drop
bool ariaIsGrabbed() const;
@@ -202,8 +209,9 @@ public:
JSRetainPtr<JSStringRef> stringForRange(unsigned location, unsigned length);
JSRetainPtr<JSStringRef> attributedStringForRange(unsigned location, unsigned length);
bool attributedStringRangeIsMisspelled(unsigned location, unsigned length);
- unsigned uiElementCountForSearchPredicate(JSContextRef, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly);
- PassRefPtr<AccessibilityUIElement> uiElementForSearchPredicate(JSContextRef, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly);
+ unsigned uiElementCountForSearchPredicate(JSContextRef, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly);
+ RefPtr<AccessibilityUIElement> uiElementForSearchPredicate(JSContextRef, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly);
+ JSRetainPtr<JSStringRef> selectTextWithCriteria(JSContextRef, JSStringRef ambiguityResolution, JSValueRef searchStrings, JSStringRef replacementString, JSStringRef activity);
// Text-specific
JSRetainPtr<JSStringRef> characterAtOffset(int offset);
@@ -212,33 +220,49 @@ public:
JSRetainPtr<JSStringRef> sentenceAtOffset(int offset);
// Table-specific
- PassRefPtr<AccessibilityUIElement> cellForColumnAndRow(unsigned column, unsigned row);
+ RefPtr<AccessibilityUIElement> cellForColumnAndRow(unsigned column, unsigned row);
// Scrollarea-specific
- PassRefPtr<AccessibilityUIElement> horizontalScrollbar() const;
- PassRefPtr<AccessibilityUIElement> verticalScrollbar() const;
+ RefPtr<AccessibilityUIElement> horizontalScrollbar() const;
+ RefPtr<AccessibilityUIElement> verticalScrollbar() const;
void scrollToMakeVisible();
+ void scrollToGlobalPoint(int x, int y);
+ void scrollToMakeVisibleWithSubFocus(int x, int y, int width, int height);
// Text markers.
- PassRefPtr<AccessibilityTextMarkerRange> textMarkerRangeForElement(AccessibilityUIElement*);
- PassRefPtr<AccessibilityTextMarkerRange> textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker);
- PassRefPtr<AccessibilityTextMarker> startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange*);
- PassRefPtr<AccessibilityTextMarker> endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange*);
- PassRefPtr<AccessibilityTextMarker> endTextMarkerForBounds(int x, int y, int width, int height);
- PassRefPtr<AccessibilityTextMarker> startTextMarkerForBounds(int x, int y, int width, int height);
- PassRefPtr<AccessibilityTextMarker> textMarkerForPoint(int x, int y);
- PassRefPtr<AccessibilityTextMarker> previousTextMarker(AccessibilityTextMarker*);
- PassRefPtr<AccessibilityTextMarker> nextTextMarker(AccessibilityTextMarker*);
- PassRefPtr<AccessibilityUIElement> accessibilityElementForTextMarker(AccessibilityTextMarker*);
+ RefPtr<AccessibilityTextMarkerRange> lineTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
+ RefPtr<AccessibilityTextMarkerRange> textMarkerRangeForElement(AccessibilityUIElement*);
+ RefPtr<AccessibilityTextMarkerRange> textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker);
+ RefPtr<AccessibilityTextMarkerRange> selectedTextMarkerRange();
+ void resetSelectedTextMarkerRange();
+ RefPtr<AccessibilityTextMarker> startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange*);
+ RefPtr<AccessibilityTextMarker> endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange*);
+ RefPtr<AccessibilityTextMarker> endTextMarkerForBounds(int x, int y, int width, int height);
+ RefPtr<AccessibilityTextMarker> startTextMarkerForBounds(int x, int y, int width, int height);
+ RefPtr<AccessibilityTextMarker> textMarkerForPoint(int x, int y);
+ RefPtr<AccessibilityTextMarker> previousTextMarker(AccessibilityTextMarker*);
+ RefPtr<AccessibilityTextMarker> nextTextMarker(AccessibilityTextMarker*);
+ RefPtr<AccessibilityUIElement> accessibilityElementForTextMarker(AccessibilityTextMarker*);
JSRetainPtr<JSStringRef> stringForTextMarkerRange(AccessibilityTextMarkerRange*);
int textMarkerRangeLength(AccessibilityTextMarkerRange*);
bool attributedStringForTextMarkerRangeContainsAttribute(JSStringRef, AccessibilityTextMarkerRange*);
int indexForTextMarker(AccessibilityTextMarker*);
bool isTextMarkerValid(AccessibilityTextMarker*);
- PassRefPtr<AccessibilityTextMarker> textMarkerForIndex(int);
- PassRefPtr<AccessibilityTextMarker> startTextMarker();
- PassRefPtr<AccessibilityTextMarker> endTextMarker();
+ RefPtr<AccessibilityTextMarker> textMarkerForIndex(int);
+ RefPtr<AccessibilityTextMarker> startTextMarker();
+ RefPtr<AccessibilityTextMarker> endTextMarker();
+ bool setSelectedVisibleTextRange(AccessibilityTextMarkerRange*);
+ RefPtr<AccessibilityTextMarkerRange> leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
+ RefPtr<AccessibilityTextMarkerRange> rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
+ RefPtr<AccessibilityTextMarker> previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*);
+ RefPtr<AccessibilityTextMarker> nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*);
+ RefPtr<AccessibilityTextMarkerRange> paragraphTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
+ RefPtr<AccessibilityTextMarker> nextParagraphEndTextMarkerForTextMarker(AccessibilityTextMarker*);
+ RefPtr<AccessibilityTextMarker> previousParagraphStartTextMarkerForTextMarker(AccessibilityTextMarker*);
+ RefPtr<AccessibilityTextMarkerRange> sentenceTextMarkerRangeForTextMarker(AccessibilityTextMarker*);
+ RefPtr<AccessibilityTextMarker> nextSentenceEndTextMarkerForTextMarker(AccessibilityTextMarker*);
+ RefPtr<AccessibilityTextMarker> previousSentenceStartTextMarkerForTextMarker(AccessibilityTextMarker*);
// Returns an ordered list of supported actions for an element.
JSRetainPtr<JSStringRef> supportedActions() const;
@@ -253,6 +277,29 @@ public:
// Make sure you call remove, because you can't rely on objects being deallocated in a timely fashion.
bool removeNotificationListener();
+ JSRetainPtr<JSStringRef> identifier();
+ JSRetainPtr<JSStringRef> traits();
+ int elementTextPosition();
+ int elementTextLength();
+ JSRetainPtr<JSStringRef> stringForSelection();
+ JSValueRef elementsForRange(unsigned location, unsigned length);
+ void increaseTextSelection();
+ void decreaseTextSelection();
+ RefPtr<AccessibilityUIElement> linkedElement();
+ RefPtr<AccessibilityUIElement> headerElementAtIndex(unsigned index);
+ void assistiveTechnologySimulatedFocus();
+ bool isSearchField() const;
+ bool isTextArea() const;
+
+ bool scrollPageUp();
+ bool scrollPageDown();
+ bool scrollPageLeft();
+ bool scrollPageRight();
+
+ // Fieldset
+ bool hasContainedByFieldsetTrait();
+ RefPtr<AccessibilityUIElement> fieldsetAncestorElement();
+
private:
AccessibilityUIElement(PlatformUIElement);
AccessibilityUIElement(const AccessibilityUIElement&);
@@ -261,7 +308,7 @@ private:
// A retained, platform specific object used to help manage notifications for this object.
#if HAVE(ACCESSIBILITY)
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
NotificationHandler m_notificationHandler;
void getLinkedUIElements(Vector<RefPtr<AccessibilityUIElement> >&);
@@ -270,7 +317,7 @@ private:
void getUIElementsWithAttribute(JSStringRef, Vector<RefPtr<AccessibilityUIElement> >&) const;
#endif
-#if PLATFORM(MAC) || PLATFORM(GTK) || PLATFORM(EFL)
+#if PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(EFL)
void getChildren(Vector<RefPtr<AccessibilityUIElement> >&);
void getChildrenWithRange(Vector<RefPtr<AccessibilityUIElement> >&, unsigned location, unsigned length);
#endif
@@ -282,5 +329,3 @@ private:
};
} // namespace WTR
-
-#endif // AccessibilityUIElement_h
diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityController.idl b/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityController.idl
new file mode 100644
index 000000000..d50a2033f
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityController.idl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+interface AccessibilityController {
+ void enableEnhancedAccessibility(boolean enable);
+ readonly attribute boolean enhancedAccessibilityEnabled;
+
+ readonly attribute DOMString platformName;
+ readonly attribute AccessibilityUIElement rootElement;
+ readonly attribute AccessibilityUIElement focusedElement;
+ AccessibilityUIElement elementAtPoint(long x, long y);
+ AccessibilityUIElement accessibleElementById(DOMString id);
+
+ boolean addNotificationListener(object functionCallback);
+ boolean removeNotificationListener();
+
+ void logFocusEvents();
+ void logValueChangeEvents();
+ void logScrollingStartEvents();
+ void logAccessibilityEvents();
+ void resetToConsistentState();
+};
+
diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityTextMarker.idl b/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityTextMarker.idl
new file mode 100644
index 000000000..149c95f34
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityTextMarker.idl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+interface AccessibilityTextMarker {
+ boolean isEqual(AccessibilityTextMarker otherMarker);
+};
+
diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityTextMarkerRange.idl b/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityTextMarkerRange.idl
new file mode 100644
index 000000000..962c584e6
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityTextMarkerRange.idl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+interface AccessibilityTextMarkerRange {
+ boolean isEqual(AccessibilityTextMarkerRange otherMarkerRange);
+};
+
diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl b/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl
new file mode 100644
index 000000000..967cb975d
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+interface AccessibilityUIElement {
+ boolean isEqual(AccessibilityUIElement otherElement);
+
+ // Document information
+ readonly attribute DOMString documentEncoding;
+ readonly attribute DOMString documentURI;
+
+ // Element access.
+ AccessibilityUIElement elementAtPoint(long x, long y);
+ AccessibilityUIElement childAtIndex(unsigned long index);
+ unsigned long indexOfChild(AccessibilityUIElement child);
+ AccessibilityUIElement linkedUIElementAtIndex(unsigned long index);
+ AccessibilityUIElement selectedChildAtIndex(unsigned long index);
+ void setSelectedChild(AccessibilityUIElement element);
+ void setSelectedChildAtIndex(unsigned long index);
+ void removeSelectionAtIndex(unsigned long index);
+ void clearSelectedChildren();
+ AccessibilityUIElement titleUIElement();
+ AccessibilityUIElement parentElement();
+
+ readonly attribute DOMString role;
+ readonly attribute DOMString subrole;
+ readonly attribute DOMString roleDescription;
+ readonly attribute DOMString computedRoleString;
+ readonly attribute DOMString title;
+ readonly attribute DOMString description;
+ readonly attribute DOMString language;
+ readonly attribute DOMString helpText;
+ readonly attribute DOMString valueDescription;
+ readonly attribute DOMString url;
+ readonly attribute DOMString speak;
+ readonly attribute DOMString orientation;
+ readonly attribute long insertionPointLineNumber;
+ readonly attribute DOMString selectedTextRange;
+
+ DOMString stringAttributeValue(DOMString attr);
+ double numberAttributeValue(DOMString attr);
+ object uiElementArrayAttributeValue(DOMString attr);
+ AccessibilityUIElement uiElementAttributeValue(DOMString attr);
+ boolean boolAttributeValue(DOMString attr);
+ void setBoolAttributeValue(DOMString attr, boolean value);
+ boolean isAttributeSupported(DOMString attr);
+ boolean isAttributeSettable(DOMString attr);
+ boolean isPressActionSupported();
+ boolean isIncrementActionSupported();
+ boolean isDecrementActionSupported();
+
+ readonly attribute DOMString stringValue;
+ readonly attribute long intValue;
+ readonly attribute long minValue;
+ readonly attribute long maxValue;
+
+ readonly attribute boolean isEnabled;
+ readonly attribute boolean isRequired;
+ readonly attribute boolean isFocused;
+ readonly attribute boolean isFocusable;
+ readonly attribute boolean isSelectable;
+ readonly attribute boolean isSelected;
+ readonly attribute boolean isSelectedOptionActive;
+ readonly attribute boolean isMultiSelectable;
+ readonly attribute boolean isExpanded;
+ readonly attribute boolean isChecked;
+ readonly attribute boolean isIndeterminate;
+ readonly attribute boolean isVisible;
+ readonly attribute boolean isCollapsed;
+ readonly attribute boolean hasPopup;
+ readonly attribute boolean isIgnored;
+ readonly attribute boolean isSingleLine;
+ readonly attribute boolean isMultiLine;
+ readonly attribute boolean isOffScreen;
+ readonly attribute boolean isValid;
+ readonly attribute long hierarchicalLevel;
+ readonly attribute boolean ariaIsGrabbed;
+ readonly attribute DOMString ariaDropEffects;
+ readonly attribute DOMString classList;
+
+ readonly attribute long x;
+ readonly attribute long y;
+ readonly attribute long width;
+ readonly attribute long height;
+ readonly attribute long clickPointX;
+ readonly attribute long clickPointY;
+
+ readonly attribute long childrenCount;
+ readonly attribute long selectedChildrenCount;
+ readonly attribute long rowCount;
+ readonly attribute long columnCount;
+
+ // Actions.
+ void increment();
+ void decrement();
+ void press();
+ void showMenu();
+
+ // Attribute info.
+ DOMString allAttributes();
+ DOMString attributesOfChildren();
+ DOMString attributesOfLinkedUIElements();
+ DOMString attributesOfDocumentLinks();
+
+ // Text info.
+ DOMString characterAtOffset(long offset);
+ DOMString wordAtOffset(long offset);
+ DOMString lineAtOffset(long offset);
+ DOMString sentenceAtOffset(long offset);
+
+ // Table info.
+ DOMString attributesOfColumnHeaders();
+ DOMString attributesOfRowHeaders();
+ DOMString attributesOfColumns();
+ DOMString attributesOfRows();
+ DOMString attributesOfVisibleCells();
+ DOMString attributesOfHeader();
+ AccessibilityUIElement cellForColumnAndRow(unsigned long column, unsigned long row);
+ AccessibilityUIElement selectedRowAtIndex(unsigned long index);
+ AccessibilityUIElement disclosedByRow();
+ AccessibilityUIElement disclosedRowAtIndex(unsigned long index);
+ AccessibilityUIElement rowAtIndex(unsigned long index);
+ long indexInTable();
+ DOMString rowIndexRange();
+ DOMString columnIndexRange();
+ long rowCount();
+ long columnCount();
+ object columnHeaders();
+ object rowHeaders();
+
+ AccessibilityUIElement ariaOwnsElementAtIndex(unsigned long index);
+ AccessibilityUIElement ariaFlowToElementAtIndex(unsigned long index);
+ AccessibilityUIElement ariaControlsElementAtIndex(unsigned long index);
+
+ // Paramaterized attributes.
+ DOMString parameterizedAttributeNames();
+ long lineForIndex(long index);
+ DOMString rangeForLine(long index);
+ DOMString rangeForPosition(long x, long y);
+ DOMString boundsForRange(unsigned long location, unsigned long length);
+ DOMString stringForRange(unsigned long location, unsigned long length);
+ DOMString attributedStringForRange(unsigned long location, unsigned long length);
+ boolean attributedStringRangeIsMisspelled(unsigned long location, unsigned long length);
+ [PassContext] unsigned long uiElementCountForSearchPredicate(AccessibilityUIElement startElement, boolean isDirectionNext, object searchKey, DOMString searchText, boolean visibleOnly, boolean immediateDescendantsOnly);
+ [PassContext] AccessibilityUIElement uiElementForSearchPredicate(AccessibilityUIElement startElement, boolean isDirectionNext, object searchKey, DOMString searchText, boolean visibleOnly, boolean immediateDescendantsOnly);
+ [PassContext] DOMString selectTextWithCriteria(DOMString ambiguityResolution, object searchStrings, DOMString replacementString, DOMString activity);
+ boolean setSelectedTextRange(unsigned long location, unsigned long length);
+
+ // Scroll area attributes.
+ readonly attribute AccessibilityUIElement horizontalScrollbar;
+ readonly attribute AccessibilityUIElement verticalScrollbar;
+
+ void scrollToMakeVisible();
+ void scrollToGlobalPoint(long x, long y);
+ void scrollToMakeVisibleWithSubFocus(long x, long y, long width, long height);
+
+ void takeFocus();
+ boolean scrollPageDown();
+ boolean scrollPageUp();
+ boolean scrollPageLeft();
+ boolean scrollPageRight();
+
+ // Text markers.
+ AccessibilityTextMarkerRange lineTextMarkerRangeForTextMarker(AccessibilityTextMarker textMarker);
+ AccessibilityTextMarkerRange textMarkerRangeForElement(AccessibilityUIElement element);
+ AccessibilityTextMarkerRange textMarkerRangeForMarkers(AccessibilityTextMarker startMarker, AccessibilityTextMarker endMarker);
+ AccessibilityTextMarkerRange selectedTextMarkerRange();
+ void resetSelectedTextMarkerRange();
+ AccessibilityTextMarker startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange range);
+ AccessibilityTextMarker endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange range);
+ AccessibilityTextMarker endTextMarkerForBounds(long x, long y, long width, long height);
+ AccessibilityTextMarker startTextMarkerForBounds(long x, long y, long width, long height);
+ AccessibilityTextMarker textMarkerForPoint(long x, long y);
+ AccessibilityTextMarker previousTextMarker(AccessibilityTextMarker marker);
+ AccessibilityTextMarker nextTextMarker(AccessibilityTextMarker marker);
+ AccessibilityUIElement accessibilityElementForTextMarker(AccessibilityTextMarker marker);
+ DOMString stringForTextMarkerRange(AccessibilityTextMarkerRange range);
+ long textMarkerRangeLength(AccessibilityTextMarkerRange range);
+ boolean attributedStringForTextMarkerRangeContainsAttribute(DOMString attr, AccessibilityTextMarkerRange range);
+ long indexForTextMarker(AccessibilityTextMarker marker);
+ boolean isTextMarkerValid(AccessibilityTextMarker marker);
+ AccessibilityTextMarker textMarkerForIndex(long textIndex);
+ readonly attribute AccessibilityTextMarker startTextMarker;
+ readonly attribute AccessibilityTextMarker endTextMarker;
+ boolean setSelectedVisibleTextRange(AccessibilityTextMarkerRange range);
+ AccessibilityTextMarkerRange leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker textMarker);
+ AccessibilityTextMarkerRange rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker textMarker);
+ AccessibilityTextMarker previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker textMarker);
+ AccessibilityTextMarker nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker textMarker);
+ AccessibilityTextMarkerRange paragraphTextMarkerRangeForTextMarker(AccessibilityTextMarker textMarker);
+ AccessibilityTextMarker previousParagraphStartTextMarkerForTextMarker(AccessibilityTextMarker textMarker);
+ AccessibilityTextMarker nextParagraphEndTextMarkerForTextMarker(AccessibilityTextMarker textMarker);
+ AccessibilityTextMarkerRange sentenceTextMarkerRangeForTextMarker(AccessibilityTextMarker textMarker);
+ AccessibilityTextMarker previousSentenceStartTextMarkerForTextMarker(AccessibilityTextMarker textMarker);
+ AccessibilityTextMarker nextSentenceEndTextMarkerForTextMarker(AccessibilityTextMarker textMarker);
+
+ // Returns an ordered list of supported actions for an element.
+ readonly attribute DOMString supportedActions;
+ readonly attribute DOMString mathPostscriptsDescription;
+ readonly attribute DOMString mathPrescriptsDescription;
+
+ readonly attribute DOMString pathDescription;
+
+ // iOS specific accessibility methods.
+ readonly attribute DOMString identifier;
+ readonly attribute DOMString traits;
+ readonly attribute long elementTextPosition;
+ readonly attribute long elementTextLength;
+ readonly attribute DOMString stringForSelection;
+ object elementsForRange(unsigned long location, unsigned long length);
+ void increaseTextSelection();
+ void decreaseTextSelection();
+ AccessibilityUIElement linkedElement();
+ AccessibilityUIElement headerElementAtIndex(unsigned long index);
+ // This will simulate the accessibilityDidBecomeFocused API in UIKit.
+ void assistiveTechnologySimulatedFocus();
+ readonly attribute boolean isSearchField;
+ readonly attribute boolean isTextArea;
+
+ // Fieldset
+ readonly attribute boolean hasContainedByFieldsetTrait;
+ AccessibilityUIElement fieldsetAncestorElement();
+
+ // Notification support.
+ boolean addNotificationListener(object callbackFunction);
+ boolean removeNotificationListener();
+};
+
diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm b/Tools/WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm
new file mode 100644
index 000000000..98d37dab9
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm
@@ -0,0 +1,577 @@
+# Copyright (C) 2010 Apple Inc. All rights reserved.
+# Copyright (C) 2012 Samsung Electronics
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+use strict;
+use warnings;
+use File::Spec;
+
+package CodeGeneratorTestRunner;
+
+use Carp qw<longmess>;
+use Data::Dumper;
+
+sub assert
+{
+ my $message = shift;
+
+ my $mess = longmess();
+ print Dumper($mess);
+
+ die $message;
+}
+
+sub new
+{
+ my ($class, $codeGenerator, $writeDependencies, $verbose, $idlFilePath) = @_;
+
+ my $reference = {
+ codeGenerator => $codeGenerator,
+ idlFilePath => $idlFilePath,
+ };
+
+ bless($reference, $class);
+ return $reference;
+}
+
+sub GenerateInterface
+{
+}
+
+sub WriteData
+{
+ my ($self, $interface, $outputDir) = @_;
+
+ foreach my $file ($self->_generateHeaderFile($interface), $self->_generateImplementationFile($interface)) {
+ $$self{codeGenerator}->UpdateFile(File::Spec->catfile($outputDir, $$file{name}), join("", @{$$file{contents}}));
+ }
+}
+
+sub _className
+{
+ my ($type) = @_;
+
+ return "JS" . _implementationClassName($type);
+}
+
+sub _classRefGetter
+{
+ my ($self, $type) = @_;
+
+ return $$self{codeGenerator}->WK_lcfirst(_implementationClassName($type)) . "Class";
+}
+
+sub _parseLicenseBlock
+{
+ my ($fileHandle) = @_;
+
+ my ($copyright, $readCount, $buffer, $currentCharacter, $previousCharacter);
+ my $startSentinel = "/*";
+ my $lengthOfStartSentinel = length($startSentinel);
+ $readCount = read($fileHandle, $buffer, $lengthOfStartSentinel);
+ return "" if ($readCount < $lengthOfStartSentinel || $buffer ne $startSentinel);
+ $copyright = $buffer;
+
+ while ($readCount = read($fileHandle, $currentCharacter, 1)) {
+ $copyright .= $currentCharacter;
+ return $copyright if $currentCharacter eq "/" && $previousCharacter eq "*";
+ $previousCharacter = $currentCharacter;
+ }
+
+ return "";
+}
+
+sub _parseLicenseBlockFromFile
+{
+ my ($path) = @_;
+ open my $fileHandle, "<", $path or die "Failed to open $path for reading: $!";
+ my $licenseBlock = _parseLicenseBlock($fileHandle);
+ close($fileHandle);
+ return $licenseBlock;
+}
+
+sub _defaultLicenseBlock
+{
+ return <<EOF;
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+EOF
+}
+
+sub _licenseBlock
+{
+ my ($self) = @_;
+ return $self->{licenseBlock} if $self->{licenseBlock};
+
+ my $licenseBlock = _parseLicenseBlockFromFile($self->{idlFilePath}) || _defaultLicenseBlock();
+ $self->{licenseBlock} = $licenseBlock;
+ return $licenseBlock;
+}
+
+sub _generateHeaderFile
+{
+ my ($self, $interface) = @_;
+
+ my @contents = ();
+
+ my $type = $interface->type;
+ my $className = _className($type);
+ my $implementationClassName = _implementationClassName($type);
+ my $filename = $className . ".h";
+
+ push(@contents, $self->_licenseBlock());
+
+ my $parentClassName = _parentClassName($interface);
+
+ push(@contents, <<EOF);
+
+#ifndef ${className}_h
+#define ${className}_h
+
+#include "${parentClassName}.h"
+EOF
+ push(@contents, <<EOF);
+
+namespace WTR {
+
+class ${implementationClassName};
+
+class ${className} : public ${parentClassName} {
+public:
+ static JSClassRef @{[$self->_classRefGetter($type)]}();
+
+private:
+ static const JSStaticFunction* staticFunctions();
+ static const JSStaticValue* staticValues();
+EOF
+
+ if (my @functions = @{$interface->functions}) {
+ push(@contents, "\n // Functions\n\n");
+ foreach my $function (@functions) {
+ push(@contents, " static JSValueRef @{[$function->name]}(JSContextRef, JSObjectRef, JSObjectRef, size_t, const JSValueRef[], JSValueRef*);\n");
+ }
+ }
+
+ if (my @attributes = @{$interface->attributes}) {
+ push(@contents, "\n // Attributes\n\n");
+ foreach my $attribute (@attributes) {
+ push(@contents, " static JSValueRef @{[$self->_getterName($attribute)]}(JSContextRef, JSObjectRef, JSStringRef, JSValueRef*);\n");
+ push(@contents, " static bool @{[$self->_setterName($attribute)]}(JSContextRef, JSObjectRef, JSStringRef, JSValueRef, JSValueRef*);\n") unless $attribute->isReadOnly;
+ }
+ }
+
+ push(@contents, <<EOF);
+};
+
+${implementationClassName}* to${implementationClassName}(JSContextRef, JSValueRef);
+
+} // namespace WTR
+
+#endif // ${className}_h
+EOF
+
+ return { name => $filename, contents => \@contents };
+}
+
+sub _generateImplementationFile
+{
+ my ($self, $interface) = @_;
+
+ my @contentsPrefix = ();
+ my %contentsIncludes = ();
+ my @contents = ();
+
+ my $type = $interface->type;
+ my $className = _className($type);
+ my $implementationClassName = _implementationClassName($type);
+ my $filename = $className . ".cpp";
+
+ push(@contentsPrefix, $self->_licenseBlock());
+
+ my $classRefGetter = $self->_classRefGetter($type);
+ my $parentClassName = _parentClassName($interface);
+
+ $contentsIncludes{"${className}.h"} = 1;
+ $contentsIncludes{"${implementationClassName}.h"} = 1;
+
+ push(@contentsPrefix, <<EOF);
+
+EOF
+
+ push(@contents, <<EOF);
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <wtf/GetPtr.h>
+
+namespace WTR {
+
+${implementationClassName}* to${implementationClassName}(JSContextRef context, JSValueRef value)
+{
+ if (!context || !value || !${className}::${classRefGetter}() || !JSValueIsObjectOfClass(context, value, ${className}::${classRefGetter}()))
+ return 0;
+ return static_cast<${implementationClassName}*>(JSWrapper::unwrap(context, value));
+}
+
+JSClassRef ${className}::${classRefGetter}()
+{
+ static JSClassRef jsClass;
+ if (!jsClass) {
+ JSClassDefinition definition = kJSClassDefinitionEmpty;
+ definition.className = "@{[$type->name]}";
+ definition.parentClass = @{[$self->_parentClassRefGetterExpression($interface)]};
+ definition.staticValues = staticValues();
+ definition.staticFunctions = staticFunctions();
+EOF
+
+ push(@contents, " definition.initialize = initialize;\n") unless _parentInterface($interface);
+ push(@contents, " definition.finalize = finalize;\n") unless _parentInterface($interface);
+
+ push(@contents, <<EOF);
+ jsClass = JSClassCreate(&definition);
+ }
+ return jsClass;
+}
+
+EOF
+
+ push(@contents, $self->_staticFunctionsGetterImplementation($interface), "\n");
+ push(@contents, $self->_staticValuesGetterImplementation($interface));
+
+ if (my @functions = @{$interface->functions}) {
+ push(@contents, "\n// Functions\n");
+
+ foreach my $function (@functions) {
+ push(@contents, <<EOF);
+
+JSValueRef ${className}::@{[$function->name]}(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ ${implementationClassName}* impl = to${implementationClassName}(context, thisObject);
+ if (!impl)
+ return JSValueMakeUndefined(context);
+
+EOF
+ my $functionCall;
+ if ($function->extendedAttributes->{"CustomArgumentHandling"}) {
+ $functionCall = "impl->" . $function->name . "(context, argumentCount, arguments, exception)";
+ } else {
+ my @arguments = ();
+ my @specifiedArguments = @{$function->arguments};
+
+ $self->_includeHeaders(\%contentsIncludes, $function->type);
+
+ if ($function->extendedAttributes->{"PassContext"}) {
+ push(@arguments, "context");
+ }
+
+ foreach my $i (0..$#specifiedArguments) {
+ my $argument = $specifiedArguments[$i];
+
+ $self->_includeHeaders(\%contentsIncludes, $type);
+
+ push(@contents, " " . $self->_platformTypeVariableDeclaration($argument->type, $argument->name, "arguments[$i]", "argumentCount > $i") . "\n");
+
+ push(@arguments, $self->_argumentExpression($argument));
+ }
+
+ $functionCall = "impl->" . $function->name . "(" . join(", ", @arguments) . ")";
+ }
+
+ push(@contents, " ${functionCall};\n\n") if $function->type->name eq "void";
+ push(@contents, " return " . $self->_returnExpression($function->type, $functionCall) . ";\n}\n");
+ }
+ }
+
+ if (my @attributes = @{$interface->attributes}) {
+ push(@contents, "\n// Attributes\n");
+ foreach my $attribute (@attributes) {
+ $self->_includeHeaders(\%contentsIncludes, $attribute->type);
+
+ my $getterName = $self->_getterName($attribute);
+ my $getterExpression = "impl->${getterName}()";
+
+ push(@contents, <<EOF);
+
+JSValueRef ${className}::${getterName}(JSContextRef context, JSObjectRef object, JSStringRef, JSValueRef* exception)
+{
+ ${implementationClassName}* impl = to${implementationClassName}(context, object);
+ if (!impl)
+ return JSValueMakeUndefined(context);
+
+ return @{[$self->_returnExpression($attribute->type, $getterExpression)]};
+}
+EOF
+
+ unless ($attribute->isReadOnly) {
+ push(@contents, <<EOF);
+
+bool ${className}::@{[$self->_setterName($attribute)]}(JSContextRef context, JSObjectRef object, JSStringRef, JSValueRef value, JSValueRef* exception)
+{
+ ${implementationClassName}* impl = to${implementationClassName}(context, object);
+ if (!impl)
+ return false;
+
+EOF
+
+ my $platformValue = $self->_platformTypeConstructor($attribute->type, "value");
+
+ push(@contents, <<EOF);
+ impl->@{[$self->_setterName($attribute)]}(${platformValue});
+
+ return true;
+}
+EOF
+ }
+ }
+ }
+
+ push(@contents, <<EOF);
+
+} // namespace WTR
+
+EOF
+
+ unshift(@contents, map { "#include \"$_\"\n" } sort keys(%contentsIncludes));
+ unshift(@contents, "#include \"config.h\"\n");
+ unshift(@contents, @contentsPrefix);
+
+ return { name => $filename, contents => \@contents };
+}
+
+sub _getterName
+{
+ my ($self, $attribute) = @_;
+
+ return $attribute->name;
+}
+
+sub _includeHeaders
+{
+ my ($self, $headers, $type) = @_;
+
+ return unless defined $type;
+ return if $type->name eq "boolean";
+ return if $type->name eq "object";
+ return if $$self{codeGenerator}->IsNonPointerType($type);
+ return if $$self{codeGenerator}->IsStringType($type);
+
+ $$headers{_className($type) . ".h"} = 1;
+ $$headers{_implementationClassName($type) . ".h"} = 1;
+}
+
+sub _implementationClassName
+{
+ my ($type) = @_;
+
+ return $type->name;
+}
+
+sub _parentClassName
+{
+ my ($interface) = @_;
+
+ my $parentInterface = _parentInterface($interface);
+ return $parentInterface ? _className($parentInterface) : "JSWrapper";
+}
+
+sub _parentClassRefGetterExpression
+{
+ my ($self, $interface) = @_;
+
+ my $parentInterface = _parentInterface($interface);
+ return $parentInterface ? $self->_classRefGetter($parentInterface) . "()" : "0";
+}
+
+sub _parentInterface
+{
+ my ($interface) = @_;
+ return $interface->parentType;
+}
+
+sub _platformType
+{
+ my ($self, $type) = @_;
+
+ return undef unless defined $type;
+
+ return "bool" if $type->name eq "boolean";
+ return "JSValueRef" if $type->name eq "object";
+ return "JSRetainPtr<JSStringRef>" if $$self{codeGenerator}->IsStringType($type);
+ return "double" if $$self{codeGenerator}->IsNonPointerType($type);
+ return _implementationClassName($type);
+}
+
+sub _platformTypeConstructor
+{
+ my ($self, $type, $argumentName) = @_;
+
+ return "JSValueToNullableBoolean(context, $argumentName)" if $type->name eq "boolean" && $type->isNullable;
+ return "JSValueToBoolean(context, $argumentName)" if $type->name eq "boolean";
+ return "$argumentName" if $type->name eq "object";
+ return "JSRetainPtr<JSStringRef>(Adopt, JSValueToStringCopy(context, $argumentName, 0))" if $$self{codeGenerator}->IsStringType($type);
+ return "JSValueToNumber(context, $argumentName, 0)" if $$self{codeGenerator}->IsNonPointerType($type);
+ return "to" . _implementationClassName($type) . "(context, $argumentName)";
+}
+
+sub _platformTypeVariableDeclaration
+{
+ my ($self, $type, $variableName, $argumentName, $condition) = @_;
+
+ my $platformType = $self->_platformType($type);
+ my $constructor = $self->_platformTypeConstructor($type, $argumentName);
+
+ my %nonPointerTypes = (
+ "bool" => 1,
+ "double" => 1,
+ "JSRetainPtr<JSStringRef>" => 1,
+ "JSValueRef" => 1,
+ );
+
+ my $nullValue = "0";
+ if ($platformType eq "JSValueRef") {
+ $nullValue = "JSValueMakeUndefined(context)";
+ } elsif (defined $nonPointerTypes{$platformType} && $platformType ne "double") {
+ $nullValue = "$platformType()";
+ }
+
+ $platformType .= "*" unless defined $nonPointerTypes{$platformType};
+
+ return "$platformType $variableName = $condition && $constructor;" if $condition && $platformType eq "bool";
+ return "$platformType $variableName = $condition ? $constructor : $nullValue;" if $condition;
+ return "$platformType $variableName = $constructor;";
+}
+
+sub _returnExpression
+{
+ my ($self, $returnType, $expression) = @_;
+
+ return "JSValueMakeUndefined(context)" if $returnType->name eq "void";
+ return "JSValueMakeBooleanOrNull(context, ${expression})" if $returnType->name eq "boolean" && $returnType->isNullable;
+ return "JSValueMakeBoolean(context, ${expression})" if $returnType->name eq "boolean";
+ return "${expression}" if $returnType->name eq "object";
+ return "JSValueMakeNumber(context, ${expression})" if $$self{codeGenerator}->IsNonPointerType($returnType);
+ return "JSValueMakeStringOrNull(context, ${expression}.get())" if $$self{codeGenerator}->IsStringType($returnType);
+ return "toJS(context, WTF::getPtr(${expression}))";
+}
+
+sub _argumentExpression
+{
+ my ($self, $argument) = @_;
+
+ my $type = $argument->type;
+ my $name = $argument->name;
+
+ return "${name}.get()" if $$self{codeGenerator}->IsStringType($type);
+ return $name;
+}
+
+sub _setterName
+{
+ my ($self, $attribute) = @_;
+
+ my $name = $attribute->name;
+
+ return "set" . $$self{codeGenerator}->WK_ucfirst($name);
+}
+
+sub _staticFunctionsGetterImplementation
+{
+ my ($self, $interface) = @_;
+
+ my $mapFunction = sub {
+ my $name = $_->name;
+ my @attributes = qw(kJSPropertyAttributeDontDelete kJSPropertyAttributeReadOnly);
+ push(@attributes, "kJSPropertyAttributeDontEnum") if $_->extendedAttributes->{"DontEnum"};
+
+ return "{ \"$name\", $name, " . join(" | ", @attributes) . " }";
+ };
+
+ return $self->_staticFunctionsOrValuesGetterImplementation($interface, "function", "{ 0, 0, 0 }", $mapFunction, $interface->functions);
+}
+
+sub _staticFunctionsOrValuesGetterImplementation
+{
+ my ($self, $interface, $functionOrValue, $arrayTerminator, $mapFunction, $functionsOrAttributes) = @_;
+
+ my $className = _className($interface->type);
+ my $uppercaseFunctionOrValue = $$self{codeGenerator}->WK_ucfirst($functionOrValue);
+
+ my $result = <<EOF;
+const JSStatic${uppercaseFunctionOrValue}* ${className}::static${uppercaseFunctionOrValue}s()
+{
+EOF
+
+ my @initializers = map(&$mapFunction, @{$functionsOrAttributes});
+ return $result . " return 0;\n}\n" unless @initializers;
+
+ $result .= <<EOF
+ static const JSStatic${uppercaseFunctionOrValue} ${functionOrValue}s[] = {
+ @{[join(",\n ", @initializers)]},
+ ${arrayTerminator}
+ };
+ return ${functionOrValue}s;
+}
+EOF
+}
+
+sub _staticValuesGetterImplementation
+{
+ my ($self, $interface) = @_;
+
+ my $mapFunction = sub {
+ return if $_->extendedAttributes->{"NoImplementation"};
+
+ my $attributeName = $_->name;
+ my $getterName = $self->_getterName($_);
+ my $setterName = $_->isReadOnly ? "0" : $self->_setterName($_);
+ my @attributes = qw(kJSPropertyAttributeDontDelete);
+ push(@attributes, "kJSPropertyAttributeReadOnly") if $_->isReadOnly;
+ push(@attributes, "kJSPropertyAttributeDontEnum") if $_->extendedAttributes->{"DontEnum"};
+
+ return "{ \"$attributeName\", $getterName, $setterName, " . join(" | ", @attributes) . " }";
+ };
+
+ return $self->_staticFunctionsOrValuesGetterImplementation($interface, "value", "{ 0, 0, 0, 0 }", $mapFunction, $interface->attributes);
+}
+
+1;
diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/EventSendingController.idl b/Tools/WebKitTestRunner/InjectedBundle/Bindings/EventSendingController.idl
new file mode 100644
index 000000000..f3280bb94
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/EventSendingController.idl
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2010, 2011, 2014-2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+interface EventSendingController {
+ void mouseDown(long buttonNumber, object modifierArray);
+ void mouseUp(long buttonNumber, object modifierArray);
+ void mouseMoveTo(long x, long y);
+ void mouseForceClick();
+ void startAndCancelMouseForceClick();
+ void mouseForceDown();
+ void mouseForceUp();
+ void mouseForceChanged(double force);
+ void mouseScrollBy(long x, long y);
+ void mouseScrollByWithWheelAndMomentumPhases(long x, long y, DOMString phase, DOMString momentum);
+ void swipeGestureWithWheelAndMomentumPhases(long x, long y, DOMString phase, DOMString momentum);
+ void continuousMouseScrollBy(long x, long y, optional boolean paged);
+ object contextClick();
+ void scheduleAsynchronousClick();
+
+ void leapForward(long milliseconds);
+
+ void keyDown(DOMString key, object modifierArray, long location);
+ void scheduleAsynchronousKeyDown(DOMString key);
+
+ // Zoom functions.
+ void textZoomIn();
+ void textZoomOut();
+ void zoomPageIn();
+ void zoomPageOut();
+ void scalePageBy(double scale, double x, double y);
+
+ void monitorWheelEvents();
+ void callAfterScrollingCompletes(object functionCallback);
+
+#if defined(ENABLE_TOUCH_EVENTS) && ENABLE_TOUCH_EVENTS
+ // Touch events.
+ void addTouchPoint(long x, long y);
+ void updateTouchPoint(long index, long x, long y);
+ void setTouchModifier(DOMString modifier, boolean enable);
+ void setTouchPointRadius(long radiusX, long radiusY);
+ void touchStart();
+ void touchMove();
+ void touchEnd();
+ void touchCancel();
+ void clearTouchPoints();
+ void releaseTouchPoint(long index);
+ void cancelTouchPoint(long index);
+#endif
+};
+
diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrappable.h b/Tools/WebKitTestRunner/InjectedBundle/Bindings/GCController.idl
index 5ec7197c5..fb933834d 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrappable.h
+++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/GCController.idl
@@ -23,25 +23,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef JSWrappable_h
-#define JSWrappable_h
-
-#include <JavaScriptCore/JavaScript.h>
-#include <wtf/RefCounted.h>
-
-namespace WTR {
-
-class JSWrappable : public RefCounted<JSWrappable> {
-public:
- virtual ~JSWrappable() { }
- virtual JSClassRef wrapperClass() = 0;
+interface GCController {
+ void collect();
+ void collectOnAlternateThread(boolean waitUntilDone);
+ unsigned long long getJSObjectCount();
};
-inline JSValueRef JSValueMakeStringOrNull(JSContextRef context, JSStringRef stringOrNull)
-{
- return stringOrNull ? JSValueMakeString(context, stringOrNull) : JSValueMakeNull(context);
-}
-
-} // namespace WTR
-
-#endif // JSWrappable_h
diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl b/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl
new file mode 100644
index 000000000..352fa0ae7
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2010-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+interface TestRunner {
+ readonly attribute boolean isWebKit2;
+
+ // The basics.
+ void dumpAsText(boolean dumpPixels);
+ void dumpChildFramesAsText();
+ void waitForPolicyDelegate();
+ void waitUntilDone();
+ void waitUntilDownloadFinished();
+ void notifyDone();
+ double preciseTime();
+ readonly attribute double timeout;
+
+ // Other dumping.
+ void dumpBackForwardList();
+ void dumpChildFrameScrollPositions();
+ void dumpEditingCallbacks();
+ void dumpSelectionRect();
+ void dumpStatusCallbacks();
+ void dumpTitleChanges();
+ void dumpFullScreenCallbacks();
+ void dumpFrameLoadCallbacks();
+ void dumpProgressFinishedCallback();
+ void dumpResourceLoadCallbacks();
+ void dumpResourceResponseMIMETypes();
+ void dumpWillCacheResponse();
+ void dumpApplicationCacheDelegateCallbacks();
+ void dumpDatabaseCallbacks();
+ void dumpDOMAsWebArchive();
+ void dumpPolicyDelegateCallbacks();
+
+ // Special options.
+ void keepWebHistory();
+ void setAcceptsEditing(boolean value);
+ void setCanOpenWindows(boolean value);
+ void setCloseRemainingWindowsWhenComplete(boolean value);
+ void setXSSAuditorEnabled(boolean value);
+ void setAllowUniversalAccessFromFileURLs(boolean value);
+ void setAllowFileAccessFromFileURLs(boolean value);
+ void setNeedsStorageAccessFromFileURLsQuirk(boolean value);
+ void setPluginsEnabled(boolean value);
+ void setJavaScriptCanAccessClipboard(boolean value);
+ void setPrivateBrowsingEnabled(boolean value);
+ void setUseDashboardCompatibilityMode(boolean value);
+ void setPopupBlockingEnabled(boolean value);
+ void setAuthorAndUserStylesEnabled(boolean value);
+ void setCustomPolicyDelegate(boolean enabled, boolean permissive);
+ void addOriginAccessWhitelistEntry(DOMString sourceOrigin, DOMString destinationProtocol, DOMString destinationHost, boolean allowDestinationSubdomains);
+ void removeOriginAccessWhitelistEntry(DOMString sourceOrigin, DOMString destinationProtocol, DOMString destinationHost, boolean allowDestinationSubdomains);
+ void setUserStyleSheetEnabled(boolean value);
+ void setUserStyleSheetLocation(DOMString location);
+ void setSpatialNavigationEnabled(boolean value);
+ void setTabKeyCyclesThroughElements(boolean enabled);
+ void setSerializeHTTPLoads();
+ void dispatchPendingLoadRequests();
+ void setCacheModel(long model);
+ void setAsynchronousSpellCheckingEnabled(boolean value);
+ void setPrinting();
+ void setShouldDecideNavigationPolicyAfterDelay(boolean value);
+ void setNavigationGesturesEnabled(boolean value);
+ void setIgnoresViewportScaleLimits(boolean value);
+ void setShouldDownloadUndisplayableMIMETypes(boolean value);
+
+ // Special DOM functions.
+ void clearBackForwardList();
+ void execCommand(DOMString name, DOMString argument);
+ boolean isCommandEnabled(DOMString name);
+ unsigned long windowCount();
+
+ // Special DOM variables.
+ attribute boolean globalFlag;
+
+ // Repaint testing.
+ void testRepaint();
+ void repaintSweepHorizontally();
+ void display();
+
+ // Printing
+ boolean isPageBoxVisible(long pageIndex);
+
+ [PassContext] void setValueForUser(object element, DOMString value);
+
+ // UserContent testing.
+ void addUserScript(DOMString source, boolean runAtStart, boolean allFrames);
+ void addUserStyleSheet(DOMString source, boolean allFrames);
+
+ // Local storage API
+ void clearAllDatabases();
+ void setDatabaseQuota(unsigned long long quota);
+ DOMString pathToLocalResource(DOMString url);
+
+ attribute double databaseDefaultQuota;
+ attribute double databaseMaxQuota;
+
+ // Application Cache API
+ void clearAllApplicationCaches();
+ void setAppCacheMaximumSize(unsigned long long size);
+ long long applicationCacheDiskUsageForOrigin(DOMString origin);
+ void clearApplicationCacheForOrigin(DOMString name);
+ void disallowIncreaseForApplicationCacheQuota();
+ object originsWithApplicationCache();
+
+ // Text search testing.
+ boolean findString(DOMString target, object optionsArray);
+
+ // Evaluating script in a special context.
+ [PassContext] void evaluateScriptInIsolatedWorld(unsigned long worldID, DOMString script);
+
+ // For Web Inspector tests
+ void showWebInspector();
+ void closeWebInspector();
+ void evaluateInWebInspector(DOMString script);
+ readonly attribute DOMString inspectorTestStubURL;
+
+ void setPOSIXLocale(DOMString locale);
+
+ void setTextDirection(DOMString direction);
+
+ void setWillSendRequestReturnsNull(boolean flag);
+ void setWillSendRequestReturnsNullOnRedirect(boolean flag);
+ void setWillSendRequestAddsHTTPBody(DOMString body);
+
+ void setShouldStayOnPageAfterHandlingBeforeUnload(boolean flag);
+
+ void setDefersLoading(boolean flag);
+ void setStopProvisionalFrameLoads();
+
+ // Focus testing.
+ void addChromeInputField(object callback);
+ void removeChromeInputField(object callback);
+ void focusWebView(object callback);
+
+ // Window/view state
+ void setBackingScaleFactor(double backingScaleFactor, object callback);
+
+ void setWindowIsKey(boolean isKey);
+ void setViewSize(double width, double height);
+
+ // Cookies testing
+ void setAlwaysAcceptCookies(boolean accept);
+
+ void overridePreference(DOMString preference, DOMString value);
+
+ // Page Visibility API
+ void setPageVisibility(DOMString state);
+ void resetPageVisibility();
+
+ // Control full screen behavior.
+ void setHasCustomFullScreenBehavior(boolean value);
+
+ // Web notifications support
+ void grantWebNotificationPermission(DOMString origin);
+ void denyWebNotificationPermission(DOMString origin);
+ void removeAllWebNotificationPermissions();
+ void simulateWebNotificationClick(object notification);
+
+ // Geolocation
+ void setGeolocationPermission(boolean value);
+ void setMockGeolocationPosition(double latitude, double longitude, double accuracy, optional object altitude, optional object altitudeAccuracy, optional object heading, optional object speed);
+ void setMockGeolocationPositionUnavailableError(DOMString errorMessage);
+ boolean isGeolocationProviderActive();
+
+ // MediaStream
+ void setUserMediaPermission(boolean value);
+ void setUserMediaPersistentPermissionForOrigin(boolean permission, DOMString origin, DOMString parentOrigin);
+ unsigned long userMediaPermissionRequestCountForOrigin(DOMString origin, DOMString parentOrigin);
+ void resetUserMediaPermissionRequestCountForOrigin(DOMString origin, DOMString parentOrigin);
+
+ // Audio testing.
+ [PassContext] void setAudioResult(object data);
+
+ boolean callShouldCloseOnWebView();
+
+ // Work queue.
+ void queueBackNavigation(unsigned long howFarBackward);
+ void queueForwardNavigation(unsigned long howFarForward);
+ void queueLoad(DOMString url, DOMString target, optional boolean shouldOpenExternalURLs);
+ void queueLoadHTMLString(DOMString content, optional DOMString baseURL, optional DOMString unreachableURL);
+ void queueReload();
+ void queueLoadingScript(DOMString script);
+ void queueNonLoadingScript(DOMString script);
+
+ // Authentication
+ void setRejectsProtectionSpaceAndContinueForAuthenticationChallenges(boolean value);
+ void setHandlesAuthenticationChallenges(boolean value);
+ void setShouldLogCanAuthenticateAgainstProtectionSpace(boolean value);
+ void setAuthenticationUsername(DOMString username);
+ void setAuthenticationPassword(DOMString password);
+
+ void setAllowsAnySSLCertificate(boolean value);
+
+ // Secure text input mode (Mac only)
+ readonly attribute boolean secureEventInputIsEnabled;
+
+ // Override plugin load policy.
+ void setBlockAllPlugins(boolean shouldBlock);
+
+ // Hooks to the JSC compiler.
+ object failNextNewCodeBlock();
+ object numberOfDFGCompiles(object function);
+ object neverInlineFunction(object function);
+
+ // Swipe gestures
+ void installDidBeginSwipeCallback(object callback);
+ void installWillEndSwipeCallback(object callback);
+ void installDidEndSwipeCallback(object callback);
+ void installDidRemoveSwipeSnapshotCallback(object callback);
+
+ unsigned long imageCountInGeneralPasteboard();
+
+ // UI Process Testing
+ void runUIScript(DOMString script, object callback);
+
+ void clearTestRunnerCallbacks();
+
+ void accummulateLogsForChannel(DOMString channel);
+
+ // Gamepad
+ void setMockGamepadDetails(unsigned long index, DOMString id, unsigned long axisCount, unsigned long buttonCount);
+ void setMockGamepadAxisValue(unsigned long index, unsigned long axisIndex, double value);
+ void setMockGamepadButtonValue(unsigned long index, unsigned long buttonIndex, double value);
+ void connectMockGamepad(unsigned long index);
+ void disconnectMockGamepad(unsigned long index);
+
+ // Resource Load Statistics
+ void installStatisticsDidModifyDataRecordsCallback(object callback);
+ void setStatisticsPrevalentResource(DOMString hostName, boolean value);
+ boolean isStatisticsPrevalentResource(DOMString hostName);
+ void setStatisticsHasHadUserInteraction(DOMString hostName, boolean value);
+ boolean isStatisticsHasHadUserInteraction(DOMString hostName);
+ void setStatisticsTimeToLiveUserInteraction(double seconds);
+ void statisticsFireDataModificationHandler();
+ void setStatisticsNotifyPagesWhenDataRecordsWereScanned(boolean value);
+ void setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(boolean value);
+ void setStatisticsMinimumTimeBetweeenDataRecordsRemoval(double seconds);
+ void statisticsResetToConsistentState();
+};
diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/TextInputController.idl b/Tools/WebKitTestRunner/InjectedBundle/Bindings/TextInputController.idl
new file mode 100644
index 000000000..d95a6985d
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/TextInputController.idl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+interface TextInputController {
+ void setMarkedText(DOMString string, long from, long length);
+ boolean hasMarkedText();
+ void unmarkText();
+ void insertText(DOMString string);
+};
+
diff --git a/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.cpp b/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.cpp
index 65e355652..6bd165288 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.cpp
+++ b/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2011, 2014-2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,13 +30,13 @@
#include "InjectedBundlePage.h"
#include "JSEventSendingController.h"
#include "StringFunctions.h"
-#include <WebKit2/WKBundle.h>
-#include <WebKit2/WKBundleFrame.h>
-#include <WebKit2/WKBundlePagePrivate.h>
-#include <WebKit2/WKBundlePrivate.h>
-#include <WebKit2/WKContextMenuItem.h>
-#include <WebKit2/WKMutableDictionary.h>
-#include <WebKit2/WKNumber.h>
+#include <WebKit/WKBundle.h>
+#include <WebKit/WKBundleFrame.h>
+#include <WebKit/WKBundlePagePrivate.h>
+#include <WebKit/WKBundlePrivate.h>
+#include <WebKit/WKContextMenuItem.h>
+#include <WebKit/WKMutableDictionary.h>
+#include <WebKit/WKNumber.h>
#include <wtf/StdLibExtras.h>
namespace WTR {
@@ -116,6 +116,8 @@ static WKEventModifiers parseModifier(JSStringRef modifier)
return kWKEventModifiersAltKey;
if (JSStringIsEqualToUTF8CString(modifier, "metaKey"))
return kWKEventModifiersMetaKey;
+ if (JSStringIsEqualToUTF8CString(modifier, "capsLockKey"))
+ return kWKEventModifiersCapsLockKey;
if (JSStringIsEqualToUTF8CString(modifier, "addSelectionKey")) {
#if OS(MAC_OS_X)
return kWKEventModifiersMetaKey;
@@ -164,9 +166,9 @@ static WKEventModifiers parseModifierArray(JSContextRef context, JSValueRef arra
return modifiers;
}
-PassRefPtr<EventSendingController> EventSendingController::create()
+Ref<EventSendingController> EventSendingController::create()
{
- return adoptRef(new EventSendingController);
+ return adoptRef(*new EventSendingController);
}
EventSendingController::EventSendingController()
@@ -208,7 +210,8 @@ static WKMutableDictionaryRef createMouseMessageBody(MouseState state, int butto
void EventSendingController::mouseDown(int button, JSValueRef modifierArray)
{
- WKBundlePageRef page = InjectedBundle::shared().page()->page();
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundlePageRef page = injectedBundle.page()->page();
WKBundleFrameRef frame = WKBundlePageGetMainFrame(page);
JSContextRef context = WKBundleFrameGetJavaScriptContext(frame);
WKEventModifiers modifiers = parseModifierArray(context, modifierArray);
@@ -216,12 +219,12 @@ void EventSendingController::mouseDown(int button, JSValueRef modifierArray)
WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender"));
WKRetainPtr<WKMutableDictionaryRef> EventSenderMessageBody(AdoptWK, createMouseMessageBody(MouseDown, button, modifiers));
- WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
+ WKBundlePagePostSynchronousMessageForTesting(page, EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
}
void EventSendingController::mouseUp(int button, JSValueRef modifierArray)
{
- WKBundlePageRef page = InjectedBundle::shared().page()->page();
+ WKBundlePageRef page = InjectedBundle::singleton().page()->page();
WKBundleFrameRef frame = WKBundlePageGetMainFrame(page);
JSContextRef context = WKBundleFrameGetJavaScriptContext(frame);
WKEventModifiers modifiers = parseModifierArray(context, modifierArray);
@@ -229,7 +232,7 @@ void EventSendingController::mouseUp(int button, JSValueRef modifierArray)
WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender"));
WKRetainPtr<WKMutableDictionaryRef> EventSenderMessageBody(AdoptWK, createMouseMessageBody(MouseUp, button, modifiers));
- WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
+ WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
}
void EventSendingController::mouseMoveTo(int x, int y)
@@ -249,7 +252,73 @@ void EventSendingController::mouseMoveTo(int x, int y)
WKRetainPtr<WKDoubleRef> yRef(AdoptWK, WKDoubleCreate(y));
WKDictionarySetItem(EventSenderMessageBody.get(), yKey.get(), yRef.get());
- WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
+ m_position = WKPointMake(x, y);
+
+ WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
+}
+
+void EventSendingController::mouseForceClick()
+{
+ WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender"));
+ WKRetainPtr<WKMutableDictionaryRef> EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate());
+
+ WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
+ WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("MouseForceClick"));
+ WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get());
+
+ WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
+}
+
+void EventSendingController::startAndCancelMouseForceClick()
+{
+ WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender"));
+ WKRetainPtr<WKMutableDictionaryRef> EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate());
+
+ WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
+ WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("StartAndCancelMouseForceClick"));
+ WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get());
+
+ WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
+}
+
+void EventSendingController::mouseForceDown()
+{
+ WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender"));
+ WKRetainPtr<WKMutableDictionaryRef> EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate());
+
+ WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
+ WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("MouseForceDown"));
+ WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get());
+
+ WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
+}
+
+void EventSendingController::mouseForceUp()
+{
+ WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender"));
+ WKRetainPtr<WKMutableDictionaryRef> EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate());
+
+ WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
+ WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("MouseForceUp"));
+ WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get());
+
+ WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
+}
+
+void EventSendingController::mouseForceChanged(double force)
+{
+ WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender"));
+ WKRetainPtr<WKMutableDictionaryRef> EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate());
+
+ WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
+ WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("MouseForceChanged"));
+ WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get());
+
+ WKRetainPtr<WKStringRef> forceKey(AdoptWK, WKStringCreateWithUTF8CString("Force"));
+ WKRetainPtr<WKDoubleRef> forceRef(AdoptWK, WKDoubleCreate(force));
+ WKDictionarySetItem(EventSenderMessageBody.get(), forceKey.get(), forceRef.get());
+
+ WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
}
void EventSendingController::leapForward(int milliseconds)
@@ -265,7 +334,7 @@ void EventSendingController::leapForward(int milliseconds)
WKRetainPtr<WKUInt64Ref> timeRef(AdoptWK, WKUInt64Create(milliseconds));
WKDictionarySetItem(EventSenderMessageBody.get(), timeKey.get(), timeRef.get());
- WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
+ WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
}
void EventSendingController::scheduleAsynchronousClick()
@@ -277,11 +346,11 @@ void EventSendingController::scheduleAsynchronousClick()
// Asynchronous mouse down.
WKRetainPtr<WKMutableDictionaryRef> mouseDownMessageBody(AdoptWK, createMouseMessageBody(MouseDown, button, modifiers));
- WKBundlePostMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), mouseDownMessageBody.get());
+ WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), mouseDownMessageBody.get());
// Asynchronous mouse up.
WKRetainPtr<WKMutableDictionaryRef> mouseUpMessageBody(AdoptWK, createMouseMessageBody(MouseUp, button, modifiers));
- WKBundlePostMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), mouseUpMessageBody.get());
+ WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), mouseUpMessageBody.get());
}
static WKRetainPtr<WKMutableDictionaryRef> createKeyDownMessageBody(JSStringRef key, WKEventModifiers modifiers, int location)
@@ -308,7 +377,7 @@ static WKRetainPtr<WKMutableDictionaryRef> createKeyDownMessageBody(JSStringRef
void EventSendingController::keyDown(JSStringRef key, JSValueRef modifierArray, int location)
{
- WKBundlePageRef page = InjectedBundle::shared().page()->page();
+ WKBundlePageRef page = InjectedBundle::singleton().page()->page();
WKBundleFrameRef frame = WKBundlePageGetMainFrame(page);
JSContextRef context = WKBundleFrameGetJavaScriptContext(frame);
WKEventModifiers modifiers = parseModifierArray(context, modifierArray);
@@ -316,7 +385,7 @@ void EventSendingController::keyDown(JSStringRef key, JSValueRef modifierArray,
WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender"));
WKRetainPtr<WKMutableDictionaryRef> keyDownMessageBody = createKeyDownMessageBody(key, modifiers, location);
- WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), keyDownMessageBody.get(), 0);
+ WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), keyDownMessageBody.get(), 0);
}
void EventSendingController::scheduleAsynchronousKeyDown(JSStringRef key)
@@ -324,7 +393,7 @@ void EventSendingController::scheduleAsynchronousKeyDown(JSStringRef key)
WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender"));
WKRetainPtr<WKMutableDictionaryRef> keyDownMessageBody = createKeyDownMessageBody(key, 0 /* modifiers */, 0 /* location */);
- WKBundlePostMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), keyDownMessageBody.get());
+ WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), keyDownMessageBody.get());
}
void EventSendingController::mouseScrollBy(int x, int y)
@@ -344,7 +413,106 @@ void EventSendingController::mouseScrollBy(int x, int y)
WKRetainPtr<WKDoubleRef> yRef(AdoptWK, WKDoubleCreate(y));
WKDictionarySetItem(EventSenderMessageBody.get(), yKey.get(), yRef.get());
- WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
+ WKBundlePageForceRepaint(InjectedBundle::singleton().page()->page()); // Triggers a scrolling tree commit.
+ WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get());
+}
+
+static uint64_t cgEventPhaseFromString(JSStringRef phaseStr)
+{
+ if (JSStringIsEqualToUTF8CString(phaseStr, "none"))
+ return 0;
+ if (JSStringIsEqualToUTF8CString(phaseStr, "began"))
+ return 1; // kCGScrollPhaseBegan
+ if (JSStringIsEqualToUTF8CString(phaseStr, "changed"))
+ return 2; // kCGScrollPhaseChanged
+ if (JSStringIsEqualToUTF8CString(phaseStr, "ended"))
+ return 4; // kCGScrollPhaseEnded
+ if (JSStringIsEqualToUTF8CString(phaseStr, "cancelled"))
+ return 8; // kCGScrollPhaseCancelled
+ if (JSStringIsEqualToUTF8CString(phaseStr, "maybegin"))
+ return 128; // kCGScrollPhaseMayBegin
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+static uint64_t cgEventMomentumPhaseFromString(JSStringRef phaseStr)
+{
+ if (JSStringIsEqualToUTF8CString(phaseStr, "none"))
+ return 0; // kCGMomentumScrollPhaseNone
+ if (JSStringIsEqualToUTF8CString(phaseStr, "begin"))
+ return 1; // kCGMomentumScrollPhaseBegin
+ if (JSStringIsEqualToUTF8CString(phaseStr, "continue"))
+ return 2; // kCGMomentumScrollPhaseContinue
+ if (JSStringIsEqualToUTF8CString(phaseStr, "end"))
+ return 3; // kCGMomentumScrollPhaseEnd
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+void EventSendingController::mouseScrollByWithWheelAndMomentumPhases(int x, int y, JSStringRef phaseStr, JSStringRef momentumStr)
+{
+ WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender"));
+ WKRetainPtr<WKMutableDictionaryRef> EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate());
+
+ WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
+ WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("MouseScrollByWithWheelAndMomentumPhases"));
+ WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get());
+
+ WKRetainPtr<WKStringRef> xKey(AdoptWK, WKStringCreateWithUTF8CString("X"));
+ WKRetainPtr<WKDoubleRef> xRef(AdoptWK, WKDoubleCreate(x));
+ WKDictionarySetItem(EventSenderMessageBody.get(), xKey.get(), xRef.get());
+
+ WKRetainPtr<WKStringRef> yKey(AdoptWK, WKStringCreateWithUTF8CString("Y"));
+ WKRetainPtr<WKDoubleRef> yRef(AdoptWK, WKDoubleCreate(y));
+ WKDictionarySetItem(EventSenderMessageBody.get(), yKey.get(), yRef.get());
+
+ uint64_t phase = cgEventPhaseFromString(phaseStr);
+ uint64_t momentum = cgEventMomentumPhaseFromString(momentumStr);
+
+ WKRetainPtr<WKStringRef> phaseKey(AdoptWK, WKStringCreateWithUTF8CString("Phase"));
+ WKRetainPtr<WKUInt64Ref> phaseRef(AdoptWK, WKUInt64Create(phase));
+ WKDictionarySetItem(EventSenderMessageBody.get(), phaseKey.get(), phaseRef.get());
+
+ WKRetainPtr<WKStringRef> momentumKey(AdoptWK, WKStringCreateWithUTF8CString("Momentum"));
+ WKRetainPtr<WKUInt64Ref> momentumRef(AdoptWK, WKUInt64Create(momentum));
+ WKDictionarySetItem(EventSenderMessageBody.get(), momentumKey.get(), momentumRef.get());
+
+ WKBundlePageForceRepaint(InjectedBundle::singleton().page()->page()); // Triggers a scrolling tree commit.
+ WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get());
+}
+
+void EventSendingController::swipeGestureWithWheelAndMomentumPhases(int x, int y, JSStringRef phaseStr, JSStringRef momentumStr)
+{
+ WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender"));
+ WKRetainPtr<WKMutableDictionaryRef> EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate());
+
+ WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
+ WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("SwipeGestureWithWheelAndMomentumPhases"));
+ WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get());
+
+ WKRetainPtr<WKStringRef> xKey(AdoptWK, WKStringCreateWithUTF8CString("X"));
+ WKRetainPtr<WKDoubleRef> xRef(AdoptWK, WKDoubleCreate(x));
+ WKDictionarySetItem(EventSenderMessageBody.get(), xKey.get(), xRef.get());
+
+ WKRetainPtr<WKStringRef> yKey(AdoptWK, WKStringCreateWithUTF8CString("Y"));
+ WKRetainPtr<WKDoubleRef> yRef(AdoptWK, WKDoubleCreate(y));
+ WKDictionarySetItem(EventSenderMessageBody.get(), yKey.get(), yRef.get());
+
+ uint64_t phase = cgEventPhaseFromString(phaseStr);
+ uint64_t momentum = cgEventMomentumPhaseFromString(momentumStr);
+
+ WKRetainPtr<WKStringRef> phaseKey(AdoptWK, WKStringCreateWithUTF8CString("Phase"));
+ WKRetainPtr<WKUInt64Ref> phaseRef(AdoptWK, WKUInt64Create(phase));
+ WKDictionarySetItem(EventSenderMessageBody.get(), phaseKey.get(), phaseRef.get());
+
+ WKRetainPtr<WKStringRef> momentumKey(AdoptWK, WKStringCreateWithUTF8CString("Momentum"));
+ WKRetainPtr<WKUInt64Ref> momentumRef(AdoptWK, WKUInt64Create(momentum));
+ WKDictionarySetItem(EventSenderMessageBody.get(), momentumKey.get(), momentumRef.get());
+
+ WKBundlePageForceRepaint(InjectedBundle::singleton().page()->page()); // Triggers a scrolling tree commit.
+ WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get());
}
void EventSendingController::continuousMouseScrollBy(int x, int y, bool paged)
@@ -368,31 +536,33 @@ void EventSendingController::continuousMouseScrollBy(int x, int y, bool paged)
WKRetainPtr<WKUInt64Ref> pagedRef(AdoptWK, WKUInt64Create(paged));
WKDictionarySetItem(EventSenderMessageBody.get(), pagedKey.get(), pagedRef.get());
- WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
+ // FIXME: This message should be asynchronous, as scrolling is intrinsically asynchronous.
+ // See also: <https://bugs.webkit.org/show_bug.cgi?id=148256>.
+ WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
}
JSValueRef EventSendingController::contextClick()
{
- WKBundlePageRef page = InjectedBundle::shared().page()->page();
+ WKBundlePageRef page = InjectedBundle::singleton().page()->page();
WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(page);
JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
#if ENABLE(CONTEXT_MENUS)
- // Do mouse context click.
- mouseDown(2, 0);
- mouseUp(2, 0);
+ WKRetainPtr<WKArrayRef> menuEntries = adoptWK(WKBundlePageCopyContextMenuAtPointInWindow(page, m_position));
+ JSValueRef arrayResult = JSObjectMakeArray(context, 0, 0, 0);
+ if (!menuEntries)
+ return arrayResult;
- WKRetainPtr<WKArrayRef> menuEntries = adoptWK(WKBundlePageCopyContextMenuItems(page));
+ JSObjectRef arrayObj = JSValueToObject(context, arrayResult, 0);
size_t entriesSize = WKArrayGetSize(menuEntries.get());
- auto jsValuesArray = std::make_unique<JSValueRef[]>(entriesSize);
for (size_t i = 0; i < entriesSize; ++i) {
ASSERT(WKGetTypeID(WKArrayGetItemAtIndex(menuEntries.get(), i)) == WKContextMenuItemGetTypeID());
WKContextMenuItemRef item = static_cast<WKContextMenuItemRef>(WKArrayGetItemAtIndex(menuEntries.get(), i));
MenuItemPrivateData* privateData = new MenuItemPrivateData(page, item);
- jsValuesArray[i] = JSObjectMake(context, getMenuItemClass(), privateData);
+ JSObjectSetPropertyAtIndex(context, arrayObj, i, JSObjectMake(context, getMenuItemClass(), privateData), 0);
}
- return JSObjectMakeArray(context, entriesSize, jsValuesArray.get(), 0);
+ return arrayResult;
#else
return JSValueMakeUndefined(context);
#endif
@@ -400,44 +570,96 @@ JSValueRef EventSendingController::contextClick()
void EventSendingController::textZoomIn()
{
+ auto& injectedBundle = InjectedBundle::singleton();
// Ensure page zoom is reset.
- WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), 1);
+ WKBundlePageSetPageZoomFactor(injectedBundle.page()->page(), 1);
- double zoomFactor = WKBundlePageGetTextZoomFactor(InjectedBundle::shared().page()->page());
- WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor * ZoomMultiplierRatio);
+ double zoomFactor = WKBundlePageGetTextZoomFactor(injectedBundle.page()->page());
+ WKBundlePageSetTextZoomFactor(injectedBundle.page()->page(), zoomFactor * ZoomMultiplierRatio);
}
void EventSendingController::textZoomOut()
{
+ auto& injectedBundle = InjectedBundle::singleton();
// Ensure page zoom is reset.
- WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), 1);
+ WKBundlePageSetPageZoomFactor(injectedBundle.page()->page(), 1);
- double zoomFactor = WKBundlePageGetTextZoomFactor(InjectedBundle::shared().page()->page());
- WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor / ZoomMultiplierRatio);
+ double zoomFactor = WKBundlePageGetTextZoomFactor(injectedBundle.page()->page());
+ WKBundlePageSetTextZoomFactor(injectedBundle.page()->page(), zoomFactor / ZoomMultiplierRatio);
}
void EventSendingController::zoomPageIn()
{
+ auto& injectedBundle = InjectedBundle::singleton();
// Ensure text zoom is reset.
- WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), 1);
+ WKBundlePageSetTextZoomFactor(injectedBundle.page()->page(), 1);
- double zoomFactor = WKBundlePageGetPageZoomFactor(InjectedBundle::shared().page()->page());
- WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor * ZoomMultiplierRatio);
+ double zoomFactor = WKBundlePageGetPageZoomFactor(injectedBundle.page()->page());
+ WKBundlePageSetPageZoomFactor(injectedBundle.page()->page(), zoomFactor * ZoomMultiplierRatio);
}
void EventSendingController::zoomPageOut()
{
+ auto& injectedBundle = InjectedBundle::singleton();
// Ensure text zoom is reset.
- WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), 1);
+ WKBundlePageSetTextZoomFactor(injectedBundle.page()->page(), 1);
- double zoomFactor = WKBundlePageGetPageZoomFactor(InjectedBundle::shared().page()->page());
- WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor / ZoomMultiplierRatio);
+ double zoomFactor = WKBundlePageGetPageZoomFactor(injectedBundle.page()->page());
+ WKBundlePageSetPageZoomFactor(injectedBundle.page()->page(), zoomFactor / ZoomMultiplierRatio);
}
void EventSendingController::scalePageBy(double scale, double x, double y)
{
WKPoint origin = { x, y };
- WKBundlePageSetScaleAtOrigin(InjectedBundle::shared().page()->page(), scale, origin);
+ WKBundlePageSetScaleAtOrigin(InjectedBundle::singleton().page()->page(), scale, origin);
+}
+
+void EventSendingController::monitorWheelEvents()
+{
+ WKBundlePageRef page = InjectedBundle::singleton().page()->page();
+
+ WKBundlePageStartMonitoringScrollOperations(page);
+}
+
+struct ScrollCompletionCallbackData {
+ JSContextRef m_context;
+ JSObjectRef m_function;
+
+ ScrollCompletionCallbackData(JSContextRef context, JSObjectRef function)
+ : m_context(context), m_function(function)
+ {
+ }
+};
+
+static void executeCallback(void* context)
+{
+ if (!context)
+ return;
+
+ std::unique_ptr<ScrollCompletionCallbackData> callBackData(reinterpret_cast<ScrollCompletionCallbackData*>(context));
+
+ JSObjectCallAsFunction(callBackData->m_context, callBackData->m_function, nullptr, 0, nullptr, nullptr);
+ JSValueUnprotect(callBackData->m_context, callBackData->m_function);
+}
+
+void EventSendingController::callAfterScrollingCompletes(JSValueRef functionCallback)
+{
+ if (!functionCallback)
+ return;
+
+ WKBundlePageRef page = InjectedBundle::singleton().page()->page();
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(page);
+ JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
+
+ JSObjectRef functionCallbackObject = JSValueToObject(context, functionCallback, nullptr);
+ if (!functionCallbackObject)
+ return;
+
+ JSValueProtect(context, functionCallbackObject);
+
+ auto scrollCompletionCallbackData = std::make_unique<ScrollCompletionCallbackData>(context, functionCallbackObject);
+
+ WKBundlePageRegisterScrollOperationCompletionCallback(page, executeCallback, scrollCompletionCallbackData.release());
}
#if ENABLE(TOUCH_EVENTS)
@@ -458,7 +680,7 @@ void EventSendingController::addTouchPoint(int x, int y)
WKRetainPtr<WKUInt64Ref> yRef(AdoptWK, WKUInt64Create(y));
WKDictionarySetItem(EventSenderMessageBody.get(), yKey.get(), yRef.get());
- WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
+ WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
}
void EventSendingController::updateTouchPoint(int index, int x, int y)
@@ -482,7 +704,7 @@ void EventSendingController::updateTouchPoint(int index, int x, int y)
WKRetainPtr<WKUInt64Ref> yRef(AdoptWK, WKUInt64Create(y));
WKDictionarySetItem(EventSenderMessageBody.get(), yKey.get(), yRef.get());
- WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
+ WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
}
void EventSendingController::setTouchModifier(const JSStringRef &modifier, bool enable)
@@ -512,7 +734,7 @@ void EventSendingController::setTouchModifier(const JSStringRef &modifier, bool
WKRetainPtr<WKUInt64Ref> enableRef(AdoptWK, WKUInt64Create(enable));
WKDictionarySetItem(EventSenderMessageBody.get(), enableKey.get(), enableRef.get());
- WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
+ WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
}
@@ -533,7 +755,7 @@ void EventSendingController::setTouchPointRadius(int radiusX, int radiusY)
WKRetainPtr<WKUInt64Ref> yRef(AdoptWK, WKUInt64Create(radiusY));
WKDictionarySetItem(EventSenderMessageBody.get(), yKey.get(), yRef.get());
- WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
+ WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
}
void EventSendingController::touchStart()
@@ -545,7 +767,7 @@ void EventSendingController::touchStart()
WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("TouchStart"));
WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get());
- WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
+ WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
}
void EventSendingController::touchMove()
@@ -557,7 +779,7 @@ void EventSendingController::touchMove()
WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("TouchMove"));
WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get());
- WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
+ WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
}
void EventSendingController::touchEnd()
@@ -569,7 +791,7 @@ void EventSendingController::touchEnd()
WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("TouchEnd"));
WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get());
- WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
+ WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
}
void EventSendingController::touchCancel()
@@ -581,7 +803,7 @@ void EventSendingController::touchCancel()
WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("TouchCancel"));
WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get());
- WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
+ WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
}
void EventSendingController::clearTouchPoints()
@@ -593,7 +815,7 @@ void EventSendingController::clearTouchPoints()
WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("ClearTouchPoints"));
WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get());
- WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
+ WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
}
void EventSendingController::releaseTouchPoint(int index)
@@ -609,7 +831,7 @@ void EventSendingController::releaseTouchPoint(int index)
WKRetainPtr<WKUInt64Ref> indexRef(AdoptWK, WKUInt64Create(index));
WKDictionarySetItem(EventSenderMessageBody.get(), indexKey.get(), indexRef.get());
- WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
+ WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
}
void EventSendingController::cancelTouchPoint(int index)
@@ -625,7 +847,7 @@ void EventSendingController::cancelTouchPoint(int index)
WKRetainPtr<WKUInt64Ref> indexRef(AdoptWK, WKUInt64Create(index));
WKDictionarySetItem(EventSenderMessageBody.get(), indexKey.get(), indexRef.get());
- WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
+ WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
}
#endif
diff --git a/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.h b/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.h
index c6a9131e4..3eb8129c7 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.h
+++ b/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2011, 2014-2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,19 +23,18 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef EventSendingController_h
-#define EventSendingController_h
+#pragma once
#include "JSWrappable.h"
-#include <WebKit2/WKEvent.h>
-#include <WebKit2/WKGeometry.h>
-#include <wtf/PassRefPtr.h>
+#include <WebKit/WKEvent.h>
+#include <WebKit/WKGeometry.h>
+#include <wtf/Ref.h>
namespace WTR {
class EventSendingController : public JSWrappable {
public:
- static PassRefPtr<EventSendingController> create();
+ static Ref<EventSendingController> create();
virtual ~EventSendingController();
void makeWindowObject(JSContextRef, JSObjectRef windowObject, JSValueRef* exception);
@@ -46,11 +45,20 @@ public:
void mouseDown(int button, JSValueRef modifierArray);
void mouseUp(int button, JSValueRef modifierArray);
void mouseMoveTo(int x, int y);
+ void mouseForceClick();
+ void startAndCancelMouseForceClick();
+ void mouseForceDown();
+ void mouseForceUp();
+ void mouseForceChanged(double force);
void mouseScrollBy(int x, int y);
+ void mouseScrollByWithWheelAndMomentumPhases(int x, int y, JSStringRef phase, JSStringRef momentum);
+ void swipeGestureWithWheelAndMomentumPhases(int x, int y, JSStringRef phase, JSStringRef momentum);
void continuousMouseScrollBy(int x, int y, bool paged);
JSValueRef contextClick();
void leapForward(int milliseconds);
void scheduleAsynchronousClick();
+ void monitorWheelEvents();
+ void callAfterScrollingCompletes(JSValueRef functionCallback);
void keyDown(JSStringRef key, JSValueRef modifierArray, int location);
void scheduleAsynchronousKeyDown(JSStringRef key);
@@ -79,8 +87,7 @@ public:
private:
EventSendingController();
+ WKPoint m_position;
};
} // namespace WTR
-
-#endif // EventSendingController_h
diff --git a/Tools/WebKitTestRunner/InjectedBundle/GCController.cpp b/Tools/WebKitTestRunner/InjectedBundle/GCController.cpp
index 10c21dba8..9358f4a0d 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/GCController.cpp
+++ b/Tools/WebKitTestRunner/InjectedBundle/GCController.cpp
@@ -28,13 +28,13 @@
#include "InjectedBundle.h"
#include "JSGCController.h"
-#include <WebKit2/WKBundlePrivate.h>
+#include <WebKit/WKBundlePrivate.h>
namespace WTR {
-PassRefPtr<GCController> GCController::create()
+Ref<GCController> GCController::create()
{
- return adoptRef(new GCController);
+ return adoptRef(*new GCController);
}
GCController::GCController()
@@ -52,17 +52,17 @@ JSClassRef GCController::wrapperClass()
void GCController::collect()
{
- WKBundleGarbageCollectJavaScriptObjects(InjectedBundle::shared().bundle());
+ WKBundleGarbageCollectJavaScriptObjects(InjectedBundle::singleton().bundle());
}
void GCController::collectOnAlternateThread(bool waitUntilDone)
{
- WKBundleGarbageCollectJavaScriptObjectsOnAlternateThreadForDebugging(InjectedBundle::shared().bundle(), waitUntilDone);
+ WKBundleGarbageCollectJavaScriptObjectsOnAlternateThreadForDebugging(InjectedBundle::singleton().bundle(), waitUntilDone);
}
size_t GCController::getJSObjectCount()
{
- return WKBundleGetJavaScriptObjectsCount(InjectedBundle::shared().bundle());
+ return WKBundleGetJavaScriptObjectsCount(InjectedBundle::singleton().bundle());
}
// Object Creation
diff --git a/Tools/WebKitTestRunner/InjectedBundle/GCController.h b/Tools/WebKitTestRunner/InjectedBundle/GCController.h
index 760fbb1e6..d349c1ce9 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/GCController.h
+++ b/Tools/WebKitTestRunner/InjectedBundle/GCController.h
@@ -23,17 +23,16 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef GCController_h
-#define GCController_h
+#pragma once
#include "JSWrappable.h"
-#include <wtf/PassRefPtr.h>
+#include <wtf/Ref.h>
namespace WTR {
class GCController : public JSWrappable {
public:
- static PassRefPtr<GCController> create();
+ static Ref<GCController> create();
virtual ~GCController();
void makeWindowObject(JSContextRef, JSObjectRef windowObject, JSValueRef* exception);
@@ -50,5 +49,3 @@ private:
};
} // namespace WTR
-
-#endif // GCController_h
diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp
index f71fe9360..f247b362b 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp
+++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010, 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2010-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,20 +29,20 @@
#include "ActivateFonts.h"
#include "InjectedBundlePage.h"
#include "StringFunctions.h"
-#include <WebKit2/WKBundle.h>
-#include <WebKit2/WKBundlePage.h>
-#include <WebKit2/WKBundlePagePrivate.h>
-#include <WebKit2/WKBundlePrivate.h>
-#include <WebKit2/WKRetainPtr.h>
-#include <WebKit2/WebKit2_C.h>
-#include <wtf/PassOwnPtr.h>
+#include "WebCoreTestSupport.h"
+#include <WebKit/WKBundle.h>
+#include <WebKit/WKBundlePage.h>
+#include <WebKit/WKBundlePagePrivate.h>
+#include <WebKit/WKBundlePrivate.h>
+#include <WebKit/WKRetainPtr.h>
+#include <WebKit/WebKit2_C.h>
#include <wtf/text/CString.h>
#include <wtf/text/StringBuilder.h>
#include <wtf/Vector.h>
namespace WTR {
-InjectedBundle& InjectedBundle::shared()
+InjectedBundle& InjectedBundle::singleton()
{
static InjectedBundle& shared = *new InjectedBundle;
return shared;
@@ -101,23 +101,18 @@ void InjectedBundle::initialize(WKBundleRef bundle, WKTypeRef initializationUser
platformInitialize(initializationUserData);
activateFonts();
- WKBundleActivateMacFontAscentHack(m_bundle);
}
void InjectedBundle::didCreatePage(WKBundlePageRef page)
{
- m_pages.append(adoptPtr(new InjectedBundlePage(page)));
+ m_pages.append(std::make_unique<InjectedBundlePage>(page));
}
void InjectedBundle::willDestroyPage(WKBundlePageRef page)
{
- size_t size = m_pages.size();
- for (size_t i = 0; i < size; ++i) {
- if (m_pages[i]->page() == page) {
- m_pages.remove(i);
- break;
- }
- }
+ m_pages.removeFirstMatching([page](auto& current) {
+ return current->page() == page;
+ });
}
void InjectedBundle::didInitializePageGroup(WKBundlePageGroupRef pageGroup)
@@ -139,6 +134,13 @@ void InjectedBundle::resetLocalSettings()
void InjectedBundle::didReceiveMessage(WKStringRef messageName, WKTypeRef messageBody)
{
+ WKRetainPtr<WKStringRef> errorMessageName(AdoptWK, WKStringCreateWithUTF8CString("Error"));
+ WKRetainPtr<WKStringRef> errorMessageBody(AdoptWK, WKStringCreateWithUTF8CString("Unknown"));
+ WKBundlePostMessage(m_bundle, errorMessageName.get(), errorMessageBody.get());
+}
+
+void InjectedBundle::didReceiveMessageToPage(WKBundlePageRef page, WKStringRef messageName, WKTypeRef messageBody)
+{
if (WKStringIsEqualToUTF8CString(messageName, "BeginTest")) {
ASSERT(messageBody);
ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
@@ -153,13 +155,18 @@ void InjectedBundle::didReceiveMessage(WKStringRef messageName, WKTypeRef messag
WKRetainPtr<WKStringRef> timeoutKey(AdoptWK, WKStringCreateWithUTF8CString("Timeout"));
m_timeout = (int)WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, timeoutKey.get())));
+ WKRetainPtr<WKStringRef> dumpJSConsoleLogInStdErrKey(AdoptWK, WKStringCreateWithUTF8CString("DumpJSConsoleLogInStdErr"));
+ m_dumpJSConsoleLogInStdErr = WKBooleanGetValue(static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, dumpJSConsoleLogInStdErrKey.get())));
+
WKRetainPtr<WKStringRef> ackMessageName(AdoptWK, WKStringCreateWithUTF8CString("Ack"));
WKRetainPtr<WKStringRef> ackMessageBody(AdoptWK, WKStringCreateWithUTF8CString("BeginTest"));
- WKBundlePostMessage(m_bundle, ackMessageName.get(), ackMessageBody.get());
+ WKBundlePagePostMessage(page, ackMessageName.get(), ackMessageBody.get());
beginTesting(messageBodyDictionary);
return;
- } else if (WKStringIsEqualToUTF8CString(messageName, "Reset")) {
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "Reset")) {
ASSERT(messageBody);
ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
@@ -170,48 +177,103 @@ void InjectedBundle::didReceiveMessage(WKStringRef messageName, WKTypeRef messag
if (shouldGC)
WKBundleGarbageCollectJavaScriptObjects(m_bundle);
+ WKRetainPtr<WKStringRef> allowedHostsKey(AdoptWK, WKStringCreateWithUTF8CString("AllowedHosts"));
+ WKTypeRef allowedHostsValue = WKDictionaryGetItemForKey(messageBodyDictionary, allowedHostsKey.get());
+ if (allowedHostsValue && WKGetTypeID(allowedHostsValue) == WKArrayGetTypeID()) {
+ WKArrayRef allowedHostsArray = static_cast<WKArrayRef>(allowedHostsValue);
+ for (size_t i = 0, size = WKArrayGetSize(allowedHostsArray); i < size; ++i) {
+ WKTypeRef item = WKArrayGetItemAtIndex(allowedHostsArray, i);
+ if (item && WKGetTypeID(item) == WKStringGetTypeID())
+ m_allowedHosts.append(toWTFString(static_cast<WKStringRef>(item)));
+ }
+ }
+
m_state = Idle;
m_dumpPixels = false;
+ m_pixelResultIsPending = false;
resetLocalSettings();
- m_testRunner->removeAllWebNotificationPermissions();
+ TestRunner::removeAllWebNotificationPermissions();
- page()->resetAfterTest();
+ InjectedBundle::page()->resetAfterTest();
return;
}
+
if (WKStringIsEqualToUTF8CString(messageName, "CallAddChromeInputFieldCallback")) {
m_testRunner->callAddChromeInputFieldCallback();
return;
}
+
if (WKStringIsEqualToUTF8CString(messageName, "CallRemoveChromeInputFieldCallback")) {
m_testRunner->callRemoveChromeInputFieldCallback();
return;
}
+
if (WKStringIsEqualToUTF8CString(messageName, "CallFocusWebViewCallback")) {
m_testRunner->callFocusWebViewCallback();
return;
}
+
if (WKStringIsEqualToUTF8CString(messageName, "CallSetBackingScaleFactorCallback")) {
m_testRunner->callSetBackingScaleFactorCallback();
return;
- }
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "CallDidBeginSwipeCallback")) {
+ m_testRunner->callDidBeginSwipeCallback();
+ return;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "CallWillEndSwipeCallback")) {
+ m_testRunner->callWillEndSwipeCallback();
+ return;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "CallDidEndSwipeCallback")) {
+ m_testRunner->callDidEndSwipeCallback();
+ return;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "CallDidRemoveSwipeSnapshotCallback")) {
+ m_testRunner->callDidRemoveSwipeSnapshotCallback();
+ return;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "NotifyDownloadDone")) {
+ m_testRunner->notifyDone();
+ return;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "CallUISideScriptCallback")) {
+ WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
+
+ WKRetainPtr<WKStringRef> resultKey(AdoptWK, WKStringCreateWithUTF8CString("Result"));
+ WKRetainPtr<WKStringRef> callbackIDKey(AdoptWK, WKStringCreateWithUTF8CString("CallbackID"));
+
+ unsigned callbackID = (unsigned)WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, callbackIDKey.get())));
+
+ WKStringRef resultString = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, resultKey.get()));
+ auto resultJSString = toJS(resultString);
+
+ m_testRunner->runUIScriptCallback(callbackID, resultJSString.get());
+ return;
+ }
+
if (WKStringIsEqualToUTF8CString(messageName, "WorkQueueProcessedCallback")) {
if (!topLoadingFrame() && !m_testRunner->waitToDump())
- page()->dump();
+ InjectedBundle::page()->dump();
return;
}
- WKRetainPtr<WKStringRef> errorMessageName(AdoptWK, WKStringCreateWithUTF8CString("Error"));
- WKRetainPtr<WKStringRef> errorMessageBody(AdoptWK, WKStringCreateWithUTF8CString("Unknown"));
- WKBundlePostMessage(m_bundle, errorMessageName.get(), errorMessageBody.get());
-}
+ if (WKStringIsEqualToUTF8CString(messageName, "WebsiteDataDeletionForTopPrivatelyOwnedDomainsFinished")) {
+ m_testRunner->statisticsDidModifyDataRecordsCallback();
+ return;
+ }
-void InjectedBundle::didReceiveMessageToPage(WKBundlePageRef page, WKStringRef messageName, WKTypeRef messageBody)
-{
WKRetainPtr<WKStringRef> errorMessageName(AdoptWK, WKStringCreateWithUTF8CString("Error"));
WKRetainPtr<WKStringRef> errorMessageBody(AdoptWK, WKStringCreateWithUTF8CString("Unknown"));
- WKBundlePostMessage(m_bundle, errorMessageName.get(), errorMessageBody.get());
+ WKBundlePagePostMessage(page, errorMessageName.get(), errorMessageBody.get());
}
bool InjectedBundle::booleanForKey(WKDictionaryRef dictionary, const char* key)
@@ -236,41 +298,60 @@ void InjectedBundle::beginTesting(WKDictionaryRef settings)
m_gcController = GCController::create();
m_eventSendingController = EventSendingController::create();
m_textInputController = TextInputController::create();
+#if HAVE(ACCESSIBILITY)
m_accessibilityController = AccessibilityController::create();
+#endif
- WKBundleSetShouldTrackVisitedLinks(m_bundle, false);
- WKBundleRemoveAllVisitedLinks(m_bundle);
WKBundleSetAllowUniversalAccessFromFileURLs(m_bundle, m_pageGroup, true);
WKBundleSetJavaScriptCanAccessClipboard(m_bundle, m_pageGroup, true);
WKBundleSetPrivateBrowsingEnabled(m_bundle, m_pageGroup, false);
+ WKBundleSetUseDashboardCompatibilityMode(m_bundle, m_pageGroup, false);
WKBundleSetAuthorAndUserStylesEnabled(m_bundle, m_pageGroup, true);
WKBundleSetFrameFlatteningEnabled(m_bundle, m_pageGroup, false);
WKBundleSetMinimumLogicalFontSize(m_bundle, m_pageGroup, 9);
WKBundleSetSpatialNavigationEnabled(m_bundle, m_pageGroup, false);
WKBundleSetAllowFileAccessFromFileURLs(m_bundle, m_pageGroup, true);
- WKBundleSetPluginsEnabled(m_bundle, m_pageGroup, true);
WKBundleSetPopupBlockingEnabled(m_bundle, m_pageGroup, false);
- WKBundleSetAlwaysAcceptCookies(m_bundle, false);
- WKBundleSetSerialLoadingEnabled(m_bundle, false);
- WKBundleSetShadowDOMEnabled(m_bundle, true);
- WKBundleSetSeamlessIFramesEnabled(m_bundle, true);
- WKBundleSetCacheModel(m_bundle, 1 /*CacheModelDocumentBrowser*/);
+ WKBundleSetAllowStorageAccessFromFileURLS(m_bundle, m_pageGroup, false);
- WKBundleRemoveAllUserContent(m_bundle, m_pageGroup);
+#if PLATFORM(IOS)
+ WKBundlePageSetUseTestingViewportConfiguration(page()->page(), !booleanForKey(settings, "UseFlexibleViewport"));
+#endif
+
+ m_testRunner->setPluginsEnabled(true);
m_testRunner->setShouldDumpFrameLoadCallbacks(booleanForKey(settings, "DumpFrameLoadDelegates"));
m_testRunner->setUserStyleSheetEnabled(false);
m_testRunner->setXSSAuditorEnabled(false);
+
+ m_testRunner->setShadowDOMEnabled(true);
+ m_testRunner->setCustomElementsEnabled(true);
+
+ m_testRunner->setWebGL2Enabled(true);
+
+ m_testRunner->setFetchAPIEnabled(true);
+
+ m_testRunner->setDownloadAttributeEnabled(true);
+
+ m_testRunner->setEncryptedMediaAPIEnabled(true);
+
m_testRunner->setCloseRemainingWindowsWhenComplete(false);
m_testRunner->setAcceptsEditing(true);
m_testRunner->setTabKeyCyclesThroughElements(true);
+ m_testRunner->clearTestRunnerCallbacks();
+
+ m_testRunner->setSubtleCryptoEnabled(true);
- m_testRunner->setCustomTimeout(m_timeout);
+ m_testRunner->setMediaStreamEnabled(true);
+ m_testRunner->setPeerConnectionEnabled(true);
+
+ if (m_timeout > 0)
+ m_testRunner->setCustomTimeout(m_timeout);
page()->prepare();
WKBundleClearAllDatabases(m_bundle);
- WKBundleClearApplicationCache(m_bundle);
+ WKBundlePageClearApplicationCache(page()->page());
WKBundleResetOriginAccessWhitelists(m_bundle);
// [WK2] REGRESSION(r128623): It made layout tests extremely slow
@@ -287,13 +368,21 @@ void InjectedBundle::done()
page()->stopLoading();
setTopLoadingFrame(0);
+ m_testRunner->invalidateWaitToDumpWatchdogTimer();
+
m_accessibilityController->resetToConsistentState();
WKRetainPtr<WKStringRef> doneMessageName(AdoptWK, WKStringCreateWithUTF8CString("Done"));
WKRetainPtr<WKMutableDictionaryRef> doneMessageBody(AdoptWK, WKMutableDictionaryCreate());
- WKRetainPtr<WKStringRef> pixelResultKey = adoptWK(WKStringCreateWithUTF8CString("PixelResult"));
- WKDictionarySetItem(doneMessageBody.get(), pixelResultKey.get(), m_pixelResult.get());
+ WKRetainPtr<WKStringRef> pixelResultIsPendingKey = adoptWK(WKStringCreateWithUTF8CString("PixelResultIsPending"));
+ WKRetainPtr<WKBooleanRef> pixelResultIsPending(AdoptWK, WKBooleanCreate(m_pixelResultIsPending));
+ WKDictionarySetItem(doneMessageBody.get(), pixelResultIsPendingKey.get(), pixelResultIsPending.get());
+
+ if (!m_pixelResultIsPending) {
+ WKRetainPtr<WKStringRef> pixelResultKey = adoptWK(WKStringCreateWithUTF8CString("PixelResult"));
+ WKDictionarySetItem(doneMessageBody.get(), pixelResultKey.get(), m_pixelResult.get());
+ }
WKRetainPtr<WKStringRef> repaintRectsKey = adoptWK(WKStringCreateWithUTF8CString("RepaintRects"));
WKDictionarySetItem(doneMessageBody.get(), repaintRectsKey.get(), m_repaintRects.get());
@@ -301,7 +390,7 @@ void InjectedBundle::done()
WKRetainPtr<WKStringRef> audioResultKey = adoptWK(WKStringCreateWithUTF8CString("AudioResult"));
WKDictionarySetItem(doneMessageBody.get(), audioResultKey.get(), m_audioResult.get());
- WKBundlePostMessage(m_bundle, doneMessageName.get(), doneMessageBody.get());
+ WKBundlePagePostMessage(page()->page(), doneMessageName.get(), doneMessageBody.get());
closeOtherPages();
@@ -326,6 +415,17 @@ void InjectedBundle::dumpBackForwardListsForAllPages(StringBuilder& stringBuilde
m_pages[i]->dumpBackForwardList(stringBuilder);
}
+void InjectedBundle::dumpToStdErr(const String& output)
+{
+ if (m_state != Testing)
+ return;
+ if (output.isEmpty())
+ return;
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("DumpToStdErr"));
+ WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithUTF8CString(output.utf8().data()));
+ WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get());
+}
+
void InjectedBundle::outputText(const String& output)
{
if (m_state != Testing)
@@ -334,60 +434,85 @@ void InjectedBundle::outputText(const String& output)
return;
WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("TextOutput"));
WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithUTF8CString(output.utf8().data()));
- WKBundlePostMessage(m_bundle, messageName.get(), messageBody.get());
+ WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get());
}
void InjectedBundle::postNewBeforeUnloadReturnValue(bool value)
{
WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("BeforeUnloadReturnValue"));
WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
- WKBundlePostMessage(m_bundle, messageName.get(), messageBody.get());
+ WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get());
}
void InjectedBundle::postAddChromeInputField()
{
WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("AddChromeInputField"));
- WKBundlePostMessage(m_bundle, messageName.get(), 0);
+ WKBundlePagePostMessage(page()->page(), messageName.get(), 0);
}
void InjectedBundle::postRemoveChromeInputField()
{
WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("RemoveChromeInputField"));
- WKBundlePostMessage(m_bundle, messageName.get(), 0);
+ WKBundlePagePostMessage(page()->page(), messageName.get(), 0);
}
void InjectedBundle::postFocusWebView()
{
WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("FocusWebView"));
- WKBundlePostMessage(m_bundle, messageName.get(), 0);
+ WKBundlePagePostMessage(page()->page(), messageName.get(), 0);
}
void InjectedBundle::postSetBackingScaleFactor(double backingScaleFactor)
{
WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetBackingScaleFactor"));
WKRetainPtr<WKDoubleRef> messageBody(AdoptWK, WKDoubleCreate(backingScaleFactor));
- WKBundlePostMessage(m_bundle, messageName.get(), messageBody.get());
+ WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get());
}
void InjectedBundle::postSetWindowIsKey(bool isKey)
{
WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetWindowIsKey"));
WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(isKey));
- WKBundlePostSynchronousMessage(m_bundle, messageName.get(), messageBody.get(), 0);
+ WKBundlePagePostSynchronousMessageForTesting(page()->page(), messageName.get(), messageBody.get(), 0);
+}
+
+void InjectedBundle::postSetViewSize(double width, double height)
+{
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetViewSize"));
+
+ WKRetainPtr<WKStringRef> widthKey(AdoptWK, WKStringCreateWithUTF8CString("width"));
+ WKRetainPtr<WKStringRef> heightKey(AdoptWK, WKStringCreateWithUTF8CString("height"));
+
+ WKRetainPtr<WKMutableDictionaryRef> messageBody(AdoptWK, WKMutableDictionaryCreate());
+
+ WKRetainPtr<WKDoubleRef> widthWK(AdoptWK, WKDoubleCreate(width));
+ WKDictionarySetItem(messageBody.get(), widthKey.get(), widthWK.get());
+
+ WKRetainPtr<WKDoubleRef> heightWK(AdoptWK, WKDoubleCreate(height));
+ WKDictionarySetItem(messageBody.get(), heightKey.get(), heightWK.get());
+
+ WKBundlePagePostSynchronousMessageForTesting(page()->page(), messageName.get(), messageBody.get(), 0);
}
void InjectedBundle::postSimulateWebNotificationClick(uint64_t notificationID)
{
WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SimulateWebNotificationClick"));
WKRetainPtr<WKUInt64Ref> messageBody(AdoptWK, WKUInt64Create(notificationID));
- WKBundlePostMessage(m_bundle, messageName.get(), messageBody.get());
+ WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get());
+}
+
+void InjectedBundle::postSetAddsVisitedLinks(bool addsVisitedLinks)
+{
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAddsVisitedLinks"));
+ WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(addsVisitedLinks));
+ WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get());
}
void InjectedBundle::setGeolocationPermission(bool enabled)
{
WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetGeolocationPermission"));
WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(enabled));
- WKBundlePostMessage(m_bundle, messageName.get(), messageBody.get());
+ WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get());
}
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)
@@ -440,13 +565,90 @@ void InjectedBundle::setMockGeolocationPosition(double latitude, double longitud
WKRetainPtr<WKDoubleRef> speedWK(AdoptWK, WKDoubleCreate(speed));
WKDictionarySetItem(messageBody.get(), speedKeyWK.get(), speedWK.get());
- WKBundlePostMessage(m_bundle, messageName.get(), messageBody.get());
+ WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get());
}
void InjectedBundle::setMockGeolocationPositionUnavailableError(WKStringRef errorMessage)
{
WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGeolocationPositionUnavailableError"));
- WKBundlePostMessage(m_bundle, messageName.get(), errorMessage);
+ WKBundlePagePostMessage(page()->page(), messageName.get(), errorMessage);
+}
+
+bool InjectedBundle::isGeolocationProviderActive() const
+{
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsGeolocationClientActive"));
+ WKTypeRef resultToPass = 0;
+ WKBundlePagePostSynchronousMessageForTesting(page()->page(), messageName.get(), 0, &resultToPass);
+ WKRetainPtr<WKBooleanRef> isActive(AdoptWK, static_cast<WKBooleanRef>(resultToPass));
+
+ return WKBooleanGetValue(isActive.get());
+}
+
+unsigned InjectedBundle::imageCountInGeneralPasteboard() const
+{
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ImageCountInGeneralPasteboard"));
+ WKTypeRef resultToPass = 0;
+ WKBundlePagePostSynchronousMessageForTesting(page()->page(), messageName.get(), 0, &resultToPass);
+ WKRetainPtr<WKUInt64Ref> imageCount(AdoptWK, static_cast<WKUInt64Ref>(resultToPass));
+
+ return static_cast<unsigned>(WKUInt64GetValue(imageCount.get()));
+}
+
+void InjectedBundle::setUserMediaPermission(bool enabled)
+{
+ auto messageName = adoptWK(WKStringCreateWithUTF8CString("SetUserMediaPermission"));
+ auto messageBody = adoptWK(WKBooleanCreate(enabled));
+ WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get());
+}
+
+void InjectedBundle::setUserMediaPersistentPermissionForOrigin(bool permission, WKStringRef origin, WKStringRef parentOrigin)
+{
+ auto messageName = adoptWK(WKStringCreateWithUTF8CString("SetUserMediaPersistentPermissionForOrigin"));
+ WKRetainPtr<WKMutableDictionaryRef> messageBody(AdoptWK, WKMutableDictionaryCreate());
+
+ WKRetainPtr<WKStringRef> permissionKeyWK(AdoptWK, WKStringCreateWithUTF8CString("permission"));
+ WKRetainPtr<WKBooleanRef> permissionWK(AdoptWK, WKBooleanCreate(permission));
+ WKDictionarySetItem(messageBody.get(), permissionKeyWK.get(), permissionWK.get());
+
+ WKRetainPtr<WKStringRef> originKeyWK(AdoptWK, WKStringCreateWithUTF8CString("origin"));
+ WKDictionarySetItem(messageBody.get(), originKeyWK.get(), origin);
+
+ WKRetainPtr<WKStringRef> parentOriginKeyWK(AdoptWK, WKStringCreateWithUTF8CString("parentOrigin"));
+ WKDictionarySetItem(messageBody.get(), parentOriginKeyWK.get(), parentOrigin);
+
+ WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get());
+}
+
+unsigned InjectedBundle::userMediaPermissionRequestCountForOrigin(WKStringRef origin, WKStringRef parentOrigin) const
+{
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("UserMediaPermissionRequestCountForOrigin"));
+ WKRetainPtr<WKMutableDictionaryRef> messageBody(AdoptWK, WKMutableDictionaryCreate());
+
+ WKRetainPtr<WKStringRef> originKeyWK(AdoptWK, WKStringCreateWithUTF8CString("origin"));
+ WKDictionarySetItem(messageBody.get(), originKeyWK.get(), origin);
+
+ WKRetainPtr<WKStringRef> parentOriginKeyWK(AdoptWK, WKStringCreateWithUTF8CString("parentOrigin"));
+ WKDictionarySetItem(messageBody.get(), parentOriginKeyWK.get(), parentOrigin);
+
+ WKTypeRef resultToPass = 0;
+ WKBundlePagePostSynchronousMessageForTesting(page()->page(), messageName.get(), messageBody.get(), &resultToPass);
+ WKRetainPtr<WKUInt64Ref> count(AdoptWK, static_cast<WKUInt64Ref>(resultToPass));
+
+ return static_cast<unsigned>(WKUInt64GetValue(count.get()));
+}
+
+void InjectedBundle::resetUserMediaPermissionRequestCountForOrigin(WKStringRef origin, WKStringRef parentOrigin)
+{
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ResetUserMediaPermissionRequestCountForOrigin"));
+ WKRetainPtr<WKMutableDictionaryRef> messageBody(AdoptWK, WKMutableDictionaryCreate());
+
+ WKRetainPtr<WKStringRef> originKeyWK(AdoptWK, WKStringCreateWithUTF8CString("origin"));
+ WKDictionarySetItem(messageBody.get(), originKeyWK.get(), origin);
+
+ WKRetainPtr<WKStringRef> parentOriginKeyWK(AdoptWK, WKStringCreateWithUTF8CString("parentOrigin"));
+ WKDictionarySetItem(messageBody.get(), parentOriginKeyWK.get(), parentOrigin);
+
+ WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get());
}
void InjectedBundle::setCustomPolicyDelegate(bool enabled, bool permissive)
@@ -463,23 +665,26 @@ void InjectedBundle::setCustomPolicyDelegate(bool enabled, bool permissive)
WKRetainPtr<WKBooleanRef> permissiveWK(AdoptWK, WKBooleanCreate(permissive));
WKDictionarySetItem(messageBody.get(), permissiveKeyWK.get(), permissiveWK.get());
- WKBundlePostMessage(m_bundle, messageName.get(), messageBody.get());
+ WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get());
}
-void InjectedBundle::setVisibilityState(WKPageVisibilityState visibilityState, bool isInitialState)
+void InjectedBundle::setHidden(bool hidden)
{
- WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetVisibilityState"));
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetHidden"));
WKRetainPtr<WKMutableDictionaryRef> messageBody(AdoptWK, WKMutableDictionaryCreate());
- WKRetainPtr<WKStringRef> visibilityStateKeyWK(AdoptWK, WKStringCreateWithUTF8CString("visibilityState"));
- WKRetainPtr<WKUInt64Ref> visibilityStateWK(AdoptWK, WKUInt64Create(visibilityState));
- WKDictionarySetItem(messageBody.get(), visibilityStateKeyWK.get(), visibilityStateWK.get());
-
- WKRetainPtr<WKStringRef> isInitialKeyWK(AdoptWK, WKStringCreateWithUTF8CString("isInitialState"));
- WKRetainPtr<WKBooleanRef> isInitialWK(AdoptWK, WKBooleanCreate(isInitialState));
+ WKRetainPtr<WKStringRef> isInitialKeyWK(AdoptWK, WKStringCreateWithUTF8CString("hidden"));
+ WKRetainPtr<WKBooleanRef> isInitialWK(AdoptWK, WKBooleanCreate(hidden));
WKDictionarySetItem(messageBody.get(), isInitialKeyWK.get(), isInitialWK.get());
- WKBundlePostMessage(m_bundle, messageName.get(), messageBody.get());
+ WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get());
+}
+
+void InjectedBundle::setCacheModel(int model)
+{
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetCacheModel"));
+ WKRetainPtr<WKUInt64Ref> messageBody(AdoptWK, WKUInt64Create(model));
+ WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get());
}
bool InjectedBundle::shouldProcessWorkQueue() const
@@ -489,7 +694,7 @@ bool InjectedBundle::shouldProcessWorkQueue() const
WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsWorkQueueEmpty"));
WKTypeRef resultToPass = 0;
- WKBundlePostSynchronousMessage(m_bundle, messageName.get(), 0, &resultToPass);
+ WKBundlePagePostSynchronousMessageForTesting(page()->page(), messageName.get(), 0, &resultToPass);
WKRetainPtr<WKBooleanRef> isEmpty(AdoptWK, static_cast<WKBooleanRef>(resultToPass));
return !WKBooleanGetValue(isEmpty.get());
@@ -498,7 +703,7 @@ bool InjectedBundle::shouldProcessWorkQueue() const
void InjectedBundle::processWorkQueue()
{
WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ProcessWorkQueue"));
- WKBundlePostMessage(m_bundle, messageName.get(), 0);
+ WKBundlePagePostMessage(page()->page(), messageName.get(), 0);
}
void InjectedBundle::queueBackNavigation(unsigned howFarBackward)
@@ -507,7 +712,7 @@ void InjectedBundle::queueBackNavigation(unsigned howFarBackward)
WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("QueueBackNavigation"));
WKRetainPtr<WKUInt64Ref> messageBody(AdoptWK, WKUInt64Create(howFarBackward));
- WKBundlePostMessage(m_bundle, messageName.get(), messageBody.get());
+ WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get());
}
void InjectedBundle::queueForwardNavigation(unsigned howFarForward)
@@ -516,10 +721,10 @@ void InjectedBundle::queueForwardNavigation(unsigned howFarForward)
WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("QueueForwardNavigation"));
WKRetainPtr<WKUInt64Ref> messageBody(AdoptWK, WKUInt64Create(howFarForward));
- WKBundlePostMessage(m_bundle, messageName.get(), messageBody.get());
+ WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get());
}
-void InjectedBundle::queueLoad(WKStringRef url, WKStringRef target)
+void InjectedBundle::queueLoad(WKStringRef url, WKStringRef target, bool shouldOpenExternalURLs)
{
m_useWorkQueue = true;
@@ -533,7 +738,11 @@ void InjectedBundle::queueLoad(WKStringRef url, WKStringRef target)
WKRetainPtr<WKStringRef> targetKey(AdoptWK, WKStringCreateWithUTF8CString("target"));
WKDictionarySetItem(loadData.get(), targetKey.get(), target);
- WKBundlePostMessage(m_bundle, messageName.get(), loadData.get());
+ WKRetainPtr<WKStringRef> shouldOpenExternalURLsKey(AdoptWK, WKStringCreateWithUTF8CString("shouldOpenExternalURLs"));
+ WKRetainPtr<WKBooleanRef> shouldOpenExternalURLsValue(AdoptWK, WKBooleanCreate(shouldOpenExternalURLs));
+ WKDictionarySetItem(loadData.get(), shouldOpenExternalURLsKey.get(), shouldOpenExternalURLsValue.get());
+
+ WKBundlePagePostMessage(page()->page(), messageName.get(), loadData.get());
}
void InjectedBundle::queueLoadHTMLString(WKStringRef content, WKStringRef baseURL, WKStringRef unreachableURL)
@@ -557,7 +766,7 @@ void InjectedBundle::queueLoadHTMLString(WKStringRef content, WKStringRef baseUR
WKDictionarySetItem(loadData.get(), unreachableURLKey.get(), unreachableURL);
}
- WKBundlePostMessage(m_bundle, messageName.get(), loadData.get());
+ WKBundlePagePostMessage(page()->page(), messageName.get(), loadData.get());
}
void InjectedBundle::queueReload()
@@ -565,7 +774,7 @@ void InjectedBundle::queueReload()
m_useWorkQueue = true;
WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("QueueReload"));
- WKBundlePostMessage(m_bundle, messageName.get(), 0);
+ WKBundlePagePostMessage(page()->page(), messageName.get(), 0);
}
void InjectedBundle::queueLoadingScript(WKStringRef script)
@@ -573,7 +782,7 @@ void InjectedBundle::queueLoadingScript(WKStringRef script)
m_useWorkQueue = true;
WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("QueueLoadingScript"));
- WKBundlePostMessage(m_bundle, messageName.get(), script);
+ WKBundlePagePostMessage(page()->page(), messageName.get(), script);
}
void InjectedBundle::queueNonLoadingScript(WKStringRef script)
@@ -581,7 +790,19 @@ void InjectedBundle::queueNonLoadingScript(WKStringRef script)
m_useWorkQueue = true;
WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("QueueNonLoadingScript"));
- WKBundlePostMessage(m_bundle, messageName.get(), script);
+ WKBundlePagePostMessage(page()->page(), messageName.get(), script);
+}
+
+bool InjectedBundle::isAllowedHost(WKStringRef host)
+{
+ if (m_allowedHosts.isEmpty())
+ return false;
+ return m_allowedHosts.contains(toWTFString(host));
+}
+
+void InjectedBundle::setAllowsAnySSLCertificate(bool allowsAnySSLCertificate)
+{
+ WebCoreTestSupport::setAllowsAnySSLCertificate(allowsAnySSLCertificate);
}
} // namespace WTR
diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h
index 170c8ac70..2edd5e797 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h
+++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010, 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2010-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,29 +23,30 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef InjectedBundle_h
-#define InjectedBundle_h
+#pragma once
-#include "AccessibilityController.h"
#include "EventSendingController.h"
#include "GCController.h"
#include "TestRunner.h"
#include "TextInputController.h"
-#include <WebKit2/WKBase.h>
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKBase.h>
+#include <WebKit/WKRetainPtr.h>
#include <sstream>
#include <wtf/Forward.h>
-#include <wtf/OwnPtr.h>
#include <wtf/RefPtr.h>
#include <wtf/Vector.h>
+#if HAVE(ACCESSIBILITY)
+#include "AccessibilityController.h"
+#endif
+
namespace WTR {
class InjectedBundlePage;
class InjectedBundle {
public:
- static InjectedBundle& shared();
+ static InjectedBundle& singleton();
// Initialize the InjectedBundle.
void initialize(WKBundleRef, WKTypeRef initializationUserData);
@@ -57,7 +58,9 @@ public:
GCController* gcController() { return m_gcController.get(); }
EventSendingController* eventSendingController() { return m_eventSendingController.get(); }
TextInputController* textInputController() { return m_textInputController.get(); }
+#if HAVE(ACCESSIBILITY)
AccessibilityController* accessibilityController() { return m_accessibilityController.get(); }
+#endif
InjectedBundlePage* page() const;
size_t pageCount() const { return m_pages.size(); }
@@ -67,7 +70,8 @@ public:
void done();
void setAudioResult(WKDataRef audioData) { m_audioResult = audioData; }
- void setPixelResult(WKImageRef image) { m_pixelResult = image; }
+ void setPixelResult(WKImageRef image) { m_pixelResult = image; m_pixelResultIsPending = false; }
+ void setPixelResultIsPending(bool isPending) { m_pixelResultIsPending = isPending; }
void setRepaintRects(WKArrayRef rects) { m_repaintRects = rects; }
bool isTestRunning() { return m_state == Testing; }
@@ -77,38 +81,58 @@ public:
bool shouldDumpPixels() const { return m_dumpPixels; }
bool useWaitToDumpWatchdogTimer() const { return m_useWaitToDumpWatchdogTimer; }
-
+ bool dumpJSConsoleLogInStdErr() const { return m_dumpJSConsoleLogInStdErr; };
+
void outputText(const String&);
+ void dumpToStdErr(const String&);
void postNewBeforeUnloadReturnValue(bool);
void postAddChromeInputField();
void postRemoveChromeInputField();
void postFocusWebView();
void postSetBackingScaleFactor(double);
void postSetWindowIsKey(bool);
+ void postSetViewSize(double width, double height);
void postSimulateWebNotificationClick(uint64_t notificationID);
+ void postSetAddsVisitedLinks(bool);
// Geolocation.
void setGeolocationPermission(bool);
void setMockGeolocationPosition(double latitude, double longitude, double accuracy, bool providesAltitude, double altitude, bool providesAltitudeAccuracy, double altitudeAccuracy, bool providesHeading, double heading, bool providesSpeed, double speed);
void setMockGeolocationPositionUnavailableError(WKStringRef errorMessage);
+ bool isGeolocationProviderActive() const;
+
+ // MediaStream.
+ void setUserMediaPermission(bool);
+ void setUserMediaPersistentPermissionForOrigin(bool permission, WKStringRef origin, WKStringRef parentOrigin);
+ unsigned userMediaPermissionRequestCountForOrigin(WKStringRef origin, WKStringRef parentOrigin) const;
+ void resetUserMediaPermissionRequestCountForOrigin(WKStringRef origin, WKStringRef parentOrigin);
// Policy delegate.
void setCustomPolicyDelegate(bool enabled, bool permissive);
// Page Visibility.
- void setVisibilityState(WKPageVisibilityState, bool isInitialState);
+ void setHidden(bool);
+
+ // Cache.
+ void setCacheModel(int);
// Work queue.
bool shouldProcessWorkQueue() const;
void processWorkQueue();
void queueBackNavigation(unsigned howFarBackward);
void queueForwardNavigation(unsigned howFarForward);
- void queueLoad(WKStringRef url, WKStringRef target);
+ void queueLoad(WKStringRef url, WKStringRef target, bool shouldOpenExternalURLs = false);
void queueLoadHTMLString(WKStringRef content, WKStringRef baseURL = 0, WKStringRef unreachableURL = 0);
void queueReload();
void queueLoadingScript(WKStringRef script);
void queueNonLoadingScript(WKStringRef script);
+ bool isAllowedHost(WKStringRef);
+
+ unsigned imageCountInGeneralPasteboard() const;
+
+ void setAllowsAnySSLCertificate(bool);
+
private:
InjectedBundle();
~InjectedBundle();
@@ -134,9 +158,11 @@ private:
WKBundleRef m_bundle;
WKBundlePageGroupRef m_pageGroup;
- Vector<OwnPtr<InjectedBundlePage> > m_pages;
+ Vector<std::unique_ptr<InjectedBundlePage>> m_pages;
+#if HAVE(ACCESSIBILITY)
RefPtr<AccessibilityController> m_accessibilityController;
+#endif
RefPtr<TestRunner> m_testRunner;
RefPtr<GCController> m_gcController;
RefPtr<EventSendingController> m_eventSendingController;
@@ -155,12 +181,14 @@ private:
bool m_useWaitToDumpWatchdogTimer;
bool m_useWorkQueue;
int m_timeout;
+ bool m_pixelResultIsPending { false };
+ bool m_dumpJSConsoleLogInStdErr { false };
WKRetainPtr<WKDataRef> m_audioResult;
WKRetainPtr<WKImageRef> m_pixelResult;
WKRetainPtr<WKArrayRef> m_repaintRects;
+
+ Vector<String> m_allowedHosts;
};
} // namespace WTR
-
-#endif // InjectedBundle_h
diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp
index 58af68221..4f1272214 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp
+++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp
@@ -26,10 +26,10 @@
#include "config.h"
#include "InjectedBundle.h"
-#include <WebKit2/WKBundleInitialize.h>
+#include <WebKit/WKBundleInitialize.h>
extern "C"
void WKBundleInitialize(WKBundleRef bundle, WKTypeRef initializationUserData)
{
- WTR::InjectedBundle::shared().initialize(bundle, initializationUserData);
+ WTR::InjectedBundle::singleton().initialize(bundle, initializationUserData);
}
diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp
index e161156a7..61c59b2e3 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp
+++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010, 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2010-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,19 +31,20 @@
#include "WebCoreTestSupport.h"
#include <cmath>
#include <JavaScriptCore/JSRetainPtr.h>
-#include <WebKit2/WKArray.h>
-#include <WebKit2/WKBundle.h>
-#include <WebKit2/WKBundleBackForwardList.h>
-#include <WebKit2/WKBundleBackForwardListItem.h>
-#include <WebKit2/WKBundleFrame.h>
-#include <WebKit2/WKBundleFramePrivate.h>
-#include <WebKit2/WKBundleHitTestResult.h>
-#include <WebKit2/WKBundleNavigationAction.h>
-#include <WebKit2/WKBundleNodeHandlePrivate.h>
-#include <WebKit2/WKBundlePagePrivate.h>
-#include <WebKit2/WKBundlePrivate.h>
-#include <WebKit2/WKSecurityOrigin.h>
-#include <WebKit2/WKURLRequest.h>
+#include <WebKit/WKArray.h>
+#include <WebKit/WKBundle.h>
+#include <WebKit/WKBundleBackForwardList.h>
+#include <WebKit/WKBundleBackForwardListItem.h>
+#include <WebKit/WKBundleFrame.h>
+#include <WebKit/WKBundleFramePrivate.h>
+#include <WebKit/WKBundleHitTestResult.h>
+#include <WebKit/WKBundleNavigationAction.h>
+#include <WebKit/WKBundleNavigationActionPrivate.h>
+#include <WebKit/WKBundleNodeHandlePrivate.h>
+#include <WebKit/WKBundlePagePrivate.h>
+#include <WebKit/WKBundlePrivate.h>
+#include <WebKit/WKSecurityOriginRef.h>
+#include <WebKit/WKURLRequest.h>
#include <wtf/HashMap.h>
#include <wtf/text/CString.h>
#include <wtf/text/StringBuilder.h>
@@ -240,7 +241,7 @@ static inline WTF::String pathSuitableForTestResult(WKURLRef fileUrl)
if (!isLocalFileScheme(schemeString.get()))
return toWTFString(adoptWK(WKURLCopyString(fileUrl)));
- WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
WKRetainPtr<WKURLRef> mainFrameURL = adoptWK(WKBundleFrameCopyURL(mainFrame));
if (!mainFrameURL)
mainFrameURL = adoptWK(WKBundleFrameCopyProvisionalURL(mainFrame));
@@ -268,8 +269,8 @@ InjectedBundlePage::InjectedBundlePage(WKBundlePageRef page)
: m_page(page)
, m_world(AdoptWK, WKBundleScriptWorldCreateWorld())
{
- WKBundlePageLoaderClientV7 loaderClient = {
- { 7, this },
+ WKBundlePageLoaderClientV8 loaderClient = {
+ { 8, this },
didStartProvisionalLoadForFrame,
didReceiveServerRedirectForProvisionalLoadForFrame,
didFailProvisionalLoadWithErrorForFrame,
@@ -304,7 +305,8 @@ InjectedBundlePage::InjectedBundlePage(WKBundlePageRef page)
0, // featuresUsedInPage
0, // willLoadURLRequest
0, // willLoadDataRequest
- 0, // willDestroyFrame
+ 0, // willDestroyFrame_unavailable
+ 0, // userAgentForURL
};
WKBundlePageSetPageLoaderClient(m_page, &loaderClient.base);
@@ -412,14 +414,26 @@ void InjectedBundlePage::prepare()
WKBundleFrameClearOpener(WKBundlePageGetMainFrame(m_page));
WKBundlePageSetTracksRepaints(m_page, false);
+
+ // Force consistent "responsive" behavior for WebPage::eventThrottlingDelay() for testing. Tests can override via internals.
+ WKEventThrottlingBehavior behavior = kWKEventThrottlingBehaviorResponsive;
+ WKBundlePageSetEventThrottlingBehaviorOverride(m_page, &behavior);
}
void InjectedBundlePage::resetAfterTest()
{
WKBundleFrameRef frame = WKBundlePageGetMainFrame(m_page);
+
+ // WebKit currently doesn't reset focus even when navigating to a new page. This may or may not be a bug
+ // (see <https://bugs.webkit.org/show_bug.cgi?id=138334>), however for tests, we want to start each one with a clean state.
+ WKBundleFrameFocus(frame);
+
JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame);
WebCoreTestSupport::resetInternalsObject(context);
assignedUrlsCache.clear();
+
+ // User scripts need to be removed after the test and before loading about:blank, as otherwise they would run in about:blank, and potentially leak results into a subsequest test.
+ WKBundlePageRemoveAllUserContent(m_page);
}
// Loader Client Callbacks
@@ -457,7 +471,7 @@ static void dumpLoadEvent(WKBundleFrameRef frame, const char* eventName)
stringBuilder.appendLiteral(" - ");
stringBuilder.append(eventName);
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ InjectedBundle::singleton().outputText(stringBuilder.toString());
}
static inline void dumpRequestDescriptionSuitableForTestResult(WKURLRequestRef request, StringBuilder& stringBuilder)
@@ -646,49 +660,64 @@ bool InjectedBundlePage::shouldCacheResponse(WKBundlePageRef page, WKBundleFrame
void InjectedBundlePage::didStartProvisionalLoadForFrame(WKBundleFrameRef frame)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
+ if (!injectedBundle.testRunner()->testURL()) {
+ WKRetainPtr<WKURLRef> testURL = adoptWK(WKBundleFrameCopyProvisionalURL(frame));
+ injectedBundle.testRunner()->setTestURL(testURL.get());
+ }
+
platformDidStartProvisionalLoadForFrame(frame);
- if (InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks())
+ if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
dumpLoadEvent(frame, "didStartProvisionalLoadForFrame");
- if (!InjectedBundle::shared().topLoadingFrame())
- InjectedBundle::shared().setTopLoadingFrame(frame);
+ if (!injectedBundle.topLoadingFrame())
+ injectedBundle.setTopLoadingFrame(frame);
- if (InjectedBundle::shared().testRunner()->shouldStopProvisionalFrameLoads())
+ if (injectedBundle.testRunner()->shouldStopProvisionalFrameLoads())
dumpLoadEvent(frame, "stopping load in didStartProvisionalLoadForFrame callback");
}
void InjectedBundlePage::didReceiveServerRedirectForProvisionalLoadForFrame(WKBundleFrameRef frame)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
- if (!InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks())
+ if (!injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
return;
dumpLoadEvent(frame, "didReceiveServerRedirectForProvisionalLoadForFrame");
}
-void InjectedBundlePage::didFailProvisionalLoadWithErrorForFrame(WKBundleFrameRef frame, WKErrorRef)
+void InjectedBundlePage::didFailProvisionalLoadWithErrorForFrame(WKBundleFrameRef frame, WKErrorRef error)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
- if (InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks())
+ if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) {
dumpLoadEvent(frame, "didFailProvisionalLoadWithError");
+ auto code = WKErrorGetErrorCode(error);
+ if (code == kWKErrorCodeCannotShowURL)
+ dumpLoadEvent(frame, "(ErrorCodeCannotShowURL)");
+ else if (code == kWKErrorCodeFrameLoadBlockedByContentBlocker)
+ dumpLoadEvent(frame, "(kWKErrorCodeFrameLoadBlockedByContentBlocker)");
+ }
frameDidChangeLocation(frame);
}
void InjectedBundlePage::didCommitLoadForFrame(WKBundleFrameRef frame)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
- if (!InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks())
+ if (!injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
return;
dumpLoadEvent(frame, "didCommitLoadForFrame");
@@ -696,13 +725,14 @@ void InjectedBundlePage::didCommitLoadForFrame(WKBundleFrameRef frame)
void InjectedBundlePage::didFinishProgress()
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
- if (!InjectedBundle::shared().testRunner()->shouldDumpProgressFinishedCallback())
+ if (!injectedBundle.testRunner()->shouldDumpProgressFinishedCallback())
return;
- InjectedBundle::shared().outputText("postProgressFinishedNotification\n");
+ injectedBundle.outputText("postProgressFinishedNotification\n");
}
enum FrameNamePolicy { ShouldNotIncludeFrameName, ShouldIncludeFrameName };
@@ -816,16 +846,15 @@ void InjectedBundlePage::dumpDOMAsWebArchive(WKBundleFrameRef frame, StringBuild
#if USE(CF)
WKRetainPtr<WKDataRef> wkData = adoptWK(WKBundleFrameCopyWebArchive(frame));
RetainPtr<CFDataRef> cfData = adoptCF(CFDataCreate(0, WKDataGetBytes(wkData.get()), WKDataGetSize(wkData.get())));
- RetainPtr<CFStringRef> cfString = adoptCF(createXMLStringFromWebArchiveData(cfData.get()));
+ RetainPtr<CFStringRef> cfString = adoptCF(WebCoreTestSupport::createXMLStringFromWebArchiveData(cfData.get()));
stringBuilder.append(cfString.get());
#endif
}
void InjectedBundlePage::dump()
{
- ASSERT(InjectedBundle::shared().isTestRunning());
-
- InjectedBundle::shared().testRunner()->invalidateWaitToDumpWatchdogTimer();
+ auto& injectedBundle = InjectedBundle::singleton();
+ ASSERT(injectedBundle.isTestRunning());
// Force a paint before dumping. This matches DumpRenderTree on Windows. (DumpRenderTree on Mac
// does this at a slightly different time.) See <http://webkit.org/b/55469> for details.
@@ -836,13 +865,13 @@ void InjectedBundlePage::dump()
String url = toWTFString(adoptWK(WKURLCopyString(urlRef.get())));
WKRetainPtr<WKStringRef> mimeType = adoptWK(WKBundleFrameCopyMIMETypeForResourceWithURL(frame, urlRef.get()));
if (url.find("dumpAsText/") != notFound || WKStringIsEqualToUTF8CString(mimeType.get(), "text/plain"))
- InjectedBundle::shared().testRunner()->dumpAsText(false);
+ injectedBundle.testRunner()->dumpAsText(false);
StringBuilder stringBuilder;
- switch (InjectedBundle::shared().testRunner()->whatToDump()) {
+ switch (injectedBundle.testRunner()->whatToDump()) {
case TestRunner::RenderTree: {
- if (InjectedBundle::shared().testRunner()->isPrinting())
+ if (injectedBundle.testRunner()->isPrinting())
stringBuilder.append(toWTFString(adoptWK(WKBundlePageCopyRenderTreeExternalRepresentationForPrinting(m_page)).get()));
else
stringBuilder.append(toWTFString(adoptWK(WKBundlePageCopyRenderTreeExternalRepresentation(m_page)).get()));
@@ -861,34 +890,47 @@ void InjectedBundlePage::dump()
break;
}
- if (InjectedBundle::shared().testRunner()->shouldDumpAllFrameScrollPositions())
+ if (injectedBundle.testRunner()->shouldDumpAllFrameScrollPositions())
dumpAllFrameScrollPositions(stringBuilder);
- else if (InjectedBundle::shared().testRunner()->shouldDumpMainFrameScrollPosition())
+ else if (injectedBundle.testRunner()->shouldDumpMainFrameScrollPosition())
dumpFrameScrollPosition(WKBundlePageGetMainFrame(m_page), stringBuilder);
- if (InjectedBundle::shared().testRunner()->shouldDumpBackForwardListsForAllWindows())
- InjectedBundle::shared().dumpBackForwardListsForAllPages(stringBuilder);
+ if (injectedBundle.testRunner()->shouldDumpBackForwardListsForAllWindows())
+ injectedBundle.dumpBackForwardListsForAllPages(stringBuilder);
+
+ if (injectedBundle.shouldDumpPixels() && injectedBundle.testRunner()->shouldDumpPixels()) {
+ bool shouldCreateSnapshot = injectedBundle.testRunner()->isPrinting();
+ if (shouldCreateSnapshot) {
+ WKSnapshotOptions options = kWKSnapshotOptionsShareable;
+ WKRect snapshotRect = WKBundleFrameGetVisibleContentBounds(WKBundlePageGetMainFrame(m_page));
- if (InjectedBundle::shared().shouldDumpPixels() && InjectedBundle::shared().testRunner()->shouldDumpPixels()) {
- WKSnapshotOptions options = kWKSnapshotOptionsShareable | kWKSnapshotOptionsInViewCoordinates;
- if (InjectedBundle::shared().testRunner()->shouldDumpSelectionRect())
- options |= kWKSnapshotOptionsPaintSelectionRectangle;
+ if (injectedBundle.testRunner()->isPrinting())
+ options |= kWKSnapshotOptionsPrinting;
+ else {
+ options |= kWKSnapshotOptionsInViewCoordinates;
+ if (injectedBundle.testRunner()->shouldDumpSelectionRect())
+ options |= kWKSnapshotOptionsPaintSelectionRectangle;
+ }
+
+ injectedBundle.setPixelResult(adoptWK(WKBundlePageCreateSnapshotWithOptions(m_page, snapshotRect, options)).get());
+ } else
+ injectedBundle.setPixelResultIsPending(true);
- InjectedBundle::shared().setPixelResult(adoptWK(WKBundlePageCreateSnapshotWithOptions(m_page, WKBundleFrameGetVisibleContentBounds(WKBundlePageGetMainFrame(m_page)), options)).get());
- if (WKBundlePageIsTrackingRepaints(m_page))
- InjectedBundle::shared().setRepaintRects(adoptWK(WKBundlePageCopyTrackedRepaintRects(m_page)).get());
+ if (WKBundlePageIsTrackingRepaints(m_page) && !injectedBundle.testRunner()->isPrinting())
+ injectedBundle.setRepaintRects(adoptWK(WKBundlePageCopyTrackedRepaintRects(m_page)).get());
}
- InjectedBundle::shared().outputText(stringBuilder.toString());
- InjectedBundle::shared().done();
+ injectedBundle.outputText(stringBuilder.toString());
+ injectedBundle.done();
}
void InjectedBundlePage::didFinishLoadForFrame(WKBundleFrameRef frame)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
- if (InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks())
+ if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
dumpLoadEvent(frame, "didFinishLoadForFrame");
frameDidChangeLocation(frame, /*shouldDump*/ true);
@@ -896,10 +938,11 @@ void InjectedBundlePage::didFinishLoadForFrame(WKBundleFrameRef frame)
void InjectedBundlePage::didFailLoadWithErrorForFrame(WKBundleFrameRef frame, WKErrorRef)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
- if (InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks())
+ if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
dumpLoadEvent(frame, "didFailLoadWithError");
frameDidChangeLocation(frame);
@@ -907,29 +950,31 @@ void InjectedBundlePage::didFailLoadWithErrorForFrame(WKBundleFrameRef frame, WK
void InjectedBundlePage::didReceiveTitleForFrame(WKStringRef title, WKBundleFrameRef frame)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
StringBuilder stringBuilder;
- if (InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks()) {
+ if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) {
dumpFrameDescriptionSuitableForTestResult(frame, stringBuilder);
stringBuilder.appendLiteral(" - didReceiveTitle: ");
stringBuilder.append(toWTFString(title));
stringBuilder.append('\n');
}
- if (InjectedBundle::shared().testRunner()->shouldDumpTitleChanges()) {
+ if (injectedBundle.testRunner()->shouldDumpTitleChanges()) {
stringBuilder.appendLiteral("TITLE CHANGED: '");
stringBuilder.append(toWTFString(title));
stringBuilder.appendLiteral("'\n");
}
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
}
void InjectedBundlePage::didClearWindowForFrame(WKBundleFrameRef frame, WKBundleScriptWorldRef world)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
JSGlobalContextRef context = WKBundleFrameGetJavaScriptContextForWorld(frame, world);
@@ -940,22 +985,23 @@ void InjectedBundlePage::didClearWindowForFrame(WKBundleFrameRef frame, WKBundle
return;
}
- JSValueRef exception = 0;
- InjectedBundle::shared().testRunner()->makeWindowObject(context, window, &exception);
- InjectedBundle::shared().gcController()->makeWindowObject(context, window, &exception);
- InjectedBundle::shared().eventSendingController()->makeWindowObject(context, window, &exception);
- InjectedBundle::shared().textInputController()->makeWindowObject(context, window, &exception);
- InjectedBundle::shared().accessibilityController()->makeWindowObject(context, window, &exception);
+ JSValueRef exception = nullptr;
+ injectedBundle.testRunner()->makeWindowObject(context, window, &exception);
+ injectedBundle.gcController()->makeWindowObject(context, window, &exception);
+ injectedBundle.eventSendingController()->makeWindowObject(context, window, &exception);
+ injectedBundle.textInputController()->makeWindowObject(context, window, &exception);
+ injectedBundle.accessibilityController()->makeWindowObject(context, window, &exception);
WebCoreTestSupport::injectInternalsObject(context);
}
void InjectedBundlePage::didCancelClientRedirectForFrame(WKBundleFrameRef frame)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
- if (!InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks())
+ if (!injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
return;
dumpLoadEvent(frame, "didCancelClientRedirectForFrame");
@@ -963,10 +1009,11 @@ void InjectedBundlePage::didCancelClientRedirectForFrame(WKBundleFrameRef frame)
void InjectedBundlePage::willPerformClientRedirectForFrame(WKBundlePageRef, WKBundleFrameRef frame, WKURLRef url, double delay, double date)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
- if (!InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks())
+ if (!injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
return;
StringBuilder stringBuilder;
@@ -974,19 +1021,31 @@ void InjectedBundlePage::willPerformClientRedirectForFrame(WKBundlePageRef, WKBu
stringBuilder.appendLiteral(" - willPerformClientRedirectToURL: ");
stringBuilder.append(pathSuitableForTestResult(url));
stringBuilder.appendLiteral(" \n");
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
}
void InjectedBundlePage::didSameDocumentNavigationForFrame(WKBundleFrameRef frame, WKSameDocumentNavigationType type)
{
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
+ return;
+
+ if (!injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
+ return;
+
+ if (type != kWKSameDocumentNavigationAnchorNavigation)
+ return;
+
+ dumpLoadEvent(frame, "didChangeLocationWithinPageForFrame");
}
void InjectedBundlePage::didFinishDocumentLoadForFrame(WKBundleFrameRef frame)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
- if (InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks())
+ if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
dumpLoadEvent(frame, "didFinishDocumentLoadForFrame");
unsigned pendingFrameUnloadEvents = WKBundleFrameGetPendingUnloadCount(frame);
@@ -996,40 +1055,44 @@ void InjectedBundlePage::didFinishDocumentLoadForFrame(WKBundleFrameRef frame)
stringBuilder.appendLiteral(" - has ");
stringBuilder.appendNumber(pendingFrameUnloadEvents);
stringBuilder.appendLiteral(" onunload handler(s)\n");
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
}
}
void InjectedBundlePage::didHandleOnloadEventsForFrame(WKBundleFrameRef frame)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
- if (InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks())
+ if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
dumpLoadEvent(frame, "didHandleOnloadEventsForFrame");
}
-void InjectedBundlePage::didDisplayInsecureContentForFrame(WKBundleFrameRef frame)
+void InjectedBundlePage::didDisplayInsecureContentForFrame(WKBundleFrameRef)
{
- if (InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks())
- InjectedBundle::shared().outputText("didDisplayInsecureContent\n");
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
+ injectedBundle.outputText("didDisplayInsecureContent\n");
}
-void InjectedBundlePage::didRunInsecureContentForFrame(WKBundleFrameRef frame)
+void InjectedBundlePage::didRunInsecureContentForFrame(WKBundleFrameRef)
{
- if (InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks())
- InjectedBundle::shared().outputText("didRunInsecureContent\n");
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
+ injectedBundle.outputText("didRunInsecureContent\n");
}
-void InjectedBundlePage::didDetectXSSForFrame(WKBundleFrameRef frame)
+void InjectedBundlePage::didDetectXSSForFrame(WKBundleFrameRef)
{
- if (InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks())
- InjectedBundle::shared().outputText("didDetectXSS\n");
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks())
+ injectedBundle.outputText("didDetectXSS\n");
}
void InjectedBundlePage::didInitiateLoadForResource(WKBundlePageRef page, WKBundleFrameRef, uint64_t identifier, WKURLRequestRef request, bool)
{
- if (!InjectedBundle::shared().isTestRunning())
+ if (!InjectedBundle::singleton().isTestRunning())
return;
WKRetainPtr<WKURLRef> url = adoptWK(WKURLRequestCopyURL(request));
@@ -1048,10 +1111,16 @@ static inline bool isHTTPOrHTTPSScheme(WKStringRef scheme)
return WKStringIsEqualToUTF8CStringIgnoringCase(scheme, "http") || WKStringIsEqualToUTF8CStringIgnoringCase(scheme, "https");
}
+static inline bool isAllowedHost(WKStringRef host)
+{
+ return InjectedBundle::singleton().isAllowedHost(host);
+}
+
WKURLRequestRef InjectedBundlePage::willSendRequestForFrame(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, WKURLRequestRef request, WKURLResponseRef response)
{
- if (InjectedBundle::shared().isTestRunning()
- && InjectedBundle::shared().testRunner()->shouldDumpResourceLoadCallbacks()) {
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (injectedBundle.isTestRunning()
+ && injectedBundle.testRunner()->shouldDumpResourceLoadCallbacks()) {
StringBuilder stringBuilder;
dumpResourceURL(identifier, stringBuilder);
stringBuilder.appendLiteral(" - willSendRequest ");
@@ -1059,16 +1128,16 @@ WKURLRequestRef InjectedBundlePage::willSendRequestForFrame(WKBundlePageRef page
stringBuilder.appendLiteral(" redirectResponse ");
dumpResponseDescriptionSuitableForTestResult(response, stringBuilder);
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
}
- if (InjectedBundle::shared().isTestRunning() && InjectedBundle::shared().testRunner()->willSendRequestReturnsNull())
- return 0;
+ if (injectedBundle.isTestRunning() && injectedBundle.testRunner()->willSendRequestReturnsNull())
+ return nullptr;
WKRetainPtr<WKURLRef> redirectURL = adoptWK(WKURLResponseCopyURL(response));
- if (InjectedBundle::shared().isTestRunning() && InjectedBundle::shared().testRunner()->willSendRequestReturnsNullOnRedirect() && redirectURL) {
- InjectedBundle::shared().outputText("Returning null for this redirect\n");
- return 0;
+ if (injectedBundle.isTestRunning() && injectedBundle.testRunner()->willSendRequestReturnsNullOnRedirect() && redirectURL) {
+ injectedBundle.outputText("Returning null for this redirect\n");
+ return nullptr;
}
WKRetainPtr<WKURLRef> url = adoptWK(WKURLRequestCopyURL(request));
@@ -1080,23 +1149,31 @@ WKURLRequestRef InjectedBundlePage::willSendRequestForFrame(WKBundlePageRef page
&& !WKStringIsEqualToUTF8CString(host.get(), "255.255.255.255") // Used in some tests that expect to get back an error.
&& !isLocalHost(host.get())) {
bool mainFrameIsExternal = false;
- if (InjectedBundle::shared().isTestRunning()) {
- WKBundleFrameRef mainFrame = InjectedBundle::shared().topLoadingFrame();
+ if (injectedBundle.isTestRunning()) {
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(m_page);
WKRetainPtr<WKURLRef> mainFrameURL = adoptWK(WKBundleFrameCopyURL(mainFrame));
if (!mainFrameURL || WKStringIsEqualToUTF8CString(adoptWK(WKURLCopyString(mainFrameURL.get())).get(), "about:blank"))
mainFrameURL = adoptWK(WKBundleFrameCopyProvisionalURL(mainFrame));
- WKRetainPtr<WKStringRef> mainFrameHost = WKURLCopyHostName(mainFrameURL.get());
- WKRetainPtr<WKStringRef> mainFrameScheme = WKURLCopyScheme(mainFrameURL.get());
+ WKRetainPtr<WKStringRef> mainFrameHost = adoptWK(WKURLCopyHostName(mainFrameURL.get()));
+ WKRetainPtr<WKStringRef> mainFrameScheme = adoptWK(WKURLCopyScheme(mainFrameURL.get()));
mainFrameIsExternal = isHTTPOrHTTPSScheme(mainFrameScheme.get()) && !isLocalHost(mainFrameHost.get());
}
- if (!mainFrameIsExternal) {
+ if (!mainFrameIsExternal && !isAllowedHost(host.get())) {
StringBuilder stringBuilder;
stringBuilder.appendLiteral("Blocked access to external URL ");
stringBuilder.append(toWTFString(urlString));
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
- return 0;
+ injectedBundle.outputText(stringBuilder.toString());
+ return nullptr;
+ }
+ }
+
+ if (injectedBundle.isTestRunning()) {
+ String body = injectedBundle.testRunner()->willSendRequestHTTPBody();
+ if (!body.isEmpty()) {
+ CString cBody = body.utf8();
+ return WKURLRequestCopySettingHTTPBody(request, WKDataCreate(reinterpret_cast<const unsigned char*>(cBody.data()), cBody.length()));
}
}
@@ -1106,20 +1183,21 @@ WKURLRequestRef InjectedBundlePage::willSendRequestForFrame(WKBundlePageRef page
void InjectedBundlePage::didReceiveResponseForResource(WKBundlePageRef page, WKBundleFrameRef, uint64_t identifier, WKURLResponseRef response)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
- if (InjectedBundle::shared().testRunner()->shouldDumpResourceLoadCallbacks()) {
+ if (injectedBundle.testRunner()->shouldDumpResourceLoadCallbacks()) {
StringBuilder stringBuilder;
dumpResourceURL(identifier, stringBuilder);
stringBuilder.appendLiteral(" - didReceiveResponse ");
dumpResponseDescriptionSuitableForTestResult(response, stringBuilder);
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
}
- if (!InjectedBundle::shared().testRunner()->shouldDumpResourceResponseMIMETypes())
+ if (!injectedBundle.testRunner()->shouldDumpResourceResponseMIMETypes())
return;
WKRetainPtr<WKURLRef> url = adoptWK(WKURLResponseCopyURL(response));
@@ -1130,8 +1208,16 @@ void InjectedBundlePage::didReceiveResponseForResource(WKBundlePageRef page, WKB
stringBuilder.append(toWTFString(urlString));
stringBuilder.appendLiteral(" has MIME type ");
stringBuilder.append(toWTFString(mimeTypeString));
+
+ String platformMimeType = platformResponseMimeType(response);
+ if (!platformMimeType.isEmpty() && platformMimeType != toWTFString(mimeTypeString)) {
+ stringBuilder.appendLiteral(" but platform response has ");
+ stringBuilder.append(platformMimeType);
+ }
+
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
+
+ injectedBundle.outputText(stringBuilder.toString());
}
void InjectedBundlePage::didReceiveContentLengthForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t, uint64_t)
@@ -1140,24 +1226,26 @@ void InjectedBundlePage::didReceiveContentLengthForResource(WKBundlePageRef, WKB
void InjectedBundlePage::didFinishLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
- if (!InjectedBundle::shared().testRunner()->shouldDumpResourceLoadCallbacks())
+ if (!injectedBundle.testRunner()->shouldDumpResourceLoadCallbacks())
return;
StringBuilder stringBuilder;
dumpResourceURL(identifier, stringBuilder);
stringBuilder.appendLiteral(" - didFinishLoading\n");
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
}
void InjectedBundlePage::didFailLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier, WKErrorRef error)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
- if (!InjectedBundle::shared().testRunner()->shouldDumpResourceLoadCallbacks())
+ if (!injectedBundle.testRunner()->shouldDumpResourceLoadCallbacks())
return;
StringBuilder stringBuilder;
@@ -1166,21 +1254,22 @@ void InjectedBundlePage::didFailLoadForResource(WKBundlePageRef, WKBundleFrameRe
dumpErrorDescriptionSuitableForTestResult(error, stringBuilder);
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
}
bool InjectedBundlePage::shouldCacheResponse(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return true;
- if (!InjectedBundle::shared().testRunner()->shouldDumpWillCacheResponse())
+ if (!injectedBundle.testRunner()->shouldDumpWillCacheResponse())
return true;
StringBuilder stringBuilder;
stringBuilder.appendNumber(identifier);
stringBuilder.appendLiteral(" - willCacheResponse: called\n");
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
// The default behavior is the cache the response.
return true;
@@ -1211,11 +1300,30 @@ void InjectedBundlePage::unableToImplementPolicy(WKBundlePageRef page, WKBundleF
WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForNavigationAction(WKBundlePageRef page, WKBundleFrameRef frame, WKBundleNavigationActionRef navigationAction, WKURLRequestRef request, WKTypeRef* userData)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return WKBundlePagePolicyActionUse;
- if (!InjectedBundle::shared().testRunner()->isPolicyDelegateEnabled())
- return WKBundlePagePolicyActionUse;
+ if (injectedBundle.testRunner()->shouldDumpPolicyCallbacks()) {
+ StringBuilder stringBuilder;
+ stringBuilder.appendLiteral(" - decidePolicyForNavigationAction \n");
+ dumpRequestDescriptionSuitableForTestResult(request, stringBuilder);
+ stringBuilder.appendLiteral(" is main frame - ");
+ stringBuilder.append(WKBundleFrameIsMainFrame(frame) ? "yes" : "no");
+ stringBuilder.appendLiteral(" should open URLs externally - ");
+ stringBuilder.append(WKBundleNavigationActionGetShouldOpenExternalURLs(navigationAction) ? "yes" : "no");
+ stringBuilder.append('\n');
+ injectedBundle.outputText(stringBuilder.toString());
+ }
+
+ if (injectedBundle.testRunner()->shouldDecideNavigationPolicyAfterDelay())
+ return WKBundlePagePolicyActionPassThrough;
+
+ if (!injectedBundle.testRunner()->isPolicyDelegateEnabled()) {
+ WKRetainPtr<WKStringRef> downloadAttributeRef(AdoptWK, WKBundleNavigationActionCopyDownloadAttribute(navigationAction));
+ String downloadAttribute = toWTFString(downloadAttributeRef);
+ return downloadAttribute.isNull() ? WKBundlePagePolicyActionUse : WKBundlePagePolicyActionPassThrough;
+ }
WKRetainPtr<WKURLRef> url = adoptWK(WKURLRequestCopyURL(request));
WKRetainPtr<WKStringRef> urlScheme = adoptWK(WKURLCopyScheme(url.get()));
@@ -1239,10 +1347,10 @@ WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForNavigationAction(WKB
}
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
- InjectedBundle::shared().testRunner()->notifyDone();
+ injectedBundle.outputText(stringBuilder.toString());
+ injectedBundle.testRunner()->notifyDone();
- if (InjectedBundle::shared().testRunner()->isPolicyDelegatePermissive())
+ if (injectedBundle.testRunner()->isPolicyDelegatePermissive())
return WKBundlePagePolicyActionUse;
return WKBundlePagePolicyActionPassThrough;
}
@@ -1254,13 +1362,13 @@ WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForNewWindowAction(WKBu
WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForResponse(WKBundlePageRef page, WKBundleFrameRef, WKURLResponseRef response, WKURLRequestRef, WKTypeRef*)
{
- if (WKURLResponseIsAttachment(response)) {
+ if (InjectedBundle::singleton().testRunner()->isPolicyDelegateEnabled() && WKURLResponseIsAttachment(response)) {
StringBuilder stringBuilder;
WKRetainPtr<WKStringRef> filename = adoptWK(WKURLResponseCopySuggestedFilename(response));
stringBuilder.appendLiteral("Policy delegate: resource is an attachment, suggested file name \'");
stringBuilder.append(toWTFString(filename));
stringBuilder.appendLiteral("\'\n");
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ InjectedBundle::singleton().outputText(stringBuilder.toString());
}
WKRetainPtr<WKStringRef> mimeType = adoptWK(WKURLResponseCopyMIMEType(response));
@@ -1330,7 +1438,8 @@ static WTF::String lastFileURLPathComponent(const WTF::String& path)
void InjectedBundlePage::willAddMessageToConsole(WKStringRef message, uint32_t lineNumber)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
WTF::String messageString = toWTFString(message);
@@ -1352,46 +1461,53 @@ void InjectedBundlePage::willAddMessageToConsole(WKStringRef message, uint32_t l
}
stringBuilder.append(messageString);
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
+
+ if (injectedBundle.dumpJSConsoleLogInStdErr())
+ injectedBundle.dumpToStdErr(stringBuilder.toString());
+ else
+ injectedBundle.outputText(stringBuilder.toString());
}
void InjectedBundlePage::willSetStatusbarText(WKStringRef statusbarText)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
- if (!InjectedBundle::shared().testRunner()->shouldDumpStatusCallbacks())
+ if (!injectedBundle.testRunner()->shouldDumpStatusCallbacks())
return;
StringBuilder stringBuilder;
stringBuilder.appendLiteral("UI DELEGATE STATUS CALLBACK: setStatusText:");
stringBuilder.append(toWTFString(statusbarText));
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
}
void InjectedBundlePage::willRunJavaScriptAlert(WKStringRef message, WKBundleFrameRef)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
StringBuilder stringBuilder;
stringBuilder.appendLiteral("ALERT: ");
stringBuilder.append(toWTFString(message));
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
}
void InjectedBundlePage::willRunJavaScriptConfirm(WKStringRef message, WKBundleFrameRef)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
StringBuilder stringBuilder;
stringBuilder.appendLiteral("CONFIRM: ");
stringBuilder.append(toWTFString(message));
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
}
void InjectedBundlePage::willRunJavaScriptPrompt(WKStringRef message, WKStringRef defaultValue, WKBundleFrameRef)
@@ -1402,12 +1518,13 @@ void InjectedBundlePage::willRunJavaScriptPrompt(WKStringRef message, WKStringRe
stringBuilder.appendLiteral(", default text: ");
stringBuilder.append(toWTFString(defaultValue));
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ InjectedBundle::singleton().outputText(stringBuilder.toString());
}
void InjectedBundlePage::didReachApplicationCacheOriginQuota(WKSecurityOriginRef origin, int64_t totalBytesNeeded)
{
- if (InjectedBundle::shared().testRunner()->shouldDumpApplicationCacheDelegateCallbacks()) {
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (injectedBundle.testRunner()->shouldDumpApplicationCacheDelegateCallbacks()) {
// For example, numbers from 30000 - 39999 will output as 30000.
// Rounding up or down does not really matter for these tests. It's
// sufficient to just get a range of 10000 to determine if we were
@@ -1420,36 +1537,37 @@ void InjectedBundlePage::didReachApplicationCacheOriginQuota(WKSecurityOriginRef
stringBuilder.appendLiteral(" totalSpaceNeeded:~");
stringBuilder.appendNumber(truncatedSpaceNeeded);
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
}
- if (InjectedBundle::shared().testRunner()->shouldDisallowIncreaseForApplicationCacheQuota())
+ if (injectedBundle.testRunner()->shouldDisallowIncreaseForApplicationCacheQuota())
return;
// Reset default application cache quota.
- WKBundleResetApplicationCacheOriginQuota(InjectedBundle::shared().bundle(), adoptWK(WKSecurityOriginCopyToString(origin)).get());
+ WKBundlePageResetApplicationCacheOriginQuota(injectedBundle.page()->page(), adoptWK(WKSecurityOriginCopyToString(origin)).get());
}
uint64_t InjectedBundlePage::didExceedDatabaseQuota(WKSecurityOriginRef origin, WKStringRef databaseName, WKStringRef databaseDisplayName, uint64_t currentQuotaBytes, uint64_t currentOriginUsageBytes, uint64_t currentDatabaseUsageBytes, uint64_t expectedUsageBytes)
{
- if (InjectedBundle::shared().testRunner()->shouldDumpDatabaseCallbacks()) {
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (injectedBundle.testRunner()->shouldDumpDatabaseCallbacks()) {
StringBuilder stringBuilder;
stringBuilder.appendLiteral("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:");
stringBuilder.append(securityOriginToStr(origin));
stringBuilder.appendLiteral(" database:");
stringBuilder.append(toWTFString(databaseName));
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
}
uint64_t defaultQuota = 5 * 1024 * 1024;
- double testDefaultQuota = InjectedBundle::shared().testRunner()->databaseDefaultQuota();
+ double testDefaultQuota = injectedBundle.testRunner()->databaseDefaultQuota();
if (testDefaultQuota >= 0)
defaultQuota = testDefaultQuota;
unsigned long long newQuota = defaultQuota;
- double maxQuota = InjectedBundle::shared().testRunner()->databaseMaxQuota();
+ double maxQuota = injectedBundle.testRunner()->databaseMaxQuota();
if (maxQuota >= 0) {
if (defaultQuota < expectedUsageBytes && expectedUsageBytes <= maxQuota) {
newQuota = expectedUsageBytes;
@@ -1458,7 +1576,7 @@ uint64_t InjectedBundlePage::didExceedDatabaseQuota(WKSecurityOriginRef origin,
stringBuilder.appendLiteral("UI DELEGATE DATABASE CALLBACK: increased quota to ");
stringBuilder.appendNumber(newQuota);
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
}
}
return newQuota;
@@ -1523,37 +1641,40 @@ void InjectedBundlePage::didChangeSelection(WKBundlePageRef page, WKStringRef no
bool InjectedBundlePage::shouldBeginEditing(WKBundleRangeHandleRef range)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return true;
- if (InjectedBundle::shared().testRunner()->shouldDumpEditingCallbacks()) {
+ if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) {
StringBuilder stringBuilder;
stringBuilder.appendLiteral("EDITING DELEGATE: shouldBeginEditingInDOMRange:");
stringBuilder.append(rangeToStr(m_page, m_world.get(), range));
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
}
- return InjectedBundle::shared().testRunner()->shouldAllowEditing();
+ return injectedBundle.testRunner()->shouldAllowEditing();
}
bool InjectedBundlePage::shouldEndEditing(WKBundleRangeHandleRef range)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return true;
- if (InjectedBundle::shared().testRunner()->shouldDumpEditingCallbacks()) {
+ if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) {
StringBuilder stringBuilder;
stringBuilder.appendLiteral("EDITING DELEGATE: shouldEndEditingInDOMRange:");
stringBuilder.append(rangeToStr(m_page, m_world.get(), range));
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
}
- return InjectedBundle::shared().testRunner()->shouldAllowEditing();
+ return injectedBundle.testRunner()->shouldAllowEditing();
}
bool InjectedBundlePage::shouldInsertNode(WKBundleNodeHandleRef node, WKBundleRangeHandleRef rangeToReplace, WKInsertActionType action)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return true;
static const char* insertactionstring[] = {
@@ -1562,7 +1683,7 @@ bool InjectedBundlePage::shouldInsertNode(WKBundleNodeHandleRef node, WKBundleRa
"WebViewInsertActionDropped",
};
- if (InjectedBundle::shared().testRunner()->shouldDumpEditingCallbacks()) {
+ if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) {
StringBuilder stringBuilder;
stringBuilder.appendLiteral("EDITING DELEGATE: shouldInsertNode:");
stringBuilder.append(dumpPath(m_page, m_world.get(), node));
@@ -1571,14 +1692,15 @@ bool InjectedBundlePage::shouldInsertNode(WKBundleNodeHandleRef node, WKBundleRa
stringBuilder.appendLiteral(" givenAction:");
stringBuilder.append(insertactionstring[action]);
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
}
- return InjectedBundle::shared().testRunner()->shouldAllowEditing();
+ return injectedBundle.testRunner()->shouldAllowEditing();
}
bool InjectedBundlePage::shouldInsertText(WKStringRef text, WKBundleRangeHandleRef rangeToReplace, WKInsertActionType action)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return true;
static const char *insertactionstring[] = {
@@ -1587,7 +1709,7 @@ bool InjectedBundlePage::shouldInsertText(WKStringRef text, WKBundleRangeHandleR
"WebViewInsertActionDropped",
};
- if (InjectedBundle::shared().testRunner()->shouldDumpEditingCallbacks()) {
+ if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) {
StringBuilder stringBuilder;
stringBuilder.appendLiteral("EDITING DELEGATE: shouldInsertText:");
stringBuilder.append(toWTFString(text));
@@ -1596,29 +1718,31 @@ bool InjectedBundlePage::shouldInsertText(WKStringRef text, WKBundleRangeHandleR
stringBuilder.appendLiteral(" givenAction:");
stringBuilder.append(insertactionstring[action]);
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
}
- return InjectedBundle::shared().testRunner()->shouldAllowEditing();
+ return injectedBundle.testRunner()->shouldAllowEditing();
}
bool InjectedBundlePage::shouldDeleteRange(WKBundleRangeHandleRef range)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return true;
- if (InjectedBundle::shared().testRunner()->shouldDumpEditingCallbacks()) {
+ if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) {
StringBuilder stringBuilder;
stringBuilder.appendLiteral("EDITING DELEGATE: shouldDeleteDOMRange:");
stringBuilder.append(rangeToStr(m_page, m_world.get(), range));
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
}
- return InjectedBundle::shared().testRunner()->shouldAllowEditing();
+ return injectedBundle.testRunner()->shouldAllowEditing();
}
bool InjectedBundlePage::shouldChangeSelectedRange(WKBundleRangeHandleRef fromRange, WKBundleRangeHandleRef toRange, WKAffinityType affinity, bool stillSelecting)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return true;
static const char *affinitystring[] = {
@@ -1630,7 +1754,7 @@ bool InjectedBundlePage::shouldChangeSelectedRange(WKBundleRangeHandleRef fromRa
"TRUE"
};
- if (InjectedBundle::shared().testRunner()->shouldDumpEditingCallbacks()) {
+ if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) {
StringBuilder stringBuilder;
stringBuilder.appendLiteral("EDITING DELEGATE: shouldChangeSelectedDOMRange:");
stringBuilder.append(rangeToStr(m_page, m_world.get(), fromRange));
@@ -1641,98 +1765,105 @@ bool InjectedBundlePage::shouldChangeSelectedRange(WKBundleRangeHandleRef fromRa
stringBuilder.appendLiteral(" stillSelecting:");
stringBuilder.append(boolstring[stillSelecting]);
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
}
- return InjectedBundle::shared().testRunner()->shouldAllowEditing();
+ return injectedBundle.testRunner()->shouldAllowEditing();
}
bool InjectedBundlePage::shouldApplyStyle(WKBundleCSSStyleDeclarationRef style, WKBundleRangeHandleRef range)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return true;
- if (InjectedBundle::shared().testRunner()->shouldDumpEditingCallbacks()) {
+ if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) {
StringBuilder stringBuilder;
stringBuilder.appendLiteral("EDITING DELEGATE: shouldApplyStyle:");
stringBuilder.append(styleDecToStr(style));
stringBuilder.appendLiteral(" toElementsInDOMRange:");
stringBuilder.append(rangeToStr(m_page, m_world.get(), range));
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
}
- return InjectedBundle::shared().testRunner()->shouldAllowEditing();
+ return injectedBundle.testRunner()->shouldAllowEditing();
}
void InjectedBundlePage::didBeginEditing(WKStringRef notificationName)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
- if (!InjectedBundle::shared().testRunner()->shouldDumpEditingCallbacks())
+ if (!injectedBundle.testRunner()->shouldDumpEditingCallbacks())
return;
StringBuilder stringBuilder;
stringBuilder.appendLiteral("EDITING DELEGATE: webViewDidBeginEditing:");
stringBuilder.append(toWTFString(notificationName));
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
}
void InjectedBundlePage::didEndEditing(WKStringRef notificationName)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
- if (!InjectedBundle::shared().testRunner()->shouldDumpEditingCallbacks())
+ if (!injectedBundle.testRunner()->shouldDumpEditingCallbacks())
return;
StringBuilder stringBuilder;
stringBuilder.appendLiteral("EDITING DELEGATE: webViewDidEndEditing:");
stringBuilder.append(toWTFString(notificationName));
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
}
void InjectedBundlePage::didChange(WKStringRef notificationName)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
- if (!InjectedBundle::shared().testRunner()->shouldDumpEditingCallbacks())
+ if (!injectedBundle.testRunner()->shouldDumpEditingCallbacks())
return;
StringBuilder stringBuilder;
stringBuilder.appendLiteral("EDITING DELEGATE: webViewDidChange:");
stringBuilder.append(toWTFString(notificationName));
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
}
void InjectedBundlePage::didChangeSelection(WKStringRef notificationName)
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
- if (!InjectedBundle::shared().testRunner()->shouldDumpEditingCallbacks())
+ if (!injectedBundle.testRunner()->shouldDumpEditingCallbacks())
return;
StringBuilder stringBuilder;
stringBuilder.appendLiteral("EDITING DELEGATE: webViewDidChangeSelection:");
stringBuilder.append(toWTFString(notificationName));
stringBuilder.append('\n');
- InjectedBundle::shared().outputText(stringBuilder.toString());
+ injectedBundle.outputText(stringBuilder.toString());
}
#if ENABLE(FULLSCREEN_API)
bool InjectedBundlePage::supportsFullScreen(WKBundlePageRef pageRef, WKFullScreenKeyboardRequestType requestType)
{
- if (InjectedBundle::shared().testRunner()->shouldDumpFullScreenCallbacks())
- InjectedBundle::shared().outputText("supportsFullScreen() == true\n");
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (injectedBundle.testRunner()->shouldDumpFullScreenCallbacks())
+ injectedBundle.outputText("supportsFullScreen() == true\n");
return true;
}
void InjectedBundlePage::enterFullScreenForElement(WKBundlePageRef pageRef, WKBundleNodeHandleRef elementRef)
{
- if (InjectedBundle::shared().testRunner()->shouldDumpFullScreenCallbacks())
- InjectedBundle::shared().outputText("enterFullScreenForElement()\n");
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (injectedBundle.testRunner()->shouldDumpFullScreenCallbacks())
+ injectedBundle.outputText("enterFullScreenForElement()\n");
- if (!InjectedBundle::shared().testRunner()->hasCustomFullScreenBehavior()) {
+ if (!injectedBundle.testRunner()->hasCustomFullScreenBehavior()) {
WKBundlePageWillEnterFullScreen(pageRef);
WKBundlePageDidEnterFullScreen(pageRef);
}
@@ -1740,10 +1871,11 @@ void InjectedBundlePage::enterFullScreenForElement(WKBundlePageRef pageRef, WKBu
void InjectedBundlePage::exitFullScreenForElement(WKBundlePageRef pageRef, WKBundleNodeHandleRef elementRef)
{
- if (InjectedBundle::shared().testRunner()->shouldDumpFullScreenCallbacks())
- InjectedBundle::shared().outputText("exitFullScreenForElement()\n");
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (injectedBundle.testRunner()->shouldDumpFullScreenCallbacks())
+ injectedBundle.outputText("exitFullScreenForElement()\n");
- if (!InjectedBundle::shared().testRunner()->hasCustomFullScreenBehavior()) {
+ if (!injectedBundle.testRunner()->hasCustomFullScreenBehavior()) {
WKBundlePageWillExitFullScreen(pageRef);
WKBundlePageDidExitFullScreen(pageRef);
}
@@ -1751,22 +1883,25 @@ void InjectedBundlePage::exitFullScreenForElement(WKBundlePageRef pageRef, WKBun
void InjectedBundlePage::beganEnterFullScreen(WKBundlePageRef, WKRect, WKRect)
{
- if (InjectedBundle::shared().testRunner()->shouldDumpFullScreenCallbacks())
- InjectedBundle::shared().outputText("beganEnterFullScreen()\n");
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (injectedBundle.testRunner()->shouldDumpFullScreenCallbacks())
+ injectedBundle.outputText("beganEnterFullScreen()\n");
}
void InjectedBundlePage::beganExitFullScreen(WKBundlePageRef, WKRect, WKRect)
{
- if (InjectedBundle::shared().testRunner()->shouldDumpFullScreenCallbacks())
- InjectedBundle::shared().outputText("beganExitFullScreen()\n");
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (injectedBundle.testRunner()->shouldDumpFullScreenCallbacks())
+ injectedBundle.outputText("beganExitFullScreen()\n");
}
void InjectedBundlePage::closeFullScreen(WKBundlePageRef pageRef)
{
- if (InjectedBundle::shared().testRunner()->shouldDumpFullScreenCallbacks())
- InjectedBundle::shared().outputText("closeFullScreen()\n");
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (injectedBundle.testRunner()->shouldDumpFullScreenCallbacks())
+ injectedBundle.outputText("closeFullScreen()\n");
- if (!InjectedBundle::shared().testRunner()->hasCustomFullScreenBehavior()) {
+ if (!injectedBundle.testRunner()->hasCustomFullScreenBehavior()) {
WKBundlePageWillExitFullScreen(pageRef);
WKBundlePageDidExitFullScreen(pageRef);
}
@@ -1862,31 +1997,37 @@ void InjectedBundlePage::dumpBackForwardList(StringBuilder& stringBuilder)
stringBuilder.appendLiteral("===============================================\n");
}
-#if !PLATFORM(MAC)
+#if !PLATFORM(COCOA)
void InjectedBundlePage::platformDidStartProvisionalLoadForFrame(WKBundleFrameRef)
{
}
+
+String InjectedBundlePage::platformResponseMimeType(WKURLResponseRef)
+{
+ return String();
+}
#endif
void InjectedBundlePage::frameDidChangeLocation(WKBundleFrameRef frame, bool shouldDump)
{
- if (frame != InjectedBundle::shared().topLoadingFrame())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (frame != injectedBundle.topLoadingFrame())
return;
- InjectedBundle::shared().setTopLoadingFrame(0);
+ injectedBundle.setTopLoadingFrame(nullptr);
- if (InjectedBundle::shared().testRunner()->waitToDump())
+ if (injectedBundle.testRunner()->waitToDump())
return;
- if (InjectedBundle::shared().shouldProcessWorkQueue()) {
- InjectedBundle::shared().processWorkQueue();
+ if (injectedBundle.shouldProcessWorkQueue()) {
+ injectedBundle.processWorkQueue();
return;
}
if (shouldDump)
- InjectedBundle::shared().page()->dump();
+ injectedBundle.page()->dump();
else
- InjectedBundle::shared().done();
+ injectedBundle.done();
}
} // namespace WTR
diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h
index f01b50b54..746fc33c5 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h
+++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h
@@ -26,9 +26,9 @@
#ifndef InjectedBundlePage_h
#define InjectedBundlePage_h
-#include <WebKit2/WKBundlePage.h>
-#include <WebKit2/WKBundleScriptWorld.h>
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKBundlePage.h>
+#include <WebKit/WKBundleScriptWorld.h>
+#include <WebKit/WKRetainPtr.h>
#include <wtf/text/WTFString.h>
namespace WTR {
@@ -169,6 +169,7 @@ private:
void dumpDOMAsWebArchive(WKBundleFrameRef, WTF::StringBuilder&);
void platformDidStartProvisionalLoadForFrame(WKBundleFrameRef);
+ String platformResponseMimeType(WKURLResponseRef);
void frameDidChangeLocation(WKBundleFrameRef, bool shouldDump = false);
diff --git a/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp b/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp
index 2b30f5df6..6f7eb0c07 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp
+++ b/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2010-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -33,20 +33,22 @@
#include "StringFunctions.h"
#include "TestController.h"
#include <JavaScriptCore/JSCTestRunnerUtils.h>
-#include <WebKit2/WKBundle.h>
-#include <WebKit2/WKBundleBackForwardList.h>
-#include <WebKit2/WKBundleFrame.h>
-#include <WebKit2/WKBundleFramePrivate.h>
-#include <WebKit2/WKBundleInspector.h>
-#include <WebKit2/WKBundleNodeHandlePrivate.h>
-#include <WebKit2/WKBundlePage.h>
-#include <WebKit2/WKBundlePagePrivate.h>
-#include <WebKit2/WKBundlePrivate.h>
-#include <WebKit2/WKBundleScriptWorld.h>
-#include <WebKit2/WKData.h>
-#include <WebKit2/WKRetainPtr.h>
-#include <WebKit2/WKSerializedScriptValue.h>
-#include <WebKit2/WebKit2_C.h>
+#include <WebCore/ResourceLoadObserver.h>
+#include <WebKit/WKBundle.h>
+#include <WebKit/WKBundleBackForwardList.h>
+#include <WebKit/WKBundleFrame.h>
+#include <WebKit/WKBundleFramePrivate.h>
+#include <WebKit/WKBundleInspector.h>
+#include <WebKit/WKBundleNodeHandlePrivate.h>
+#include <WebKit/WKBundlePage.h>
+#include <WebKit/WKBundlePagePrivate.h>
+#include <WebKit/WKBundlePrivate.h>
+#include <WebKit/WKBundleScriptWorld.h>
+#include <WebKit/WKData.h>
+#include <WebKit/WKPagePrivate.h>
+#include <WebKit/WKRetainPtr.h>
+#include <WebKit/WKSerializedScriptValue.h>
+#include <WebKit/WebKit2_C.h>
#include <wtf/CurrentTime.h>
#include <wtf/HashMap.h>
#include <wtf/StdLibExtras.h>
@@ -55,11 +57,9 @@
namespace WTR {
-const double TestRunner::waitToDumpWatchdogTimerInterval = 30;
-
-PassRefPtr<TestRunner> TestRunner::create()
+Ref<TestRunner> TestRunner::create()
{
- return adoptRef(new TestRunner);
+ return adoptRef(*new TestRunner);
}
TestRunner::TestRunner()
@@ -93,10 +93,14 @@ TestRunner::TestRunner()
, m_policyDelegatePermissive(false)
, m_globalFlag(false)
, m_customFullScreenBehavior(false)
+ , m_timeout(30000)
, m_databaseDefaultQuota(-1)
, m_databaseMaxQuota(-1)
, m_userStyleSheetEnabled(false)
, m_userStyleSheetLocation(adoptWK(WKStringCreateWithUTF8CString("")))
+#if PLATFORM(GTK)
+ , m_waitToDumpWatchdogTimer(RunLoop::main(), this, &TestRunner::waitToDumpWatchdogTimerFired)
+#endif
{
platformInitialize();
}
@@ -112,7 +116,7 @@ JSClassRef TestRunner::wrapperClass()
void TestRunner::display()
{
- WKBundlePageRef page = InjectedBundle::shared().page()->page();
+ WKBundlePageRef page = InjectedBundle::singleton().page()->page();
WKBundlePageForceRepaint(page);
WKBundlePageSetTracksRepaints(page, true);
WKBundlePageResetTrackedRepaints(page);
@@ -130,7 +134,7 @@ void TestRunner::setCustomPolicyDelegate(bool enabled, bool permissive)
m_policyDelegateEnabled = enabled;
m_policyDelegatePermissive = permissive;
- InjectedBundle::shared().setCustomPolicyDelegate(enabled, permissive);
+ InjectedBundle::singleton().setCustomPolicyDelegate(enabled, permissive);
}
void TestRunner::waitForPolicyDelegate()
@@ -139,42 +143,58 @@ void TestRunner::waitForPolicyDelegate()
waitUntilDone();
}
+void TestRunner::waitUntilDownloadFinished()
+{
+ m_shouldFinishAfterDownload = true;
+ waitUntilDone();
+}
+
void TestRunner::waitUntilDone()
{
m_waitToDump = true;
- if (InjectedBundle::shared().useWaitToDumpWatchdogTimer())
+ if (InjectedBundle::singleton().useWaitToDumpWatchdogTimer())
initializeWaitToDumpWatchdogTimerIfNeeded();
}
void TestRunner::waitToDumpWatchdogTimerFired()
{
invalidateWaitToDumpWatchdogTimer();
- InjectedBundle::shared().outputText("FAIL: Timed out waiting for notifyDone to be called\n\n");
- InjectedBundle::shared().done();
+ auto& injectedBundle = InjectedBundle::singleton();
+#if PLATFORM(COCOA)
+ char buffer[1024];
+ snprintf(buffer, sizeof(buffer), "#PID UNRESPONSIVE - %s (pid %d)\n", getprogname(), getpid());
+ injectedBundle.outputText(buffer);
+#endif
+ injectedBundle.outputText("FAIL: Timed out waiting for notifyDone to be called\n\n");
+ injectedBundle.done();
}
void TestRunner::notifyDone()
{
- if (!InjectedBundle::shared().isTestRunning())
+ auto& injectedBundle = InjectedBundle::singleton();
+ if (!injectedBundle.isTestRunning())
return;
- if (m_waitToDump && !InjectedBundle::shared().topLoadingFrame())
- InjectedBundle::shared().page()->dump();
+ if (m_waitToDump && !injectedBundle.topLoadingFrame())
+ injectedBundle.page()->dump();
+
+ // We don't call invalidateWaitToDumpWatchdogTimer() here, even if we continue to wait for a load to finish.
+ // The test is still subject to timeout checking - it is better to detect an async timeout inside WebKitTestRunner
+ // than to let webkitpy do that, because WebKitTestRunner will dump partial results.
m_waitToDump = false;
}
-void TestRunner::setCustomTimeout(int timeout)
+unsigned TestRunner::imageCountInGeneralPasteboard() const
{
- m_timeout = timeout;
+ return InjectedBundle::singleton().imageCountInGeneralPasteboard();
}
void TestRunner::addUserScript(JSStringRef source, bool runAtStart, bool allFrames)
{
WKRetainPtr<WKStringRef> sourceWK = toWK(source);
- WKRetainPtr<WKBundleScriptWorldRef> scriptWorld(AdoptWK, WKBundleScriptWorldCreateWorld());
- WKBundleAddUserScript(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), scriptWorld.get(), sourceWK.get(), 0, 0, 0,
+ WKBundlePageAddUserScript(InjectedBundle::singleton().page()->page(), sourceWK.get(),
(runAtStart ? kWKInjectAtDocumentStart : kWKInjectAtDocumentEnd),
(allFrames ? kWKInjectInAllFrames : kWKInjectInTopFrameOnly));
}
@@ -182,27 +202,27 @@ void TestRunner::addUserScript(JSStringRef source, bool runAtStart, bool allFram
void TestRunner::addUserStyleSheet(JSStringRef source, bool allFrames)
{
WKRetainPtr<WKStringRef> sourceWK = toWK(source);
- WKRetainPtr<WKBundleScriptWorldRef> scriptWorld(AdoptWK, WKBundleScriptWorldCreateWorld());
- WKBundleAddUserStyleSheet(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), scriptWorld.get(), sourceWK.get(), 0, 0, 0,
+ WKBundlePageAddUserStyleSheet(InjectedBundle::singleton().page()->page(), sourceWK.get(),
(allFrames ? kWKInjectInAllFrames : kWKInjectInTopFrameOnly));
}
void TestRunner::keepWebHistory()
{
- WKBundleSetShouldTrackVisitedLinks(InjectedBundle::shared().bundle(), true);
+ InjectedBundle::singleton().postSetAddsVisitedLinks(true);
}
void TestRunner::execCommand(JSStringRef name, JSStringRef argument)
{
- WKBundlePageExecuteEditingCommand(InjectedBundle::shared().page()->page(), toWK(name).get(), toWK(argument).get());
+ WKBundlePageExecuteEditingCommand(InjectedBundle::singleton().page()->page(), toWK(name).get(), toWK(argument).get());
}
bool TestRunner::findString(JSStringRef target, JSValueRef optionsArrayAsValue)
{
WKFindOptions options = 0;
- WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
JSRetainPtr<JSStringRef> lengthPropertyName(Adopt, JSStringCreateWithUTF8CString("length"));
JSObjectRef optionsArray = JSValueToObject(context, optionsArrayAsValue, 0);
@@ -233,37 +253,42 @@ bool TestRunner::findString(JSStringRef target, JSValueRef optionsArrayAsValue)
}
}
- return WKBundlePageFindString(InjectedBundle::shared().page()->page(), toWK(target).get(), options);
+ return WKBundlePageFindString(injectedBundle.page()->page(), toWK(target).get(), options);
}
void TestRunner::clearAllDatabases()
{
- WKBundleClearAllDatabases(InjectedBundle::shared().bundle());
+ WKBundleClearAllDatabases(InjectedBundle::singleton().bundle());
+
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("DeleteAllIndexedDatabases"));
+ WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(true));
+
+ WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
}
void TestRunner::setDatabaseQuota(uint64_t quota)
{
- return WKBundleSetDatabaseQuota(InjectedBundle::shared().bundle(), quota);
+ return WKBundleSetDatabaseQuota(InjectedBundle::singleton().bundle(), quota);
}
void TestRunner::clearAllApplicationCaches()
{
- WKBundleClearApplicationCache(InjectedBundle::shared().bundle());
+ WKBundlePageClearApplicationCache(InjectedBundle::singleton().page()->page());
}
void TestRunner::clearApplicationCacheForOrigin(JSStringRef origin)
{
- WKBundleClearApplicationCacheForOrigin(InjectedBundle::shared().bundle(), toWK(origin).get());
+ WKBundlePageClearApplicationCacheForOrigin(InjectedBundle::singleton().page()->page(), toWK(origin).get());
}
void TestRunner::setAppCacheMaximumSize(uint64_t size)
{
- WKBundleSetAppCacheMaximumSize(InjectedBundle::shared().bundle(), size);
+ WKBundlePageSetAppCacheMaximumSize(InjectedBundle::singleton().page()->page(), size);
}
long long TestRunner::applicationCacheDiskUsageForOrigin(JSStringRef origin)
{
- return WKBundleGetAppCacheUsageForOrigin(InjectedBundle::shared().bundle(), toWK(origin).get());
+ return WKBundlePageGetAppCacheUsageForOrigin(InjectedBundle::singleton().page()->page(), toWK(origin).get());
}
void TestRunner::disallowIncreaseForApplicationCacheQuota()
@@ -275,21 +300,24 @@ static inline JSValueRef stringArrayToJS(JSContextRef context, WKArrayRef string
{
const size_t count = WKArrayGetSize(strings);
- auto jsStringsArray = std::make_unique<JSValueRef[]>(count);
+ JSValueRef arrayResult = JSObjectMakeArray(context, 0, 0, 0);
+ JSObjectRef arrayObj = JSValueToObject(context, arrayResult, 0);
for (size_t i = 0; i < count; ++i) {
WKStringRef stringRef = static_cast<WKStringRef>(WKArrayGetItemAtIndex(strings, i));
JSRetainPtr<JSStringRef> stringJS = toJS(stringRef);
- jsStringsArray[i] = JSValueMakeString(context, stringJS.get());
+ JSObjectSetPropertyAtIndex(context, arrayObj, i, JSValueMakeString(context, stringJS.get()), 0);
}
- return JSObjectMakeArray(context, count, jsStringsArray.get(), 0);
+ return arrayResult;
}
JSValueRef TestRunner::originsWithApplicationCache()
{
- WKRetainPtr<WKArrayRef> origins(AdoptWK, WKBundleCopyOriginsWithApplicationCache(InjectedBundle::shared().bundle()));
+ WKBundlePageRef page = InjectedBundle::singleton().page()->page();
+
+ WKRetainPtr<WKArrayRef> origins(AdoptWK, WKBundlePageCopyOriginsWithApplicationCache(page));
- WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(page);
JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
return stringArrayToJS(context, origins.get());
@@ -297,70 +325,174 @@ JSValueRef TestRunner::originsWithApplicationCache()
bool TestRunner::isCommandEnabled(JSStringRef name)
{
- return WKBundlePageIsEditingCommandEnabled(InjectedBundle::shared().page()->page(), toWK(name).get());
+ return WKBundlePageIsEditingCommandEnabled(InjectedBundle::singleton().page()->page(), toWK(name).get());
}
void TestRunner::setCanOpenWindows(bool)
{
- // It's not clear if or why any tests require opening windows be forbidden.
- // For now, just ignore this setting, and if we find later it's needed we can add it.
+ // The test plugins/get-url-with-blank-target.html requires that the embedding client forbid
+ // opening windows (by omitting a call to this function) so as to test that NPN_GetURL()
+ // with a blank target will return an error.
+ //
+ // It is not clear if we should implement this functionality or remove it and plugins/get-url-with-blank-target.html
+ // per the remark in <https://trac.webkit.org/changeset/64504/trunk/LayoutTests/platform/mac-wk2/Skipped>.
+ // For now, just ignore this setting.
}
void TestRunner::setXSSAuditorEnabled(bool enabled)
{
WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitXSSAuditorEnabled"));
- WKBundleOverrideBoolPreferenceForTestRunner(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), key.get(), enabled);
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
+}
+
+void TestRunner::setShadowDOMEnabled(bool enabled)
+{
+ WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitShadowDOMEnabled"));
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
+}
+
+void TestRunner::setCustomElementsEnabled(bool enabled)
+{
+ WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitCustomElementsEnabled"));
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
+}
+
+void TestRunner::setSubtleCryptoEnabled(bool enabled)
+{
+ WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitSubtleCryptoEnabled"));
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
+}
+
+void TestRunner::setMediaStreamEnabled(bool enabled)
+{
+ WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitMediaStreamEnabled"));
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
+}
+
+void TestRunner::setPeerConnectionEnabled(bool enabled)
+{
+ WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitPeerConnectionEnabled"));
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
+}
+
+void TestRunner::setModernMediaControlsEnabled(bool enabled)
+{
+ WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitModernMediaControlsEnabled"));
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
+}
+
+void TestRunner::setWebGL2Enabled(bool enabled)
+{
+ WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitWebGL2Enabled"));
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
+}
+
+void TestRunner::setFetchAPIEnabled(bool enabled)
+{
+ WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitFetchAPIEnabled"));
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
+}
+
+void TestRunner::setDownloadAttributeEnabled(bool enabled)
+{
+ WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitDownloadAttributeEnabled"));
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
+}
+
+void TestRunner::setEncryptedMediaAPIEnabled(bool enabled)
+{
+ WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitEncryptedMediaAPIEnabled"));
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
+}
+
+void TestRunner::setAllowsAnySSLCertificate(bool enabled)
+{
+ InjectedBundle::singleton().setAllowsAnySSLCertificate(enabled);
}
void TestRunner::setAllowUniversalAccessFromFileURLs(bool enabled)
{
- WKBundleSetAllowUniversalAccessFromFileURLs(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), enabled);
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleSetAllowUniversalAccessFromFileURLs(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
}
void TestRunner::setAllowFileAccessFromFileURLs(bool enabled)
{
- WKBundleSetAllowFileAccessFromFileURLs(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), enabled);
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleSetAllowFileAccessFromFileURLs(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
}
+void TestRunner::setNeedsStorageAccessFromFileURLsQuirk(bool needsQuirk)
+{
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleSetAllowStorageAccessFromFileURLS(injectedBundle.bundle(), injectedBundle.pageGroup(), needsQuirk);
+}
+
void TestRunner::setPluginsEnabled(bool enabled)
{
- WKBundleSetPluginsEnabled(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), enabled);
+ WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitPluginsEnabled"));
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled);
}
void TestRunner::setJavaScriptCanAccessClipboard(bool enabled)
{
- WKBundleSetJavaScriptCanAccessClipboard(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), enabled);
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleSetJavaScriptCanAccessClipboard(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
}
void TestRunner::setPrivateBrowsingEnabled(bool enabled)
{
- WKBundleSetPrivateBrowsingEnabled(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), enabled);
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleSetPrivateBrowsingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
}
+void TestRunner::setUseDashboardCompatibilityMode(bool enabled)
+{
+#if ENABLE(DASHBOARD_SUPPORT)
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleSetUseDashboardCompatibilityMode(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
+#endif
+}
+
void TestRunner::setPopupBlockingEnabled(bool enabled)
{
- WKBundleSetPopupBlockingEnabled(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), enabled);
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleSetPopupBlockingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
}
void TestRunner::setAuthorAndUserStylesEnabled(bool enabled)
{
- WKBundleSetAuthorAndUserStylesEnabled(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), enabled);
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleSetAuthorAndUserStylesEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
}
void TestRunner::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
{
- WKBundleAddOriginAccessWhitelistEntry(InjectedBundle::shared().bundle(), toWK(sourceOrigin).get(), toWK(destinationProtocol).get(), toWK(destinationHost).get(), allowDestinationSubdomains);
+ WKBundleAddOriginAccessWhitelistEntry(InjectedBundle::singleton().bundle(), toWK(sourceOrigin).get(), toWK(destinationProtocol).get(), toWK(destinationHost).get(), allowDestinationSubdomains);
}
void TestRunner::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
{
- WKBundleRemoveOriginAccessWhitelistEntry(InjectedBundle::shared().bundle(), toWK(sourceOrigin).get(), toWK(destinationProtocol).get(), toWK(destinationHost).get(), allowDestinationSubdomains);
+ WKBundleRemoveOriginAccessWhitelistEntry(InjectedBundle::singleton().bundle(), toWK(sourceOrigin).get(), toWK(destinationProtocol).get(), toWK(destinationHost).get(), allowDestinationSubdomains);
}
bool TestRunner::isPageBoxVisible(int pageIndex)
{
- WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
- return WKBundleIsPageBoxVisible(InjectedBundle::shared().bundle(), mainFrame, pageIndex);
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
+ return WKBundleIsPageBoxVisible(injectedBundle.bundle(), mainFrame, pageIndex);
}
void TestRunner::setValueForUser(JSContextRef context, JSValueRef element, JSStringRef value)
@@ -374,21 +506,22 @@ void TestRunner::setValueForUser(JSContextRef context, JSValueRef element, JSStr
void TestRunner::setAudioResult(JSContextRef context, JSValueRef data)
{
+ auto& injectedBundle = InjectedBundle::singleton();
// FIXME (123058): Use a JSC API to get buffer contents once such is exposed.
- WKRetainPtr<WKDataRef> audioData(AdoptWK, WKBundleCreateWKDataFromUInt8Array(InjectedBundle::shared().bundle(), context, data));
- InjectedBundle::shared().setAudioResult(audioData.get());
+ WKRetainPtr<WKDataRef> audioData(AdoptWK, WKBundleCreateWKDataFromUInt8Array(injectedBundle.bundle(), context, data));
+ injectedBundle.setAudioResult(audioData.get());
m_whatToDump = Audio;
m_dumpPixels = false;
}
unsigned TestRunner::windowCount()
{
- return InjectedBundle::shared().pageCount();
+ return InjectedBundle::singleton().pageCount();
}
void TestRunner::clearBackForwardList()
{
- WKBundleBackForwardListClear(WKBundlePageGetBackForwardList(InjectedBundle::shared().page()->page()));
+ WKBundleBackForwardListClear(WKBundlePageGetBackForwardList(InjectedBundle::singleton().page()->page()));
}
// Object Creation
@@ -400,24 +533,18 @@ void TestRunner::makeWindowObject(JSContextRef context, JSObjectRef windowObject
void TestRunner::showWebInspector()
{
-#if ENABLE(INSPECTOR)
- WKBundleInspectorShow(WKBundlePageGetInspector(InjectedBundle::shared().page()->page()));
-#endif // ENABLE(INSPECTOR)
+ WKBundleInspectorShow(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()));
}
void TestRunner::closeWebInspector()
{
-#if ENABLE(INSPECTOR)
- WKBundleInspectorClose(WKBundlePageGetInspector(InjectedBundle::shared().page()->page()));
-#endif // ENABLE(INSPECTOR)
+ WKBundleInspectorClose(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()));
}
-void TestRunner::evaluateInWebInspector(long callID, JSStringRef script)
+void TestRunner::evaluateInWebInspector(JSStringRef script)
{
-#if ENABLE(INSPECTOR)
WKRetainPtr<WKStringRef> scriptWK = toWK(script);
- WKBundleInspectorEvaluateScriptForTest(WKBundlePageGetInspector(InjectedBundle::shared().page()->page()), callID, scriptWK.get());
-#endif // ENABLE(INSPECTOR)
+ WKBundleInspectorEvaluateScriptForTest(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()), scriptWK.get());
}
typedef WTF::HashMap<unsigned, WKRetainPtr<WKBundleScriptWorldRef> > WorldMap;
@@ -454,7 +581,7 @@ void TestRunner::evaluateScriptInIsolatedWorld(JSContextRef context, unsigned wo
WKBundleFrameRef frame = WKBundleFrameForJavaScriptContext(context);
if (!frame)
- frame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ frame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
JSGlobalContextRef jsContext = WKBundleFrameGetJavaScriptContextForWorld(frame, world.get());
JSEvaluateScript(jsContext, script, 0, 0, 0, 0);
@@ -469,35 +596,28 @@ void TestRunner::setPOSIXLocale(JSStringRef locale)
void TestRunner::setTextDirection(JSStringRef direction)
{
- WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
return WKBundleFrameSetTextDirection(mainFrame, toWK(direction).get());
}
void TestRunner::setShouldStayOnPageAfterHandlingBeforeUnload(bool shouldStayOnPage)
{
- InjectedBundle::shared().postNewBeforeUnloadReturnValue(!shouldStayOnPage);
+ InjectedBundle::singleton().postNewBeforeUnloadReturnValue(!shouldStayOnPage);
}
void TestRunner::setDefersLoading(bool shouldDeferLoading)
{
- WKBundlePageSetDefersLoading(InjectedBundle::shared().page()->page(), shouldDeferLoading);
+ WKBundlePageSetDefersLoading(InjectedBundle::singleton().page()->page(), shouldDeferLoading);
}
void TestRunner::setPageVisibility(JSStringRef state)
{
- WKPageVisibilityState visibilityState = kWKPageVisibilityStateVisible;
-
- if (JSStringIsEqualToUTF8CString(state, "hidden"))
- visibilityState = kWKPageVisibilityStateHidden;
- else if (JSStringIsEqualToUTF8CString(state, "prerender"))
- visibilityState = kWKPageVisibilityStatePrerender;
-
- InjectedBundle::shared().setVisibilityState(visibilityState, false);
+ InjectedBundle::singleton().setHidden(JSStringIsEqualToUTF8CString(state, "hidden") || JSStringIsEqualToUTF8CString(state, "prerender"));
}
void TestRunner::resetPageVisibility()
{
- InjectedBundle::shared().setVisibilityState(kWKPageVisibilityStateVisible, true);
+ InjectedBundle::singleton().setHidden(false);
}
typedef WTF::HashMap<unsigned, JSValueRef> CallbackMap;
@@ -511,7 +631,13 @@ enum {
AddChromeInputFieldCallbackID = 1,
RemoveChromeInputFieldCallbackID,
FocusWebViewCallbackID,
- SetBackingScaleFactorCallbackID
+ SetBackingScaleFactorCallbackID,
+ DidBeginSwipeCallbackID,
+ WillEndSwipeCallbackID,
+ DidEndSwipeCallbackID,
+ DidRemoveSwipeSnapshotCallbackID,
+ StatisticsDidModifyDataRecordsCallbackID,
+ FirstUIScriptCallbackID = 100
};
static void cacheTestRunnerCallback(unsigned index, JSValueRef callback)
@@ -519,50 +645,77 @@ static void cacheTestRunnerCallback(unsigned index, JSValueRef callback)
if (!callback)
return;
- WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ if (callbackMap().contains(index)) {
+ InjectedBundle::singleton().outputText(String::format("FAIL: Tried to install a second TestRunner callback for the same event (id %d)\n\n", index));
+ return;
+ }
+
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
JSValueProtect(context, callback);
callbackMap().add(index, callback);
}
-static void callTestRunnerCallback(unsigned index)
+static void callTestRunnerCallback(unsigned index, size_t argumentCount = 0, const JSValueRef arguments[] = nullptr)
{
if (!callbackMap().contains(index))
return;
- WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
JSObjectRef callback = JSValueToObject(context, callbackMap().take(index), 0);
- JSObjectCallAsFunction(context, callback, JSContextGetGlobalObject(context), 0, 0, 0);
+ JSObjectCallAsFunction(context, callback, JSContextGetGlobalObject(context), argumentCount, arguments, 0);
JSValueUnprotect(context, callback);
}
+void TestRunner::clearTestRunnerCallbacks()
+{
+ for (auto& iter : callbackMap()) {
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
+ JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
+ JSObjectRef callback = JSValueToObject(context, iter.value, 0);
+ JSValueUnprotect(context, callback);
+ }
+
+ callbackMap().clear();
+}
+
+void TestRunner::accummulateLogsForChannel(JSStringRef)
+{
+ // FIXME: Implement getting the call to all processes.
+}
+
void TestRunner::addChromeInputField(JSValueRef callback)
{
cacheTestRunnerCallback(AddChromeInputFieldCallbackID, callback);
- InjectedBundle::shared().postAddChromeInputField();
+ InjectedBundle::singleton().postAddChromeInputField();
}
void TestRunner::removeChromeInputField(JSValueRef callback)
{
cacheTestRunnerCallback(RemoveChromeInputFieldCallbackID, callback);
- InjectedBundle::shared().postRemoveChromeInputField();
+ InjectedBundle::singleton().postRemoveChromeInputField();
}
void TestRunner::focusWebView(JSValueRef callback)
{
cacheTestRunnerCallback(FocusWebViewCallbackID, callback);
- InjectedBundle::shared().postFocusWebView();
+ InjectedBundle::singleton().postFocusWebView();
}
void TestRunner::setBackingScaleFactor(double backingScaleFactor, JSValueRef callback)
{
cacheTestRunnerCallback(SetBackingScaleFactorCallbackID, callback);
- InjectedBundle::shared().postSetBackingScaleFactor(backingScaleFactor);
+ InjectedBundle::singleton().postSetBackingScaleFactor(backingScaleFactor);
}
void TestRunner::setWindowIsKey(bool isKey)
{
- InjectedBundle::shared().postSetWindowIsKey(isKey);
+ InjectedBundle::singleton().postSetWindowIsKey(isKey);
+}
+
+void TestRunner::setViewSize(double width, double height)
+{
+ InjectedBundle::singleton().postSetViewSize(width, height);
}
void TestRunner::callAddChromeInputFieldCallback()
@@ -592,13 +745,18 @@ static inline bool toBool(JSStringRef value)
void TestRunner::overridePreference(JSStringRef preference, JSStringRef value)
{
+ auto& injectedBundle = InjectedBundle::singleton();
// FIXME: handle non-boolean preferences.
- WKBundleOverrideBoolPreferenceForTestRunner(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), toWK(preference).get(), toBool(value));
+ WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), toWK(preference).get(), toBool(value));
}
void TestRunner::setAlwaysAcceptCookies(bool accept)
{
- WKBundleSetAlwaysAcceptCookies(InjectedBundle::shared().bundle(), accept);
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAlwaysAcceptCookies"));
+
+ WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(accept));
+
+ WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
}
double TestRunner::preciseTime()
@@ -612,7 +770,8 @@ void TestRunner::setUserStyleSheetEnabled(bool enabled)
WKRetainPtr<WKStringRef> emptyUrl = adoptWK(WKStringCreateWithUTF8CString(""));
WKStringRef location = enabled ? m_userStyleSheetLocation.get() : emptyUrl.get();
- WKBundleSetUserStyleSheetLocation(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), location);
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleSetUserStyleSheetLocation(injectedBundle.bundle(), injectedBundle.pageGroup(), location);
}
void TestRunner::setUserStyleSheetLocation(JSStringRef location)
@@ -625,68 +784,81 @@ void TestRunner::setUserStyleSheetLocation(JSStringRef location)
void TestRunner::setSpatialNavigationEnabled(bool enabled)
{
- WKBundleSetSpatialNavigationEnabled(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), enabled);
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleSetSpatialNavigationEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
}
void TestRunner::setTabKeyCyclesThroughElements(bool enabled)
{
- WKBundleSetTabKeyCyclesThroughElements(InjectedBundle::shared().bundle(), InjectedBundle::shared().page()->page(), enabled);
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleSetTabKeyCyclesThroughElements(injectedBundle.bundle(), injectedBundle.page()->page(), enabled);
}
void TestRunner::setSerializeHTTPLoads()
{
- WKBundleSetSerialLoadingEnabled(InjectedBundle::shared().bundle(), true);
+ // WK2 doesn't reorder loads.
}
void TestRunner::dispatchPendingLoadRequests()
{
- WKBundleDispatchPendingLoadRequests(InjectedBundle::shared().bundle());
+ // WK2 doesn't keep pending requests.
}
void TestRunner::setCacheModel(int model)
{
- WKBundleSetCacheModel(InjectedBundle::shared().bundle(), model);
+ InjectedBundle::singleton().setCacheModel(model);
}
void TestRunner::setAsynchronousSpellCheckingEnabled(bool enabled)
{
- WKBundleSetAsynchronousSpellCheckingEnabled(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), enabled);
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleSetAsynchronousSpellCheckingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled);
}
void TestRunner::grantWebNotificationPermission(JSStringRef origin)
{
WKRetainPtr<WKStringRef> originWK = toWK(origin);
- WKBundleSetWebNotificationPermission(InjectedBundle::shared().bundle(), InjectedBundle::shared().page()->page(), originWK.get(), true);
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleSetWebNotificationPermission(injectedBundle.bundle(), injectedBundle.page()->page(), originWK.get(), true);
}
void TestRunner::denyWebNotificationPermission(JSStringRef origin)
{
WKRetainPtr<WKStringRef> originWK = toWK(origin);
- WKBundleSetWebNotificationPermission(InjectedBundle::shared().bundle(), InjectedBundle::shared().page()->page(), originWK.get(), false);
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleSetWebNotificationPermission(injectedBundle.bundle(), injectedBundle.page()->page(), originWK.get(), false);
}
void TestRunner::removeAllWebNotificationPermissions()
{
- WKBundleRemoveAllWebNotificationPermissions(InjectedBundle::shared().bundle(), InjectedBundle::shared().page()->page());
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleRemoveAllWebNotificationPermissions(injectedBundle.bundle(), injectedBundle.page()->page());
}
void TestRunner::simulateWebNotificationClick(JSValueRef notification)
{
- WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
- uint64_t notificationID = WKBundleGetWebNotificationID(InjectedBundle::shared().bundle(), context, notification);
- InjectedBundle::shared().postSimulateWebNotificationClick(notificationID);
+ uint64_t notificationID = WKBundleGetWebNotificationID(injectedBundle.bundle(), context, notification);
+ injectedBundle.postSimulateWebNotificationClick(notificationID);
}
void TestRunner::setGeolocationPermission(bool enabled)
{
// FIXME: this should be done by frame.
- InjectedBundle::shared().setGeolocationPermission(enabled);
+ InjectedBundle::singleton().setGeolocationPermission(enabled);
+}
+
+bool TestRunner::isGeolocationProviderActive()
+{
+ return InjectedBundle::singleton().isGeolocationProviderActive();
}
void TestRunner::setMockGeolocationPosition(double latitude, double longitude, double accuracy, JSValueRef jsAltitude, JSValueRef jsAltitudeAccuracy, JSValueRef jsHeading, JSValueRef jsSpeed)
{
- WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page());
JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
bool providesAltitude = false;
@@ -717,38 +889,66 @@ void TestRunner::setMockGeolocationPosition(double latitude, double longitude, d
speed = JSValueToNumber(context, jsSpeed, 0);
}
- InjectedBundle::shared().setMockGeolocationPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed);
+ injectedBundle.setMockGeolocationPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed);
}
void TestRunner::setMockGeolocationPositionUnavailableError(JSStringRef message)
{
WKRetainPtr<WKStringRef> messageWK = toWK(message);
- InjectedBundle::shared().setMockGeolocationPositionUnavailableError(messageWK.get());
+ InjectedBundle::singleton().setMockGeolocationPositionUnavailableError(messageWK.get());
+}
+
+void TestRunner::setUserMediaPermission(bool enabled)
+{
+ // FIXME: this should be done by frame.
+ InjectedBundle::singleton().setUserMediaPermission(enabled);
+}
+
+void TestRunner::setUserMediaPersistentPermissionForOrigin(bool permission, JSStringRef origin, JSStringRef parentOrigin)
+{
+ WKRetainPtr<WKStringRef> originWK = toWK(origin);
+ WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin);
+ InjectedBundle::singleton().setUserMediaPersistentPermissionForOrigin(permission, originWK.get(), parentOriginWK.get());
+}
+
+unsigned TestRunner::userMediaPermissionRequestCountForOrigin(JSStringRef origin, JSStringRef parentOrigin) const
+{
+ WKRetainPtr<WKStringRef> originWK = toWK(origin);
+ WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin);
+ return InjectedBundle::singleton().userMediaPermissionRequestCountForOrigin(originWK.get(), parentOriginWK.get());
+}
+
+void TestRunner::resetUserMediaPermissionRequestCountForOrigin(JSStringRef origin, JSStringRef parentOrigin)
+{
+ WKRetainPtr<WKStringRef> originWK = toWK(origin);
+ WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin);
+ InjectedBundle::singleton().resetUserMediaPermissionRequestCountForOrigin(originWK.get(), parentOriginWK.get());
}
bool TestRunner::callShouldCloseOnWebView()
{
- WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
return WKBundleFrameCallShouldCloseOnWebView(mainFrame);
}
void TestRunner::queueBackNavigation(unsigned howFarBackward)
{
- InjectedBundle::shared().queueBackNavigation(howFarBackward);
+ InjectedBundle::singleton().queueBackNavigation(howFarBackward);
}
void TestRunner::queueForwardNavigation(unsigned howFarForward)
{
- InjectedBundle::shared().queueForwardNavigation(howFarForward);
+ InjectedBundle::singleton().queueForwardNavigation(howFarForward);
}
-void TestRunner::queueLoad(JSStringRef url, JSStringRef target)
+void TestRunner::queueLoad(JSStringRef url, JSStringRef target, bool shouldOpenExternalURLs)
{
- WKRetainPtr<WKURLRef> baseURLWK(AdoptWK, WKBundleFrameCopyURL(WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page())));
+ auto& injectedBundle = InjectedBundle::singleton();
+ WKRetainPtr<WKURLRef> baseURLWK(AdoptWK, WKBundleFrameCopyURL(WKBundlePageGetMainFrame(injectedBundle.page()->page())));
WKRetainPtr<WKURLRef> urlWK(AdoptWK, WKURLCreateWithBaseURL(baseURLWK.get(), toWTFString(toWK(url)).utf8().data()));
WKRetainPtr<WKStringRef> urlStringWK(AdoptWK, WKURLCopyString(urlWK.get()));
- InjectedBundle::shared().queueLoad(urlStringWK.get(), toWK(target).get());
+ injectedBundle.queueLoad(urlStringWK.get(), toWK(target).get(), shouldOpenExternalURLs);
}
void TestRunner::queueLoadHTMLString(JSStringRef content, JSStringRef baseURL, JSStringRef unreachableURL)
@@ -757,45 +957,59 @@ void TestRunner::queueLoadHTMLString(JSStringRef content, JSStringRef baseURL, J
WKRetainPtr<WKStringRef> baseURLWK = baseURL ? toWK(baseURL) : WKRetainPtr<WKStringRef>();
WKRetainPtr<WKStringRef> unreachableURLWK = unreachableURL ? toWK(unreachableURL) : WKRetainPtr<WKStringRef>();
- InjectedBundle::shared().queueLoadHTMLString(contentWK.get(), baseURLWK.get(), unreachableURLWK.get());
+ InjectedBundle::singleton().queueLoadHTMLString(contentWK.get(), baseURLWK.get(), unreachableURLWK.get());
}
void TestRunner::queueReload()
{
- InjectedBundle::shared().queueReload();
+ InjectedBundle::singleton().queueReload();
}
void TestRunner::queueLoadingScript(JSStringRef script)
{
WKRetainPtr<WKStringRef> scriptWK = toWK(script);
- InjectedBundle::shared().queueLoadingScript(scriptWK.get());
+ InjectedBundle::singleton().queueLoadingScript(scriptWK.get());
}
void TestRunner::queueNonLoadingScript(JSStringRef script)
{
WKRetainPtr<WKStringRef> scriptWK = toWK(script);
- InjectedBundle::shared().queueNonLoadingScript(scriptWK.get());
+ InjectedBundle::singleton().queueNonLoadingScript(scriptWK.get());
}
+void TestRunner::setRejectsProtectionSpaceAndContinueForAuthenticationChallenges(bool value)
+{
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetRejectsProtectionSpaceAndContinueForAuthenticationChallenges"));
+ WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
+ WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
+}
+
void TestRunner::setHandlesAuthenticationChallenges(bool handlesAuthenticationChallenges)
{
- WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetHandlesAuthenticationChallenge"));
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetHandlesAuthenticationChallenges"));
WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(handlesAuthenticationChallenges));
- WKBundlePostMessage(InjectedBundle::shared().bundle(), messageName.get(), messageBody.get());
+ WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
+}
+
+void TestRunner::setShouldLogCanAuthenticateAgainstProtectionSpace(bool value)
+{
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetShouldLogCanAuthenticateAgainstProtectionSpace"));
+ WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
+ WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
}
void TestRunner::setAuthenticationUsername(JSStringRef username)
{
WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAuthenticationUsername"));
WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(username));
- WKBundlePostMessage(InjectedBundle::shared().bundle(), messageName.get(), messageBody.get());
+ WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
}
void TestRunner::setAuthenticationPassword(JSStringRef password)
{
WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAuthenticationPassword"));
WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(password));
- WKBundlePostMessage(InjectedBundle::shared().bundle(), messageName.get(), messageBody.get());
+ WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
}
bool TestRunner::secureEventInputIsEnabled() const
@@ -803,7 +1017,7 @@ bool TestRunner::secureEventInputIsEnabled() const
WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SecureEventInputIsEnabled"));
WKTypeRef returnData = 0;
- WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), messageName.get(), 0, &returnData);
+ WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), 0, &returnData);
return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
}
@@ -811,21 +1025,386 @@ void TestRunner::setBlockAllPlugins(bool shouldBlock)
{
WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetBlockAllPlugins"));
WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(shouldBlock));
- WKBundlePostMessage(InjectedBundle::shared().bundle(), messageName.get(), messageBody.get());
+ WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
+}
+
+JSValueRef TestRunner::failNextNewCodeBlock()
+{
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
+ JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
+ return JSC::failNextNewCodeBlock(context);
}
JSValueRef TestRunner::numberOfDFGCompiles(JSValueRef theFunction)
{
- WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
return JSC::numberOfDFGCompiles(context, theFunction);
}
JSValueRef TestRunner::neverInlineFunction(JSValueRef theFunction)
{
- WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
return JSC::setNeverInline(context, theFunction);
}
+void TestRunner::setShouldDecideNavigationPolicyAfterDelay(bool value)
+{
+ m_shouldDecideNavigationPolicyAfterDelay = value;
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetShouldDecideNavigationPolicyAfterDelay"));
+ WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
+ WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
+}
+
+void TestRunner::setNavigationGesturesEnabled(bool value)
+{
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetNavigationGesturesEnabled"));
+ WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
+ WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
+}
+
+void TestRunner::setIgnoresViewportScaleLimits(bool value)
+{
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetIgnoresViewportScaleLimits"));
+ WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
+ WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
+}
+
+void TestRunner::setShouldDownloadUndisplayableMIMETypes(bool value)
+{
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetShouldDownloadUndisplayableMIMETypes"));
+ WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
+ WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get());
+}
+
+static unsigned nextUIScriptCallbackID()
+{
+ static unsigned callbackID = FirstUIScriptCallbackID;
+ return callbackID++;
+}
+
+void TestRunner::runUIScript(JSStringRef script, JSValueRef callback)
+{
+ unsigned callbackID = nextUIScriptCallbackID();
+ cacheTestRunnerCallback(callbackID, callback);
+
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("RunUIProcessScript"));
+
+ WKRetainPtr<WKMutableDictionaryRef> testDictionary(AdoptWK, WKMutableDictionaryCreate());
+
+ WKRetainPtr<WKStringRef> scriptKey(AdoptWK, WKStringCreateWithUTF8CString("Script"));
+ WKRetainPtr<WKStringRef> scriptValue(AdoptWK, WKStringCreateWithJSString(script));
+
+ WKRetainPtr<WKStringRef> callbackIDKey(AdoptWK, WKStringCreateWithUTF8CString("CallbackID"));
+ WKRetainPtr<WKUInt64Ref> callbackIDValue = adoptWK(WKUInt64Create(callbackID));
+
+ WKDictionarySetItem(testDictionary.get(), scriptKey.get(), scriptValue.get());
+ WKDictionarySetItem(testDictionary.get(), callbackIDKey.get(), callbackIDValue.get());
+
+ WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), testDictionary.get());
+}
+
+void TestRunner::runUIScriptCallback(unsigned callbackID, JSStringRef result)
+{
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
+ JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
+
+ JSValueRef resultValue = JSValueMakeString(context, result);
+ callTestRunnerCallback(callbackID, 1, &resultValue);
+}
+
+void TestRunner::installDidBeginSwipeCallback(JSValueRef callback)
+{
+ cacheTestRunnerCallback(DidBeginSwipeCallbackID, callback);
+}
+
+void TestRunner::installWillEndSwipeCallback(JSValueRef callback)
+{
+ cacheTestRunnerCallback(WillEndSwipeCallbackID, callback);
+}
+
+void TestRunner::installDidEndSwipeCallback(JSValueRef callback)
+{
+ cacheTestRunnerCallback(DidEndSwipeCallbackID, callback);
+}
+
+void TestRunner::installDidRemoveSwipeSnapshotCallback(JSValueRef callback)
+{
+ cacheTestRunnerCallback(DidRemoveSwipeSnapshotCallbackID, callback);
+}
+
+void TestRunner::callDidBeginSwipeCallback()
+{
+ callTestRunnerCallback(DidBeginSwipeCallbackID);
+}
+
+void TestRunner::callWillEndSwipeCallback()
+{
+ callTestRunnerCallback(WillEndSwipeCallbackID);
+}
+
+void TestRunner::callDidEndSwipeCallback()
+{
+ callTestRunnerCallback(DidEndSwipeCallbackID);
+}
+
+void TestRunner::callDidRemoveSwipeSnapshotCallback()
+{
+ callTestRunnerCallback(DidRemoveSwipeSnapshotCallbackID);
+}
+
+void TestRunner::setStatisticsPrevalentResource(JSStringRef hostName, bool value)
+{
+ Vector<WKRetainPtr<WKStringRef>> keys;
+ Vector<WKRetainPtr<WKTypeRef>> values;
+
+ keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
+ values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
+
+ keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
+ values.append({ AdoptWK, WKBooleanCreate(value) });
+
+ Vector<WKStringRef> rawKeys;
+ Vector<WKTypeRef> rawValues;
+ rawKeys.resize(keys.size());
+ rawValues.resize(values.size());
+
+ for (size_t i = 0; i < keys.size(); ++i) {
+ rawKeys[i] = keys[i].get();
+ rawValues[i] = values[i].get();
+ }
+
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsPrevalentResource"));
+ WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
+
+ WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
+}
+
+bool TestRunner::isStatisticsPrevalentResource(JSStringRef hostName)
+{
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsPrevalentResource"));
+ WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(hostName));
+ WKTypeRef returnData = 0;
+ WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
+ return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
+}
+
+void TestRunner::setStatisticsHasHadUserInteraction(JSStringRef hostName, bool value)
+{
+ Vector<WKRetainPtr<WKStringRef>> keys;
+ Vector<WKRetainPtr<WKTypeRef>> values;
+
+ keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") });
+ values.append({ AdoptWK, WKStringCreateWithJSString(hostName) });
+
+ keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
+ values.append({ AdoptWK, WKBooleanCreate(value) });
+
+ Vector<WKStringRef> rawKeys;
+ Vector<WKTypeRef> rawValues;
+ rawKeys.resize(keys.size());
+ rawValues.resize(values.size());
+
+ for (size_t i = 0; i < keys.size(); ++i) {
+ rawKeys[i] = keys[i].get();
+ rawValues[i] = values[i].get();
+ }
+
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsHasHadUserInteraction"));
+ WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
+
+ WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
+}
+
+bool TestRunner::isStatisticsHasHadUserInteraction(JSStringRef hostName)
+{
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsHasHadUserInteraction"));
+ WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(hostName));
+ WKTypeRef returnData = 0;
+ WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData);
+ return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData));
+}
+
+void TestRunner::setStatisticsTimeToLiveUserInteraction(double seconds)
+{
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsTimeToLiveUserInteraction"));
+ WKRetainPtr<WKDoubleRef> messageBody(AdoptWK, WKDoubleCreate(seconds));
+ WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
+}
+
+void TestRunner::installStatisticsDidModifyDataRecordsCallback(JSValueRef callback)
+{
+ cacheTestRunnerCallback(StatisticsDidModifyDataRecordsCallbackID, callback);
+}
+
+void TestRunner::statisticsDidModifyDataRecordsCallback()
+{
+ callTestRunnerCallback(StatisticsDidModifyDataRecordsCallbackID);
+}
+
+void TestRunner::statisticsFireDataModificationHandler()
+{
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsFireDataModificationHandler"));
+ WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
+}
+
+void TestRunner::setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool value)
+{
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsNotifyPagesWhenDataRecordsWereScanned"));
+ WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
+ WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
+}
+
+void TestRunner::setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(bool value)
+{
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsShouldClassifyResourcesBeforeDataRecordsRemoval"));
+ WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
+ WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
+}
+
+void TestRunner::setStatisticsMinimumTimeBetweeenDataRecordsRemoval(double seconds)
+{
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsMinimumTimeBetweeenDataRecordsRemoval"));
+ WKRetainPtr<WKDoubleRef> messageBody(AdoptWK, WKDoubleCreate(seconds));
+ WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
+}
+
+void TestRunner::statisticsResetToConsistentState()
+{
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsResetToConsistentState"));
+ WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
+}
+
+#if PLATFORM(MAC)
+void TestRunner::connectMockGamepad(unsigned index)
+{
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ConnectMockGamepad"));
+ WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(index));
+
+ WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
+}
+
+void TestRunner::disconnectMockGamepad(unsigned index)
+{
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("DisconnectMockGamepad"));
+ WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(index));
+
+ WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
+}
+
+void TestRunner::setMockGamepadDetails(unsigned index, JSStringRef gamepadID, unsigned axisCount, unsigned buttonCount)
+{
+ Vector<WKRetainPtr<WKStringRef>> keys;
+ Vector<WKRetainPtr<WKTypeRef>> values;
+
+ keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadID") });
+ values.append(toWK(gamepadID));
+
+ keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") });
+ values.append({ AdoptWK, WKUInt64Create(index) });
+
+ keys.append({ AdoptWK, WKStringCreateWithUTF8CString("AxisCount") });
+ values.append({ AdoptWK, WKUInt64Create(axisCount) });
+
+ keys.append({ AdoptWK, WKStringCreateWithUTF8CString("ButtonCount") });
+ values.append({ AdoptWK, WKUInt64Create(buttonCount) });
+
+ Vector<WKStringRef> rawKeys;
+ Vector<WKTypeRef> rawValues;
+ rawKeys.resize(keys.size());
+ rawValues.resize(values.size());
+
+ for (size_t i = 0; i < keys.size(); ++i) {
+ rawKeys[i] = keys[i].get();
+ rawValues[i] = values[i].get();
+ }
+
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadDetails"));
+ WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
+
+ WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
+}
+
+void TestRunner::setMockGamepadAxisValue(unsigned index, unsigned axisIndex, double value)
+{
+ Vector<WKRetainPtr<WKStringRef>> keys;
+ Vector<WKRetainPtr<WKTypeRef>> values;
+
+ keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") });
+ values.append({ AdoptWK, WKUInt64Create(index) });
+
+ keys.append({ AdoptWK, WKStringCreateWithUTF8CString("AxisIndex") });
+ values.append({ AdoptWK, WKUInt64Create(axisIndex) });
+
+ keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
+ values.append({ AdoptWK, WKDoubleCreate(value) });
+
+ Vector<WKStringRef> rawKeys;
+ Vector<WKTypeRef> rawValues;
+ rawKeys.resize(keys.size());
+ rawValues.resize(values.size());
+
+ for (size_t i = 0; i < keys.size(); ++i) {
+ rawKeys[i] = keys[i].get();
+ rawValues[i] = values[i].get();
+ }
+
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadAxisValue"));
+ WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
+
+ WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
+}
+
+void TestRunner::setMockGamepadButtonValue(unsigned index, unsigned buttonIndex, double value)
+{
+ Vector<WKRetainPtr<WKStringRef>> keys;
+ Vector<WKRetainPtr<WKTypeRef>> values;
+
+ keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") });
+ values.append({ AdoptWK, WKUInt64Create(index) });
+
+ keys.append({ AdoptWK, WKStringCreateWithUTF8CString("ButtonIndex") });
+ values.append({ AdoptWK, WKUInt64Create(buttonIndex) });
+
+ keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") });
+ values.append({ AdoptWK, WKDoubleCreate(value) });
+
+ Vector<WKStringRef> rawKeys;
+ Vector<WKTypeRef> rawValues;
+ rawKeys.resize(keys.size());
+ rawValues.resize(values.size());
+
+ for (size_t i = 0; i < keys.size(); ++i) {
+ rawKeys[i] = keys[i].get();
+ rawValues[i] = values[i].get();
+ }
+
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadButtonValue"));
+ WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
+
+ WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
+}
+#else
+void TestRunner::connectMockGamepad(unsigned)
+{
+}
+
+void TestRunner::disconnectMockGamepad(unsigned)
+{
+}
+
+void TestRunner::setMockGamepadDetails(unsigned, JSStringRef, unsigned, unsigned)
+{
+}
+
+void TestRunner::setMockGamepadAxisValue(unsigned, unsigned, double)
+{
+}
+
+void TestRunner::setMockGamepadButtonValue(unsigned, unsigned, double)
+{
+}
+#endif // PLATFORM(MAC)
+
} // namespace WTR
diff --git a/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h b/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h
index cefb6a5d1..764c9e4a9 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h
+++ b/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010, 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2010-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,28 +23,28 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TestRunner_h
-#define TestRunner_h
+#pragma once
#include "JSWrappable.h"
+#include "StringFunctions.h"
#include <JavaScriptCore/JSRetainPtr.h>
-#include <WebKit2/WKBundleScriptWorld.h>
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKBundleScriptWorld.h>
+#include <WebKit/WKRetainPtr.h>
#include <string>
-#include <wtf/PassRefPtr.h>
+#include <wtf/Ref.h>
+#include <wtf/text/WTFString.h>
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
#include <wtf/RetainPtr.h>
#include <CoreFoundation/CFRunLoop.h>
typedef RetainPtr<CFRunLoopTimerRef> PlatformTimerRef;
#elif PLATFORM(GTK)
-typedef unsigned int PlatformTimerRef;
+#include <wtf/RunLoop.h>
+namespace WTR {
+class TestRunner;
+typedef RunLoop::Timer<TestRunner> PlatformTimerRef;
+}
#elif PLATFORM(EFL)
-#if USE(EO)
-typedef struct _Eo_Opaque Ecore_Timer;
-#else
-typedef struct _Ecore_Timer Ecore_Timer;
-#endif
typedef Ecore_Timer* PlatformTimerRef;
#endif
@@ -52,7 +52,7 @@ namespace WTR {
class TestRunner : public JSWrappable {
public:
- static PassRefPtr<TestRunner> create();
+ static Ref<TestRunner> create();
virtual ~TestRunner();
// JSWrappable
@@ -60,13 +60,19 @@ public:
void makeWindowObject(JSContextRef, JSObjectRef windowObject, JSValueRef* exception);
+ bool isWebKit2() const { return true; }
+
// The basics.
+ WKURLRef testURL() const { return m_testURL.get(); }
+ void setTestURL(WKURLRef url) { m_testURL = url; }
void dumpAsText(bool dumpPixels);
void waitForPolicyDelegate();
void dumpChildFramesAsText() { m_whatToDump = AllFramesText; }
+ void waitUntilDownloadFinished();
void waitUntilDone();
void notifyDone();
double preciseTime();
+ double timeout() { return m_timeout; }
// Other dumping.
void dumpBackForwardList() { m_shouldDumpBackForwardListsForAllWindows = true; }
@@ -84,6 +90,7 @@ public:
void dumpApplicationCacheDelegateCallbacks() { m_dumpApplicationCacheDelegateCallbacks = true; }
void dumpDatabaseCallbacks() { m_dumpDatabaseCallbacks = true; }
void dumpDOMAsWebArchive() { m_whatToDump = DOMAsWebArchive; }
+ void dumpPolicyDelegateCallbacks() { m_dumpPolicyCallbacks = true; }
void setShouldDumpFrameLoadCallbacks(bool value) { m_dumpFrameLoadCallbacks = value; }
void setShouldDumpProgressFinishedCallback(bool value) { m_dumpProgressFinishedCallback = value; }
@@ -94,11 +101,18 @@ public:
void setCanOpenWindows(bool);
void setCloseRemainingWindowsWhenComplete(bool value) { m_shouldCloseExtraWindows = value; }
void setXSSAuditorEnabled(bool);
+ void setShadowDOMEnabled(bool);
+ void setCustomElementsEnabled(bool);
+ void setModernMediaControlsEnabled(bool);
+ void setWebGL2Enabled(bool);
+ void setFetchAPIEnabled(bool);
void setAllowUniversalAccessFromFileURLs(bool);
void setAllowFileAccessFromFileURLs(bool);
+ void setNeedsStorageAccessFromFileURLsQuirk(bool);
void setPluginsEnabled(bool);
void setJavaScriptCanAccessClipboard(bool);
void setPrivateBrowsingEnabled(bool);
+ void setUseDashboardCompatibilityMode(bool);
void setPopupBlockingEnabled(bool);
void setAuthorAndUserStylesEnabled(bool);
void setCustomPolicyDelegate(bool enabled, bool permissive = false);
@@ -112,6 +126,12 @@ public:
void dispatchPendingLoadRequests();
void setCacheModel(int);
void setAsynchronousSpellCheckingEnabled(bool);
+ void setDownloadAttributeEnabled(bool);
+ void setAllowsAnySSLCertificate(bool);
+ void setEncryptedMediaAPIEnabled(bool);
+ void setSubtleCryptoEnabled(bool);
+ void setMediaStreamEnabled(bool);
+ void setPeerConnectionEnabled(bool);
// Special DOM functions.
void clearBackForwardList();
@@ -151,7 +171,9 @@ public:
void setPrinting() { m_isPrinting = true; }
// Authentication
+ void setRejectsProtectionSpaceAndContinueForAuthenticationChallenges(bool);
void setHandlesAuthenticationChallenges(bool);
+ void setShouldLogCanAuthenticateAgainstProtectionSpace(bool);
void setAuthenticationUsername(JSStringRef);
void setAuthenticationPassword(JSStringRef);
@@ -181,6 +203,7 @@ public:
bool shouldDumpApplicationCacheDelegateCallbacks() const { return m_dumpApplicationCacheDelegateCallbacks; }
bool shouldDumpDatabaseCallbacks() const { return m_dumpDatabaseCallbacks; }
bool shouldDumpSelectionRect() const { return m_dumpSelectionRect; }
+ bool shouldDumpPolicyCallbacks() const { return m_dumpPolicyCallbacks; }
bool isPolicyDelegateEnabled() const { return m_policyDelegateEnabled; }
bool isPolicyDelegatePermissive() const { return m_policyDelegatePermissive; }
@@ -188,6 +211,7 @@ public:
bool waitToDump() const { return m_waitToDump; }
void waitToDumpWatchdogTimerFired();
void invalidateWaitToDumpWatchdogTimer();
+ bool shouldFinishAfterDownload() const { return m_shouldFinishAfterDownload; }
bool shouldAllowEditing() const { return m_shouldAllowEditing; }
@@ -198,7 +222,8 @@ public:
void showWebInspector();
void closeWebInspector();
- void evaluateInWebInspector(long callId, JSStringRef script);
+ void evaluateInWebInspector(JSStringRef script);
+ JSRetainPtr<JSStringRef> inspectorTestStubURL();
void setPOSIXLocale(JSStringRef);
@@ -206,6 +231,8 @@ public:
void setWillSendRequestReturnsNull(bool f) { m_willSendRequestReturnsNull = f; }
bool willSendRequestReturnsNullOnRedirect() const { return m_willSendRequestReturnsNullOnRedirect; }
void setWillSendRequestReturnsNullOnRedirect(bool f) { m_willSendRequestReturnsNullOnRedirect = f; }
+ void setWillSendRequestAddsHTTPBody(JSStringRef body) { m_willSendRequestHTTPBody = toWTFString(toWK(body)); }
+ String willSendRequestHTTPBody() const { return m_willSendRequestHTTPBody; }
void setTextDirection(JSStringRef);
@@ -232,6 +259,8 @@ public:
void setWindowIsKey(bool);
+ void setViewSize(double width, double height);
+
void callAddChromeInputFieldCallback();
void callRemoveChromeInputFieldCallback();
void callFocusWebViewCallback();
@@ -247,45 +276,98 @@ public:
bool hasCustomFullScreenBehavior() const { return m_customFullScreenBehavior; }
// Web notifications.
- void grantWebNotificationPermission(JSStringRef origin);
- void denyWebNotificationPermission(JSStringRef origin);
- void removeAllWebNotificationPermissions();
- void simulateWebNotificationClick(JSValueRef notification);
+ static void grantWebNotificationPermission(JSStringRef origin);
+ static void denyWebNotificationPermission(JSStringRef origin);
+ static void removeAllWebNotificationPermissions();
+ static void simulateWebNotificationClick(JSValueRef notification);
// Geolocation.
void setGeolocationPermission(bool);
void setMockGeolocationPosition(double latitude, double longitude, double accuracy, JSValueRef altitude, JSValueRef altitudeAccuracy, JSValueRef heading, JSValueRef speed);
void setMockGeolocationPositionUnavailableError(JSStringRef message);
+ bool isGeolocationProviderActive();
+
+ // MediaStream
+ void setUserMediaPermission(bool);
+ void setUserMediaPersistentPermissionForOrigin(bool permission, JSStringRef origin, JSStringRef parentOrigin);
+ unsigned userMediaPermissionRequestCountForOrigin(JSStringRef origin, JSStringRef parentOrigin) const;
+ void resetUserMediaPermissionRequestCountForOrigin(JSStringRef origin, JSStringRef parentOrigin);
void setPageVisibility(JSStringRef state);
void resetPageVisibility();
bool callShouldCloseOnWebView();
- void setCustomTimeout(int duration);
+ void setCustomTimeout(int duration) { m_timeout = duration; }
// Work queue.
void queueBackNavigation(unsigned howFarBackward);
void queueForwardNavigation(unsigned howFarForward);
- void queueLoad(JSStringRef url, JSStringRef target);
+ void queueLoad(JSStringRef url, JSStringRef target, bool shouldOpenExternalURLs);
void queueLoadHTMLString(JSStringRef content, JSStringRef baseURL, JSStringRef unreachableURL);
void queueReload();
void queueLoadingScript(JSStringRef script);
void queueNonLoadingScript(JSStringRef script);
bool secureEventInputIsEnabled() const;
-
+
+ JSValueRef failNextNewCodeBlock();
JSValueRef numberOfDFGCompiles(JSValueRef theFunction);
JSValueRef neverInlineFunction(JSValueRef theFunction);
-private:
- static const double waitToDumpWatchdogTimerInterval;
+ bool shouldDecideNavigationPolicyAfterDelay() const { return m_shouldDecideNavigationPolicyAfterDelay; }
+ void setShouldDecideNavigationPolicyAfterDelay(bool);
+ void setNavigationGesturesEnabled(bool);
+ void setIgnoresViewportScaleLimits(bool);
+ void setShouldDownloadUndisplayableMIMETypes(bool);
+
+ void runUIScript(JSStringRef script, JSValueRef callback);
+ void runUIScriptCallback(unsigned callbackID, JSStringRef result);
+
+ void installDidBeginSwipeCallback(JSValueRef);
+ void installWillEndSwipeCallback(JSValueRef);
+ void installDidEndSwipeCallback(JSValueRef);
+ void installDidRemoveSwipeSnapshotCallback(JSValueRef);
+ void callDidBeginSwipeCallback();
+ void callWillEndSwipeCallback();
+ void callDidEndSwipeCallback();
+ void callDidRemoveSwipeSnapshotCallback();
+
+ void clearTestRunnerCallbacks();
+ void accummulateLogsForChannel(JSStringRef channel);
+
+ unsigned imageCountInGeneralPasteboard() const;
+
+ // Gamepads
+ void connectMockGamepad(unsigned index);
+ void disconnectMockGamepad(unsigned index);
+ void setMockGamepadDetails(unsigned index, JSStringRef gamepadID, unsigned axisCount, unsigned buttonCount);
+ void setMockGamepadAxisValue(unsigned index, unsigned axisIndex, double value);
+ void setMockGamepadButtonValue(unsigned index, unsigned buttonIndex, double value);
+
+ // Resource Load Statistics
+ void installStatisticsDidModifyDataRecordsCallback(JSValueRef callback);
+ void statisticsDidModifyDataRecordsCallback();
+ void statisticsFireDataModificationHandler();
+ void setStatisticsPrevalentResource(JSStringRef hostName, bool value);
+ bool isStatisticsPrevalentResource(JSStringRef hostName);
+ void setStatisticsHasHadUserInteraction(JSStringRef hostName, bool value);
+ bool isStatisticsHasHadUserInteraction(JSStringRef hostName);
+ void setStatisticsTimeToLiveUserInteraction(double seconds);
+ void setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool);
+ void setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(bool);
+ void setStatisticsMinimumTimeBetweeenDataRecordsRemoval(double);
+ void statisticsResetToConsistentState();
+
+private:
TestRunner();
void platformInitialize();
void initializeWaitToDumpWatchdogTimerIfNeeded();
+ WKRetainPtr<WKURLRef> m_testURL; // Set by InjectedBundlePage once provisional load starts.
+
WhatToDump m_whatToDump;
bool m_shouldDumpAllFrameScrollPositions;
bool m_shouldDumpBackForwardListsForAllWindows;
@@ -306,6 +388,7 @@ private:
bool m_dumpWillCacheResponse;
bool m_dumpApplicationCacheDelegateCallbacks;
bool m_dumpDatabaseCallbacks;
+ bool m_dumpPolicyCallbacks { false };
bool m_disallowIncreaseForApplicationCacheQuota;
bool m_waitToDump; // True if waitUntilDone() has been called, but notifyDone() has not yet been called.
bool m_testRepaint;
@@ -315,6 +398,7 @@ private:
bool m_willSendRequestReturnsNull;
bool m_willSendRequestReturnsNullOnRedirect;
bool m_shouldStopProvisionalFrameLoads;
+ String m_willSendRequestHTTPBody;
bool m_policyDelegateEnabled;
bool m_policyDelegatePermissive;
@@ -327,12 +411,17 @@ private:
double m_databaseDefaultQuota;
double m_databaseMaxQuota;
+ bool m_shouldDecideNavigationPolicyAfterDelay { false };
+ bool m_shouldFinishAfterDownload { false };
+
bool m_userStyleSheetEnabled;
WKRetainPtr<WKStringRef> m_userStyleSheetLocation;
+ WKRetainPtr<WKArrayRef> m_allowedHosts;
+
+ size_t m_userMediaPermissionRequestCount { 0 };
+
PlatformTimerRef m_waitToDumpWatchdogTimer;
};
} // namespace WTR
-
-#endif // TestRunner_h
diff --git a/Tools/WebKitTestRunner/InjectedBundle/TextInputController.cpp b/Tools/WebKitTestRunner/InjectedBundle/TextInputController.cpp
index 0087aa301..2e304e28c 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/TextInputController.cpp
+++ b/Tools/WebKitTestRunner/InjectedBundle/TextInputController.cpp
@@ -30,13 +30,13 @@
#include "InjectedBundlePage.h"
#include "JSTextInputController.h"
#include "StringFunctions.h"
-#include <WebKit2/WKBundlePagePrivate.h>
+#include <WebKit/WKBundlePagePrivate.h>
namespace WTR {
-PassRefPtr<TextInputController> TextInputController::create()
+Ref<TextInputController> TextInputController::create()
{
- return adoptRef(new TextInputController);
+ return adoptRef(*new TextInputController);
}
TextInputController::TextInputController()
@@ -59,22 +59,22 @@ void TextInputController::makeWindowObject(JSContextRef context, JSObjectRef win
void TextInputController::setMarkedText(JSStringRef text, int from, int length)
{
- WKBundlePageSetComposition(InjectedBundle::shared().page()->page(), toWK(text).get(), from, length);
+ WKBundlePageSetComposition(InjectedBundle::singleton().page()->page(), toWK(text).get(), from, length);
}
bool TextInputController::hasMarkedText()
{
- return WKBundlePageHasComposition(InjectedBundle::shared().page()->page());
+ return WKBundlePageHasComposition(InjectedBundle::singleton().page()->page());
}
void TextInputController::unmarkText()
{
- WKBundlePageConfirmComposition(InjectedBundle::shared().page()->page());
+ WKBundlePageConfirmComposition(InjectedBundle::singleton().page()->page());
}
void TextInputController::insertText(JSStringRef text)
{
- WKBundlePageConfirmCompositionWithText(InjectedBundle::shared().page()->page(), toWK(text).get());
+ WKBundlePageConfirmCompositionWithText(InjectedBundle::singleton().page()->page(), toWK(text).get());
}
} // namespace WTR
diff --git a/Tools/WebKitTestRunner/InjectedBundle/TextInputController.h b/Tools/WebKitTestRunner/InjectedBundle/TextInputController.h
index 71a043752..ed174816f 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/TextInputController.h
+++ b/Tools/WebKitTestRunner/InjectedBundle/TextInputController.h
@@ -23,17 +23,16 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TextInputController_h
-#define TextInputController_h
+#pragma once
#include "JSWrappable.h"
-#include <wtf/PassRefPtr.h>
+#include <wtf/Ref.h>
namespace WTR {
class TextInputController : public JSWrappable {
public:
- static PassRefPtr<TextInputController> create();
+ static Ref<TextInputController> create();
virtual ~TextInputController();
// JSWrappable
@@ -51,5 +50,3 @@ private:
};
} // namespace WTR
-
-#endif // TextInputController_h
diff --git a/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityControllerAtk.cpp b/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityControllerAtk.cpp
index 3573a2a5c..a1a554a9d 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityControllerAtk.cpp
+++ b/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityControllerAtk.cpp
@@ -33,35 +33,14 @@
#include "InjectedBundle.h"
#include "InjectedBundlePage.h"
-#include <WebKit2/WKBundlePagePrivate.h>
+#include <WebKit/WKBundlePagePrivate.h>
#include <atk/atk.h>
#include <cstdio>
-#include <wtf/gobject/GUniquePtr.h>
+#include <wtf/glib/GUniquePtr.h>
#include <wtf/text/StringBuilder.h>
namespace WTR {
-void AccessibilityController::logAccessibilityEvents()
-{
- // Ensure no callbacks are connected before.
- resetToConsistentState();
-
- // Ensure that accessibility is initialized for the WebView by querying for
- // the root accessible object, which will create the full hierarchy.
- rootElement();
-
- if (!m_globalNotificationHandler)
- m_globalNotificationHandler = AccessibilityNotificationHandler::create();
- m_globalNotificationHandler->logAccessibilityEvents();
-
- // Ensure the Atk interface types are registered, otherwise
- // the AtkDocument signal handlers below won't get registered.
- GObject* dummyAxObject = G_OBJECT(g_object_new(ATK_TYPE_OBJECT, nullptr));
- AtkObject* dummyNoOpAxObject = atk_no_op_object_new(dummyAxObject);
- g_object_unref(G_OBJECT(dummyNoOpAxObject));
- g_object_unref(dummyAxObject);
-}
-
void AccessibilityController::resetToConsistentState()
{
m_globalNotificationHandler = nullptr;
@@ -97,9 +76,9 @@ static AtkObject* childElementById(AtkObject* parent, const char* id)
return nullptr;
}
-PassRefPtr<AccessibilityUIElement> AccessibilityController::accessibleElementById(JSStringRef id)
+RefPtr<AccessibilityUIElement> AccessibilityController::accessibleElementById(JSStringRef id)
{
- AtkObject* root = ATK_OBJECT(WKAccessibilityRootObject(InjectedBundle::shared().page()->page()));
+ AtkObject* root = ATK_OBJECT(WKAccessibilityRootObject(InjectedBundle::singleton().page()->page()));
if (!root)
return nullptr;
@@ -120,17 +99,17 @@ JSRetainPtr<JSStringRef> AccessibilityController::platformName()
return platformName;
}
-PassRefPtr<AccessibilityUIElement> AccessibilityController::rootElement()
+Ref<AccessibilityUIElement> AccessibilityController::rootElement()
{
- WKBundlePageRef page = InjectedBundle::shared().page()->page();
+ WKBundlePageRef page = InjectedBundle::singleton().page()->page();
void* root = WKAccessibilityRootObject(page);
return AccessibilityUIElement::create(static_cast<AtkObject*>(root));
}
-PassRefPtr<AccessibilityUIElement> AccessibilityController::focusedElement()
+Ref<AccessibilityUIElement> AccessibilityController::focusedElement()
{
- WKBundlePageRef page = InjectedBundle::shared().page()->page();
+ WKBundlePageRef page = InjectedBundle::singleton().page()->page();
void* root = WKAccessibilityFocusedObject(page);
return AccessibilityUIElement::create(static_cast<AtkObject*>(root));
diff --git a/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.cpp b/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.cpp
index b6af081c2..bb2280877 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.cpp
+++ b/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.cpp
@@ -25,12 +25,12 @@
#include "InjectedBundle.h"
#include "InjectedBundlePage.h"
#include "JSWrapper.h"
-#include <WebKit2/WKBundleFrame.h>
-#include <WebKit2/WKBundlePage.h>
-#include <WebKit2/WKBundlePagePrivate.h>
+#include <WebKit/WKBundleFrame.h>
+#include <WebKit/WKBundlePage.h>
+#include <WebKit/WKBundlePagePrivate.h>
#include <wtf/HashMap.h>
#include <wtf/Vector.h>
-#include <wtf/gobject/GUniquePtr.h>
+#include <wtf/glib/GUniquePtr.h>
#include <wtf/text/CString.h>
#include <wtf/text/WTFString.h>
@@ -43,29 +43,6 @@ typedef HashMap<AtkObject*, AccessibilityNotificationHandler*> NotificationHandl
WTF::Vector<unsigned> listenerIds;
NotificationHandlersMap notificationHandlers;
AccessibilityNotificationHandler* globalNotificationHandler = nullptr;
-bool loggingAccessibilityEvents = false;
-
-void printAccessibilityEvent(AtkObject* accessible, const char* signalName, const char* signalValue)
-{
- // Do not handle state-change:defunct signals, as the AtkObject
- // associated to them will not be valid at this point already.
- if (!signalName || !g_strcmp0(signalName, "state-change:defunct"))
- return;
-
- if (!accessible || !ATK_IS_OBJECT(accessible))
- return;
-
- const char* objectName = atk_object_get_name(accessible);
- AtkRole objectRole = atk_object_get_role(accessible);
-
- // Try to always provide a name to be logged for the object.
- if (!objectName || *objectName == '\0')
- objectName = "(No name)";
-
- GUniquePtr<char> signalNameAndValue(signalValue ? g_strdup_printf("%s = %s", signalName, signalValue) : g_strdup(signalName));
- GUniquePtr<char> accessibilityEventString(g_strdup_printf("Accessibility object emitted \"%s\" / Name: \"%s\" / Role: %d\n", signalNameAndValue.get(), objectName, objectRole));
- InjectedBundle::shared().outputText(String::fromUTF8(accessibilityEventString.get()));
-}
gboolean axObjectEventListener(GSignalInvocationHint* signalHint, unsigned numParamValues, const GValue* paramValues, gpointer data)
{
@@ -78,7 +55,7 @@ gboolean axObjectEventListener(GSignalInvocationHint* signalHint, unsigned numPa
return true;
#if PLATFORM(GTK) || PLATFORM(EFL)
- WKBundlePageRef page = InjectedBundle::shared().page()->page();
+ WKBundlePageRef page = InjectedBundle::singleton().page()->page();
WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(page);
JSContextRef jsContext = WKBundleFrameGetJavaScriptContext(mainFrame);
#else
@@ -86,47 +63,39 @@ gboolean axObjectEventListener(GSignalInvocationHint* signalHint, unsigned numPa
#endif
GSignalQuery signalQuery;
- GUniquePtr<char> signalName;
- GUniquePtr<char> signalValue;
const char* notificationName = nullptr;
Vector<JSValueRef> extraArgs;
g_signal_query(signalHint->signal_id, &signalQuery);
if (!g_strcmp0(signalQuery.signal_name, "state-change")) {
- signalName.reset(g_strdup_printf("state-change:%s", g_value_get_string(&paramValues[1])));
- signalValue.reset(g_strdup_printf("%d", g_value_get_boolean(&paramValues[2])));
if (!g_strcmp0(g_value_get_string(&paramValues[1]), "checked"))
notificationName = "CheckedStateChanged";
else if (!g_strcmp0(g_value_get_string(&paramValues[1]), "invalid-entry"))
notificationName = "AXInvalidStatusChanged";
} else if (!g_strcmp0(signalQuery.signal_name, "focus-event")) {
- signalName.reset(g_strdup("focus-event"));
- signalValue.reset(g_strdup_printf("%d", g_value_get_boolean(&paramValues[1])));
if (g_value_get_boolean(&paramValues[1]))
notificationName = "AXFocusedUIElementChanged";
+ } else if (!g_strcmp0(signalQuery.signal_name, "selection-changed")) {
+ notificationName = "AXSelectedChildrenChanged";
} else if (!g_strcmp0(signalQuery.signal_name, "children-changed")) {
const gchar* childrenChangedDetail = g_quark_to_string(signalHint->detail);
- signalName.reset(g_strdup_printf("children-changed:%s", childrenChangedDetail));
- signalValue.reset(g_strdup_printf("%d", g_value_get_uint(&paramValues[1])));
notificationName = !g_strcmp0(childrenChangedDetail, "add") ? "AXChildrenAdded" : "AXChildrenRemoved";
+ gpointer child = g_value_get_pointer(&paramValues[2]);
+ if (ATK_IS_OBJECT(child))
+ extraArgs.append(toJS(jsContext, WTF::getPtr(WTR::AccessibilityUIElement::create(ATK_OBJECT(child)))));
} else if (!g_strcmp0(signalQuery.signal_name, "property-change")) {
- signalName.reset(g_strdup_printf("property-change:%s", g_quark_to_string(signalHint->detail)));
if (!g_strcmp0(g_quark_to_string(signalHint->detail), "accessible-value"))
notificationName = "AXValueChanged";
} else if (!g_strcmp0(signalQuery.signal_name, "load-complete"))
notificationName = "AXLoadComplete";
else if (!g_strcmp0(signalQuery.signal_name, "text-caret-moved")) {
notificationName = "AXTextCaretMoved";
- signalName.reset(g_strdup(signalQuery.signal_name));
- signalValue.reset(g_strdup_printf("%d", g_value_get_int(&paramValues[1])));
+ GUniquePtr<char> signalValue(g_strdup_printf("%d", g_value_get_int(&paramValues[1])));
JSRetainPtr<JSStringRef> jsSignalValue(Adopt, JSStringCreateWithUTF8CString(signalValue.get()));
extraArgs.append(JSValueMakeString(jsContext, jsSignalValue.get()));
- } else
- signalName.reset(g_strdup(signalQuery.signal_name));
-
- if (loggingAccessibilityEvents)
- printAccessibilityEvent(accessible, signalName.get(), signalValue.get());
+ } else if (!g_strcmp0(signalQuery.signal_name, "text-insert") || !g_strcmp0(signalQuery.signal_name, "text-remove"))
+ notificationName = "AXTextChanged";
if (!jsContext)
return true;
@@ -174,12 +143,6 @@ AccessibilityNotificationHandler::~AccessibilityNotificationHandler()
disconnectAccessibilityCallbacks();
}
-void AccessibilityNotificationHandler::logAccessibilityEvents()
-{
- connectAccessibilityCallbacks();
- loggingAccessibilityEvents = true;
-}
-
void AccessibilityNotificationHandler::setNotificationFunctionCallback(JSValueRef notificationFunctionCallback)
{
if (!notificationFunctionCallback) {
@@ -191,7 +154,7 @@ void AccessibilityNotificationHandler::setNotificationFunctionCallback(JSValueRe
m_notificationFunctionCallback = notificationFunctionCallback;
#if PLATFORM(GTK) || PLATFORM(EFL)
- WKBundlePageRef page = InjectedBundle::shared().page()->page();
+ WKBundlePageRef page = InjectedBundle::singleton().page()->page();
WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(page);
JSContextRef jsContext = WKBundleFrameGetJavaScriptContext(mainFrame);
#else
@@ -222,7 +185,7 @@ void AccessibilityNotificationHandler::setNotificationFunctionCallback(JSValueRe
void AccessibilityNotificationHandler::removeAccessibilityNotificationHandler()
{
#if PLATFORM(GTK) || PLATFORM(EFL)
- WKBundlePageRef page = InjectedBundle::shared().page()->page();
+ WKBundlePageRef page = InjectedBundle::singleton().page()->page();
WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(page);
JSContextRef jsContext = WKBundleFrameGetJavaScriptContext(mainFrame);
#else
@@ -257,7 +220,10 @@ void AccessibilityNotificationHandler::connectAccessibilityCallbacks()
"ATK:AtkObject:property-change",
"ATK:AtkObject:visible-data-changed",
"ATK:AtkDocument:load-complete",
+ "ATK:AtkSelection:selection-changed",
"ATK:AtkText:text-caret-moved",
+ "ATK:AtkText:text-insert",
+ "ATK:AtkText:text-remove",
0
};
@@ -271,7 +237,7 @@ void AccessibilityNotificationHandler::connectAccessibilityCallbacks()
unsigned id = atk_add_global_event_listener(axObjectEventListener, *signalName);
if (!id) {
String message = String::format("atk_add_global_event_listener failed for signal %s\n", *signalName);
- InjectedBundle::shared().outputText(message);
+ InjectedBundle::singleton().outputText(message);
continue;
}
diff --git a/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.h b/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.h
index 3443bce2c..da5d8ecdd 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.h
+++ b/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.h
@@ -17,32 +17,29 @@
* Boston, MA 02110-1301, USA.
*/
-#ifndef AccessibilityNotificationHandlerAtk_h
-#define AccessibilityNotificationHandlerAtk_h
+#pragma once
#if HAVE(ACCESSIBILITY)
#include <JavaScriptCore/JSObjectRef.h>
#include <atk/atk.h>
#include <atk/atkobject.h>
-#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
-#include <wtf/gobject/GRefPtr.h>
+#include <wtf/glib/GRefPtr.h>
namespace WTR {
class AccessibilityNotificationHandler : public RefCounted<AccessibilityNotificationHandler> {
public:
- static PassRefPtr<AccessibilityNotificationHandler> create()
+ static Ref<AccessibilityNotificationHandler> create()
{
- return adoptRef(new AccessibilityNotificationHandler());
+ return adoptRef(*new AccessibilityNotificationHandler());
}
~AccessibilityNotificationHandler();
void setPlatformElement(GRefPtr<AtkObject> platformElement) { m_platformElement = platformElement; }
GRefPtr<AtkObject> platformElement() const { return m_platformElement; }
void setNotificationFunctionCallback(JSValueRef);
JSValueRef notificationFunctionCallback() const { return m_notificationFunctionCallback; }
- void logAccessibilityEvents();
private:
AccessibilityNotificationHandler();
@@ -57,5 +54,3 @@ private:
} // namespace WTR
#endif // HAVE(ACCESSIBILITY)
-
-#endif // AccessibilityNotificationHandlerAtk_h
diff --git a/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp b/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp
index 440377937..7ecf65a29 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp
+++ b/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp
@@ -35,10 +35,13 @@
#include "NotImplemented.h"
#include <JavaScriptCore/JSStringRef.h>
#include <JavaScriptCore/OpaqueJSString.h>
+#if ATK_CHECK_VERSION(2,11,90)
+#include <WebKit/WKBundleFrame.h>
+#endif
#include <atk/atk.h>
#include <wtf/Assertions.h>
-#include <wtf/gobject/GRefPtr.h>
-#include <wtf/gobject/GUniquePtr.h>
+#include <wtf/glib/GRefPtr.h>
+#include <wtf/glib/GUniquePtr.h>
#include <wtf/text/CString.h>
#include <wtf/text/StringBuilder.h>
#include <wtf/text/WTFString.h>
@@ -48,6 +51,13 @@ namespace WTR {
namespace {
+#if ATK_CHECK_VERSION(2,11,92)
+enum RangeLimit {
+ RangeLimitMinimum,
+ RangeLimitMaximum
+};
+#endif
+
enum AtkAttributeType {
ObjectAttributeType,
TextAttributeType
@@ -61,6 +71,8 @@ enum AttributeDomain {
enum AttributesIndex {
// Attribute names.
InvalidNameIndex = 0,
+ PosInSetIndex,
+ SetSizeIndex,
PlaceholderNameIndex,
SortNameIndex,
@@ -76,6 +88,8 @@ enum AttributesIndex {
const String attributesMap[][2] = {
// Attribute names.
{ "AXInvalid", "invalid" },
+ { "AXARIAPosInSet", "posinset" },
+ { "AXARIASetSize", "setsize" },
{ "AXPlaceholderValue", "placeholder-text" } ,
{ "AXSortDirection", "sort" },
@@ -91,6 +105,7 @@ const char* landmarkStringComplementary = "AXLandmarkComplementary";
const char* landmarkStringContentinfo = "AXLandmarkContentInfo";
const char* landmarkStringMain = "AXLandmarkMain";
const char* landmarkStringNavigation = "AXLandmarkNavigation";
+const char* landmarkStringRegion = "AXLandmarkRegion";
const char* landmarkStringSearch = "AXLandmarkSearch";
#endif
@@ -172,9 +187,8 @@ String getAttributeSetValueForId(AtkObject* accessible, AtkAttributeType type, S
return atkAttributeValueToCoreAttributeValue(type, id, attributeValue);
}
-String getAtkAttributeSetAsString(AtkObject* accessible, AtkAttributeType type)
+String attributeSetToString(AtkAttributeSet* attributeSet, String separator=", ")
{
- AtkAttributeSet* attributeSet = getAttributeSet(accessible, type);
if (!attributeSet)
return String();
@@ -184,13 +198,18 @@ String getAtkAttributeSetAsString(AtkObject* accessible, AtkAttributeType type)
GUniquePtr<gchar> attributeData(g_strconcat(attribute->name, ":", attribute->value, NULL));
builder.append(attributeData.get());
if (attributes->next)
- builder.append(", ");
+ builder.append(separator);
}
atk_attribute_set_free(attributeSet);
return builder.toString();
}
+String getAtkAttributeSetAsString(AtkObject* accessible, AtkAttributeType type, String separator=", ")
+{
+ return attributeSetToString(getAttributeSet(accessible, type), separator);
+}
+
bool checkElementState(PlatformUIElement element, AtkStateType stateType)
{
if (!ATK_IS_OBJECT(element.get()))
@@ -203,7 +222,10 @@ bool checkElementState(PlatformUIElement element, AtkStateType stateType)
JSStringRef indexRangeInTable(PlatformUIElement element, bool isRowRange)
{
GUniquePtr<gchar> rangeString(g_strdup("{0, 0}"));
-
+#if ATK_CHECK_VERSION(2,11,90)
+ if (!ATK_IS_TABLE_CELL(element.get()))
+ return JSStringCreateWithUTF8CString(rangeString.get());
+#else
if (!ATK_IS_OBJECT(element.get()))
return JSStringCreateWithUTF8CString(rangeString.get());
@@ -215,11 +237,20 @@ JSStringRef indexRangeInTable(PlatformUIElement element, bool isRowRange)
gint indexInParent = atk_object_get_index_in_parent(ATK_OBJECT(element.get()));
if (indexInParent == -1)
return JSStringCreateWithUTF8CString(rangeString.get());
+#endif
- int row = -1;
- int column = -1;
+ gint row = -1;
+ gint column = -1;
+ gint rowSpan = -1;
+ gint columnSpan = -1;
+#if ATK_CHECK_VERSION(2,11,90)
+ atk_table_cell_get_row_column_span(ATK_TABLE_CELL(element.get()), &row, &column, &rowSpan, &columnSpan);
+#else
row = atk_table_get_row_at_index(ATK_TABLE(axTable), indexInParent);
column = atk_table_get_column_at_index(ATK_TABLE(axTable), indexInParent);
+ rowSpan = atk_table_get_row_extent_at(ATK_TABLE(axTable), row, column);
+ columnSpan = atk_table_get_column_extent_at(ATK_TABLE(axTable), row, column);
+#endif
// Get the actual values, if row and columns are valid values.
if (row != -1 && column != -1) {
@@ -227,10 +258,10 @@ JSStringRef indexRangeInTable(PlatformUIElement element, bool isRowRange)
int length = 0;
if (isRowRange) {
base = row;
- length = atk_table_get_row_extent_at(ATK_TABLE(axTable), row, column);
+ length = rowSpan;
} else {
base = column;
- length = atk_table_get_column_extent_at(ATK_TABLE(axTable), row, column);
+ length = columnSpan;
}
rangeString.reset(g_strdup_printf("{%d, %d}", base, length));
}
@@ -243,6 +274,13 @@ void alterCurrentValue(PlatformUIElement element, int factor)
if (!ATK_IS_VALUE(element.get()))
return;
+#if ATK_CHECK_VERSION(2,11,92)
+ double currentValue;
+ atk_value_get_value_and_text(ATK_VALUE(element.get()), &currentValue, nullptr);
+
+ double increment = atk_value_get_increment(ATK_VALUE(element.get()));
+ atk_value_set_value(ATK_VALUE(element.get()), currentValue + factor * increment);
+#else
GValue currentValue = G_VALUE_INIT;
atk_value_get_current_value(ATK_VALUE(element.get()), &currentValue);
@@ -258,6 +296,7 @@ void alterCurrentValue(PlatformUIElement element, int factor)
g_value_unset(&newValue);
g_value_unset(&increment);
g_value_unset(&currentValue);
+#endif
}
gchar* replaceCharactersForResults(gchar* str)
@@ -283,17 +322,19 @@ const gchar* roleToString(AtkObject* object)
#if ATK_CHECK_VERSION(2, 11, 3)
if (role == ATK_ROLE_LANDMARK) {
String xmlRolesValue = getAttributeSetValueForId(object, ObjectAttributeType, "xml-roles");
- if (equalIgnoringCase(xmlRolesValue, "banner"))
+ if (equalLettersIgnoringASCIICase(xmlRolesValue, "banner"))
return landmarkStringBanner;
- if (equalIgnoringCase(xmlRolesValue, "complementary"))
+ if (equalLettersIgnoringASCIICase(xmlRolesValue, "complementary"))
return landmarkStringComplementary;
- if (equalIgnoringCase(xmlRolesValue, "contentinfo"))
+ if (equalLettersIgnoringASCIICase(xmlRolesValue, "contentinfo"))
return landmarkStringContentinfo;
- if (equalIgnoringCase(xmlRolesValue, "main"))
+ if (equalLettersIgnoringASCIICase(xmlRolesValue, "main"))
return landmarkStringMain;
- if (equalIgnoringCase(xmlRolesValue, "navigation"))
+ if (equalLettersIgnoringASCIICase(xmlRolesValue, "navigation"))
return landmarkStringNavigation;
- if (equalIgnoringCase(xmlRolesValue, "search"))
+ if (equalLettersIgnoringASCIICase(xmlRolesValue, "region"))
+ return landmarkStringRegion;
+ if (equalLettersIgnoringASCIICase(xmlRolesValue, "search"))
return landmarkStringSearch;
}
#endif
@@ -305,6 +346,8 @@ const gchar* roleToString(AtkObject* object)
return "AXDialog";
case ATK_ROLE_CANVAS:
return "AXCanvas";
+ case ATK_ROLE_CAPTION:
+ return "AXCaption";
case ATK_ROLE_CHECK_BOX:
return "AXCheckBox";
case ATK_ROLE_COLOR_CHOOSER:
@@ -339,6 +382,8 @@ const gchar* roleToString(AtkObject* object)
return "AXInvalid";
case ATK_ROLE_LABEL:
return "AXLabel";
+ case ATK_ROLE_LEVEL_BAR:
+ return "AXProgressIndicator";
case ATK_ROLE_LINK:
return "AXLink";
case ATK_ROLE_LIST:
@@ -420,6 +465,10 @@ const gchar* roleToString(AtkObject* object)
#if ATK_CHECK_VERSION(2, 11, 3)
case ATK_ROLE_ARTICLE:
return "AXArticle";
+ case ATK_ROLE_AUDIO:
+ return "AXAudio";
+ case ATK_ROLE_BLOCK_QUOTE:
+ return "AXBlockquote";
case ATK_ROLE_DEFINITION:
return "AXDefinition";
case ATK_ROLE_LOG:
@@ -430,6 +479,8 @@ const gchar* roleToString(AtkObject* object)
return "AXMath";
case ATK_ROLE_TIMER:
return "AXTimer";
+ case ATK_ROLE_VIDEO:
+ return "AXVideo";
#endif
#if ATK_CHECK_VERSION(2, 11, 4)
case ATK_ROLE_DESCRIPTION_LIST:
@@ -439,6 +490,20 @@ const gchar* roleToString(AtkObject* object)
case ATK_ROLE_DESCRIPTION_VALUE:
return "AXDescriptionValue";
#endif
+#if ATK_CHECK_VERSION(2, 15, 2)
+ case ATK_ROLE_STATIC:
+ return "AXStatic";
+#endif
+#if ATK_CHECK_VERSION(2, 15, 4)
+ case ATK_ROLE_MATH_FRACTION:
+ return "AXMathFraction";
+ case ATK_ROLE_MATH_ROOT:
+ return "AXMathRoot";
+ case ATK_ROLE_SUBSCRIPT:
+ return "AXSubscript";
+ case ATK_ROLE_SUPERSCRIPT:
+ return "AXSuperscript";
+#endif
default:
// We want to distinguish ATK_ROLE_UNKNOWN from a known AtkRole which
// our DRT isn't properly handling.
@@ -446,6 +511,19 @@ const gchar* roleToString(AtkObject* object)
}
}
+String selectedText(AtkObject* accessible)
+{
+ if (!ATK_IS_TEXT(accessible))
+ return String();
+
+ AtkText* text = ATK_TEXT(accessible);
+
+ gint start, end;
+ g_free(atk_text_get_selection(text, 0, &start, &end));
+
+ return atk_text_get_text(text, start, end);
+}
+
String attributesOfElement(AccessibilityUIElement* element)
{
StringBuilder builder;
@@ -552,6 +630,53 @@ static Vector<RefPtr<AccessibilityUIElement> > getVisibleCells(AccessibilityUIEl
return visibleCells;
}
+#if ATK_CHECK_VERSION(2,11,90)
+static Vector<RefPtr<AccessibilityUIElement>> convertGPtrArrayToVector(const GPtrArray* array)
+{
+ Vector<RefPtr<AccessibilityUIElement>> cells;
+ for (guint i = 0; i < array->len; i++) {
+ if (AtkObject* atkObject = static_cast<AtkObject*>(g_ptr_array_index(array, i)))
+ cells.append(AccessibilityUIElement::create(atkObject));
+ }
+ return cells;
+}
+
+static JSValueRef convertToJSObjectArray(const Vector<RefPtr<AccessibilityUIElement>>& children)
+{
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
+ JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
+
+ size_t elementCount = children.size();
+ auto valueElements = std::make_unique<JSValueRef[]>(elementCount);
+ for (size_t i = 0; i < elementCount; i++)
+ valueElements[i] = JSObjectMake(context, children[i]->wrapperClass(), children[i].get());
+
+ return JSObjectMakeArray(context, elementCount, valueElements.get(), nullptr);
+}
+#endif
+
+#if ATK_CHECK_VERSION(2,11,92)
+static double rangeMinMaxValue(AtkValue* atkValue, RangeLimit rangeLimit)
+{
+ AtkRange* range = atk_value_get_range(atkValue);
+ if (!range)
+ return 0;
+
+ double rangeValue = 0;
+ switch (rangeLimit) {
+ case RangeLimitMinimum:
+ rangeValue = atk_range_get_lower_limit(range);
+ break;
+ case RangeLimitMaximum:
+ rangeValue = atk_range_get_upper_limit(range);
+ break;
+ };
+
+ atk_range_free(range);
+ return rangeValue;
+}
+#endif
+
} // namespace
AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element)
@@ -605,7 +730,7 @@ int AccessibilityUIElement::childrenCount()
return atk_object_get_n_accessible_children(ATK_OBJECT(m_element.get()));
}
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::elementAtPoint(int x, int y)
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::elementAtPoint(int x, int y)
{
if (!ATK_IS_COMPONENT(m_element.get()))
return nullptr;
@@ -630,7 +755,7 @@ unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element)
return 0;
}
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::childAtIndex(unsigned index)
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::childAtIndex(unsigned index)
{
if (!ATK_IS_OBJECT(m_element.get()))
return nullptr;
@@ -644,28 +769,16 @@ PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::childAtIndex(unsigned
return nullptr;
}
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::linkedUIElementAtIndex(unsigned index)
-{
- // FIXME: implement
- return nullptr;
-}
-
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index)
+static RefPtr<AccessibilityUIElement> accessibilityElementAtIndex(AtkObject* element, AtkRelationType relationType, unsigned index)
{
- // FIXME: implement
- return nullptr;
-}
-
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index)
-{
- if (!ATK_IS_OBJECT(m_element.get()))
+ if (!ATK_IS_OBJECT(element))
return nullptr;
- AtkRelationSet* relationSet = atk_object_ref_relation_set(ATK_OBJECT(m_element.get()));
+ AtkRelationSet* relationSet = atk_object_ref_relation_set(element);
if (!relationSet)
return nullptr;
- AtkRelation* relation = atk_relation_set_get_relation_by_type(relationSet, ATK_RELATION_FLOWS_TO);
+ AtkRelation* relation = atk_relation_set_get_relation_by_type(relationSet, relationType);
if (!relation)
return nullptr;
@@ -673,43 +786,80 @@ PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaFlowToElementAtIn
if (!targetList || !targetList->len || index >= targetList->len)
return nullptr;
+ AtkObject* target = static_cast<AtkObject*>(g_ptr_array_index(targetList, index));
g_object_unref(relationSet);
- AtkObject* target = static_cast<AtkObject*>(g_ptr_array_index(targetList, index));
- return target ? AccessibilityUIElement::create(target) : nullptr;
+ return target ? AccessibilityUIElement::create(target).ptr() : nullptr;
}
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedRowAtIndex(unsigned index)
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::linkedUIElementAtIndex(unsigned index)
{
// FIXME: implement
return nullptr;
}
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::rowAtIndex(unsigned index)
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index)
{
// FIXME: implement
return nullptr;
}
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedChildAtIndex(unsigned index) const
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index)
+{
+ return accessibilityElementAtIndex(m_element.get(), ATK_RELATION_FLOWS_TO, index);
+}
+
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaControlsElementAtIndex(unsigned index)
+{
+ return accessibilityElementAtIndex(m_element.get(), ATK_RELATION_CONTROLLER_FOR, index);
+}
+
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedRowAtIndex(unsigned index)
{
// FIXME: implement
return nullptr;
}
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::rowAtIndex(unsigned index)
+{
+ // ATK doesn't have API to get an accessible row by index directly. It does, however, have
+ // API to get cells in the row specified by index. The parent of a cell should be the row.
+ AtkTable* axTable = ATK_TABLE(m_element.get());
+ unsigned nColumns = columnCount();
+ for (unsigned col = 0; col < nColumns; col++) {
+ // Find the first cell in this row that only spans one row.
+ if (atk_table_get_row_extent_at(axTable, index, col) == 1) {
+ AtkObject* cell = atk_table_ref_at(axTable, index, col);
+ return cell ? AccessibilityUIElement::create(atk_object_get_parent(cell)).ptr() : nullptr;
+ }
+ }
+
+ return nullptr;
+}
+
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedChildAtIndex(unsigned index) const
+{
+ if (!ATK_SELECTION(m_element.get()))
+ return nullptr;
+
+ GRefPtr<AtkObject> child = adoptGRef(atk_selection_ref_selection(ATK_SELECTION(m_element.get()), index));
+ return child ? AccessibilityUIElement::create(child.get()).ptr() : nullptr;
+}
+
unsigned AccessibilityUIElement::selectedChildrenCount() const
{
- // FIXME: implement
- return 0;
+ if (!ATK_IS_SELECTION(m_element.get()))
+ return 0;
+ return atk_selection_get_selection_count(ATK_SELECTION(m_element.get()));
}
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedRowAtIndex(unsigned index)
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedRowAtIndex(unsigned index)
{
// FIXME: implement
return nullptr;
}
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::titleUIElement()
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::titleUIElement()
{
if (!ATK_IS_OBJECT(m_element.get()))
return nullptr;
@@ -730,19 +880,19 @@ PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::titleUIElement()
}
g_object_unref(set);
- return target ? AccessibilityUIElement::create(target) : nullptr;
+ return target ? AccessibilityUIElement::create(target).ptr() : nullptr;
}
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::parentElement()
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::parentElement()
{
if (!ATK_IS_OBJECT(m_element.get()))
return nullptr;
AtkObject* parent = atk_object_get_parent(ATK_OBJECT(m_element.get()));
- return parent ? AccessibilityUIElement::create(parent) : nullptr;
+ return parent ? AccessibilityUIElement::create(parent).ptr() : nullptr;
}
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedByRow()
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedByRow()
{
// FIXME: implement
return nullptr;
@@ -786,7 +936,13 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::stringAttributeValue(JSStringRe
String atkAttributeName = coreAttributeToAtkAttribute(attribute);
- // Try object attributes first.
+ // The value of AXSelectedText is not exposed through any AtkAttribute.
+ if (atkAttributeName == "AXSelectedText") {
+ String string = selectedText(m_element.get());
+ return JSStringCreateWithUTF8CString(string.utf8().data());
+ }
+
+ // Try object attributes before text attributes.
String attributeValue = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, atkAttributeName);
// Try text attributes if the requested one was not found and we have an AtkText object.
@@ -812,7 +968,19 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::stringAttributeValue(JSStringRe
double AccessibilityUIElement::numberAttributeValue(JSStringRef attribute)
{
- // FIXME: implement
+ if (!ATK_IS_OBJECT(m_element.get()))
+ return 0;
+
+ String atkAttributeName = coreAttributeToAtkAttribute(attribute);
+ if (atkAttributeName.isEmpty())
+ return 0;
+
+ if (atkAttributeName == "setsize" || atkAttributeName == "posinset") {
+ String attributeValue = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, atkAttributeName);
+ if (!attributeValue.isEmpty())
+ return attributeValue.toDouble();
+ }
+
return 0;
}
@@ -824,25 +992,87 @@ JSValueRef AccessibilityUIElement::uiElementArrayAttributeValue(JSStringRef attr
JSValueRef AccessibilityUIElement::rowHeaders() const
{
- // FIXME: implement
+#if ATK_CHECK_VERSION(2,11,90)
+ if (!ATK_IS_TABLE_CELL(m_element.get()))
+ return nullptr;
+
+ GRefPtr<GPtrArray> array = adoptGRef(atk_table_cell_get_row_header_cells(ATK_TABLE_CELL(m_element.get())));
+ if (!array)
+ return nullptr;
+
+ Vector<RefPtr<AccessibilityUIElement>> rows = convertGPtrArrayToVector(array.get());
+ return convertToJSObjectArray(rows);
+#else
return nullptr;
+#endif
}
JSValueRef AccessibilityUIElement::columnHeaders() const
{
- // FIXME: implement
+#if ATK_CHECK_VERSION(2,11,90)
+ if (!ATK_IS_TABLE_CELL(m_element.get()) && !ATK_IS_TABLE(m_element.get()))
+ return nullptr;
+
+ Vector<RefPtr<AccessibilityUIElement>> columns;
+ if (ATK_IS_TABLE_CELL(m_element.get())) {
+ GRefPtr<GPtrArray> array = adoptGRef(atk_table_cell_get_column_header_cells(ATK_TABLE_CELL(m_element.get())));
+ if (!array)
+ return nullptr;
+
+ columns = convertGPtrArrayToVector(array.get());
+ } else
+ columns = getColumnHeaders(ATK_TABLE(m_element.get()));
+ return convertToJSObjectArray(columns);
+#else
return nullptr;
+#endif
}
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementAttributeValue(JSStringRef attribute) const
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementAttributeValue(JSStringRef attribute) const
{
- // FIXME: implement
+ if (!ATK_IS_OBJECT(m_element.get()))
+ return nullptr;
+
+ // ATK does not have this API. So we're "faking it" here on a case-by-case basis.
+ String attributeString = jsStringToWTFString(attribute);
+ AtkRole role = atk_object_get_role(ATK_OBJECT(m_element.get()));
+ if (role == ATK_ROLE_SPIN_BUTTON && const_cast<AccessibilityUIElement*>(this)->childrenCount() == 2) {
+ if (attributeString == "AXDecrementButton")
+ return const_cast<AccessibilityUIElement*>(this)->childAtIndex(0);
+ if (attributeString == "AXIncrementButton")
+ return const_cast<AccessibilityUIElement*>(this)->childAtIndex(1);
+ }
+
return nullptr;
}
bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute)
{
- // FIXME: implement
+ if (!ATK_IS_OBJECT(m_element.get()))
+ return false;
+
+ String attributeString = jsStringToWTFString(attribute);
+ if (attributeString == "AXElementBusy")
+ return checkElementState(m_element.get(), ATK_STATE_BUSY);
+ if (attributeString == "AXChecked")
+ return checkElementState(m_element.get(), ATK_STATE_CHECKED);
+ if (attributeString == "AXEnabled")
+ return checkElementState(m_element.get(), ATK_STATE_ENABLED);
+ if (attributeString == "AXExpanded")
+ return checkElementState(m_element.get(), ATK_STATE_EXPANDED);
+ if (attributeString == "AXFocused")
+ return checkElementState(m_element.get(), ATK_STATE_FOCUSED);
+ if (attributeString == "AXInvalid")
+ return checkElementState(m_element.get(), ATK_STATE_INVALID);
+ if (attributeString == "AXMultiSelectable")
+ return checkElementState(m_element.get(), ATK_STATE_MULTISELECTABLE);
+ if (attributeString == "AXRequired")
+ return checkElementState(m_element.get(), ATK_STATE_REQUIRED);
+ if (attributeString == "AXSelected")
+ return checkElementState(m_element.get(), ATK_STATE_SELECTED);
+ if (attributeString == "AXVisited")
+ return checkElementState(m_element.get(), ATK_STATE_VISITED);
+
return false;
}
@@ -852,8 +1082,51 @@ bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute)
return false;
String attributeString = jsStringToWTFString(attribute);
- if (attributeString == "AXValue")
- return checkElementState(m_element.get(), ATK_STATE_EDITABLE);
+ if (attributeString != "AXValue")
+ return false;
+
+ // ATK does not have a single state or property to indicate whether or not the value
+ // of an accessible object can be set. ATs look at several states and properties based
+ // on the type of object. If nothing explicitly indicates the value can or cannot be
+ // set, ATs make role- and interface-based decisions. We'll do something similar here.
+
+ // This state is expected to be present only for text widgets and contenteditable elements.
+ if (checkElementState(m_element.get(), ATK_STATE_EDITABLE))
+ return true;
+
+#if ATK_CHECK_VERSION(2,11,2)
+ // This state is applicable to checkboxes, radiobuttons, switches, etc.
+ if (checkElementState(m_element.get(), ATK_STATE_CHECKABLE))
+ return true;
+#endif
+
+#if ATK_CHECK_VERSION(2,15,3)
+ // This state is expected to be present only for controls and only if explicitly set.
+ if (checkElementState(m_element.get(), ATK_STATE_READ_ONLY))
+ return false;
+#endif
+
+ // We expose an object attribute to ATs when there is an author-provided ARIA property
+ // and also when there is a supported ARIA role but no author-provided value.
+ String isReadOnly = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, "readonly");
+ if (!isReadOnly.isEmpty())
+ return isReadOnly == "true" ? false : true;
+
+ // If we have a native listbox or combobox and the value can be set, the options should
+ // have ATK_STATE_SELECTABLE.
+ AtkRole role = atk_object_get_role(ATK_OBJECT(m_element.get()));
+ if (role == ATK_ROLE_LIST_BOX || role == ATK_ROLE_COMBO_BOX) {
+ if (GRefPtr<AtkObject> child = adoptGRef(atk_object_ref_accessible_child(ATK_OBJECT(m_element.get()), 0))) {
+ if (atk_object_get_role(ATK_OBJECT(child.get())) == ATK_ROLE_MENU)
+ child = adoptGRef(atk_object_ref_accessible_child(ATK_OBJECT(child.get()), 0));
+ return child && checkElementState(child.get(), ATK_STATE_SELECTABLE);
+ }
+ }
+
+ // If we have a native element which exposes a range whose value can be set, it should
+ // be focusable and have a true range.
+ if (ATK_IS_VALUE(m_element.get()) && checkElementState(m_element.get(), ATK_STATE_FOCUSABLE))
+ return minValue() != maxValue();
return false;
}
@@ -898,7 +1171,18 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::subrole()
JSRetainPtr<JSStringRef> AccessibilityUIElement::roleDescription()
{
- // FIXME: implement
+ String roleDescription = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, "roledescription");
+ GUniquePtr<gchar> axRoleDescription(g_strdup_printf("AXRoleDescription: %s", roleDescription.utf8().data()));
+
+ return JSStringCreateWithUTF8CString(axRoleDescription.get());
+}
+
+JSRetainPtr<JSStringRef> AccessibilityUIElement::computedRoleString()
+{
+ String role = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, "computed-role");
+ if (!role.isEmpty())
+ return JSStringCreateWithUTF8CString(role.utf8().data());
+
return JSStringCreateWithCharacters(0, 0);
}
@@ -976,15 +1260,15 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::helpText() const
AtkRelationSet* relationSet = atk_object_ref_relation_set(ATK_OBJECT(m_element.get()));
if (!relationSet)
- return nullptr;
+ return JSStringCreateWithCharacters(0, 0);
AtkRelation* relation = atk_relation_set_get_relation_by_type(relationSet, ATK_RELATION_DESCRIBED_BY);
if (!relation)
- return nullptr;
+ return JSStringCreateWithCharacters(0, 0);
GPtrArray* targetList = atk_relation_get_target(relation);
if (!targetList || !targetList->len)
- return nullptr;
+ return JSStringCreateWithCharacters(0, 0);
StringBuilder builder;
builder.append("AXHelp: ");
@@ -1008,8 +1292,12 @@ double AccessibilityUIElement::x()
if (!ATK_IS_COMPONENT(m_element.get()))
return 0;
- int x, y;
- atk_component_get_position(ATK_COMPONENT(m_element.get()), &x, &y, ATK_XY_SCREEN);
+ int x;
+#if ATK_CHECK_VERSION(2,11,90)
+ atk_component_get_extents(ATK_COMPONENT(m_element.get()), &x, nullptr, nullptr, nullptr, ATK_XY_SCREEN);
+#else
+ atk_component_get_position(ATK_COMPONENT(m_element.get()), &x, nullptr, ATK_XY_SCREEN);
+#endif
return x;
}
@@ -1018,8 +1306,12 @@ double AccessibilityUIElement::y()
if (!ATK_IS_COMPONENT(m_element.get()))
return 0;
- int x, y;
- atk_component_get_position(ATK_COMPONENT(m_element.get()), &x, &y, ATK_XY_SCREEN);
+ int y;
+#if ATK_CHECK_VERSION(2,11,90)
+ atk_component_get_extents(ATK_COMPONENT(m_element.get()), nullptr, &y, nullptr, nullptr, ATK_XY_SCREEN);
+#else
+ atk_component_get_position(ATK_COMPONENT(m_element.get()), nullptr, &y, ATK_XY_SCREEN);
+#endif
return y;
}
@@ -1028,8 +1320,12 @@ double AccessibilityUIElement::width()
if (!ATK_IS_COMPONENT(m_element.get()))
return 0;
- int width, height;
- atk_component_get_size(ATK_COMPONENT(m_element.get()), &width, &height);
+ int width;
+#if ATK_CHECK_VERSION(2,11,90)
+ atk_component_get_extents(ATK_COMPONENT(m_element.get()), nullptr, nullptr, &width, nullptr, ATK_XY_WINDOW);
+#else
+ atk_component_get_size(ATK_COMPONENT(m_element.get()), &width, nullptr);
+#endif
return width;
}
@@ -1038,8 +1334,12 @@ double AccessibilityUIElement::height()
if (!ATK_IS_COMPONENT(m_element.get()))
return 0;
- int width, height;
- atk_component_get_size(ATK_COMPONENT(m_element.get()), &width, &height);
+ int height;
+#if ATK_CHECK_VERSION(2,11,90)
+ atk_component_get_extents(ATK_COMPONENT(m_element.get()), nullptr, nullptr, nullptr, &height, ATK_XY_WINDOW);
+#else
+ atk_component_get_size(ATK_COMPONENT(m_element.get()), nullptr, &height);
+#endif
return height;
}
@@ -1048,11 +1348,13 @@ double AccessibilityUIElement::clickPointX()
if (!ATK_IS_COMPONENT(m_element.get()))
return 0;
- int x, y;
- atk_component_get_position(ATK_COMPONENT(m_element.get()), &x, &y, ATK_XY_WINDOW);
-
- int width, height;
- atk_component_get_size(ATK_COMPONENT(m_element.get()), &width, &height);
+ int x, width;
+#if ATK_CHECK_VERSION(2,11,90)
+ atk_component_get_extents(ATK_COMPONENT(m_element.get()), &x, nullptr, &width, nullptr, ATK_XY_WINDOW);
+#else
+ atk_component_get_position(ATK_COMPONENT(m_element.get()), &x, nullptr, ATK_XY_WINDOW);
+ atk_component_get_size(ATK_COMPONENT(m_element.get()), &width, nullptr);
+#endif
return x + width / 2.0;
}
@@ -1062,11 +1364,13 @@ double AccessibilityUIElement::clickPointY()
if (!ATK_IS_COMPONENT(m_element.get()))
return 0;
- int x, y;
- atk_component_get_position(ATK_COMPONENT(m_element.get()), &x, &y, ATK_XY_WINDOW);
-
- int width, height;
- atk_component_get_size(ATK_COMPONENT(m_element.get()), &width, &height);
+ int y, height;
+#if ATK_CHECK_VERSION(2,11,90)
+ atk_component_get_extents(ATK_COMPONENT(m_element.get()), nullptr, &y, nullptr, &height, ATK_XY_WINDOW);
+#else
+ atk_component_get_position(ATK_COMPONENT(m_element.get()), nullptr, &y, ATK_XY_WINDOW);
+ atk_component_get_size(ATK_COMPONENT(m_element.get()), nullptr, &height);
+#endif
return y + height / 2.0;
}
@@ -1077,11 +1381,17 @@ double AccessibilityUIElement::intValue() const
return 0;
if (ATK_IS_VALUE(m_element.get())) {
+#if ATK_CHECK_VERSION(2,11,92)
+ double value;
+ atk_value_get_value_and_text(ATK_VALUE(m_element.get()), &value, nullptr);
+ return value;
+#else
GValue value = G_VALUE_INIT;
atk_value_get_current_value(ATK_VALUE(m_element.get()), &value);
if (!G_VALUE_HOLDS_FLOAT(&value))
return 0;
return g_value_get_float(&value);
+#endif
}
// Consider headings as an special case when returning the "int value" of
@@ -1102,13 +1412,16 @@ double AccessibilityUIElement::minValue()
{
if (!ATK_IS_VALUE(m_element.get()))
return 0;
-
+#if ATK_CHECK_VERSION(2,11,92)
+ return rangeMinMaxValue(ATK_VALUE(m_element.get()), RangeLimitMinimum);
+#else
GValue value = G_VALUE_INIT;
atk_value_get_minimum_value(ATK_VALUE(m_element.get()), &value);
if (!G_VALUE_HOLDS_FLOAT(&value))
return 0;
return g_value_get_float(&value);
+#endif
}
double AccessibilityUIElement::maxValue()
@@ -1116,18 +1429,23 @@ double AccessibilityUIElement::maxValue()
if (!ATK_IS_VALUE(m_element.get()))
return 0;
+#if ATK_CHECK_VERSION(2,11,92)
+ return rangeMinMaxValue(ATK_VALUE(m_element.get()), RangeLimitMaximum);
+#else
GValue value = G_VALUE_INIT;
atk_value_get_maximum_value(ATK_VALUE(m_element.get()), &value);
if (!G_VALUE_HOLDS_FLOAT(&value))
return 0;
return g_value_get_float(&value);
+#endif
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::valueDescription()
{
- // FIXME: implement
- return JSStringCreateWithCharacters(0, 0);
+ String valueText = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, "valuetext");
+ GUniquePtr<gchar> valueDescription(g_strdup_printf("AXValueDescription: %s", valueText.utf8().data()));
+ return JSStringCreateWithUTF8CString(valueDescription.get());
}
int AccessibilityUIElement::insertionPointLineNumber()
@@ -1142,7 +1460,7 @@ bool AccessibilityUIElement::isPressActionSupported()
return false;
const gchar* actionName = atk_action_get_name(ATK_ACTION(m_element.get()), 0);
- return equalIgnoringCase(actionName, String("press")) || equalIgnoringCase(actionName, String("jump"));
+ return equalLettersIgnoringASCIICase(String(actionName), "press") || equalLettersIgnoringASCIICase(String(actionName), "jump");
}
bool AccessibilityUIElement::isIncrementActionSupported()
@@ -1242,8 +1560,16 @@ int AccessibilityUIElement::lineForIndex(int index)
JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForLine(int line)
{
- // FIXME: implement
- return JSStringCreateWithCharacters(0, 0);
+ if (!ATK_IS_TEXT(m_element.get()))
+ return JSStringCreateWithCharacters(0, 0);
+
+ AtkText* text = ATK_TEXT(m_element.get());
+ gint startOffset = 0, endOffset = 0;
+ for (int i = 0; i <= line; ++i)
+ atk_text_get_string_at_offset(text, endOffset, ATK_TEXT_GRANULARITY_LINE, &startOffset, &endOffset);
+
+ GUniquePtr<gchar> range(g_strdup_printf("{%d, %d}", startOffset, endOffset - startOffset));
+ return JSStringCreateWithUTF8CString(range.get());
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForPosition(int x, int y)
@@ -1254,8 +1580,14 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForPosition(int x, int y)
JSRetainPtr<JSStringRef> AccessibilityUIElement::boundsForRange(unsigned location, unsigned length)
{
- // FIXME: implement
- return JSStringCreateWithCharacters(0, 0);
+ if (!ATK_IS_TEXT(m_element.get()))
+ return JSStringCreateWithCharacters(0, 0);
+
+ AtkTextRectangle rect;
+ atk_text_get_range_extents(ATK_TEXT(m_element.get()), location, location + length, ATK_XY_WINDOW, &rect);
+
+ GUniquePtr<gchar> bounds(g_strdup_printf("{%d, %d, %d, %d}", rect.x, rect.y, rect.width, rect.height));
+ return JSStringCreateWithUTF8CString(bounds.get());
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForRange(unsigned location, unsigned length)
@@ -1269,8 +1601,29 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForRange(unsigned locatio
JSRetainPtr<JSStringRef> AccessibilityUIElement::attributedStringForRange(unsigned location, unsigned length)
{
- // FIXME: implement
- return JSStringCreateWithCharacters(0, 0);
+ if (!ATK_IS_TEXT(m_element.get()))
+ return JSStringCreateWithCharacters(0, 0);
+
+ StringBuilder builder;
+
+ // The default text attributes apply to the entire element.
+ builder.append("\n\tDefault text attributes:\n\t\t");
+ builder.append(attributeSetToString(getAttributeSet(m_element.get(), TextAttributeType), "\n\t\t"));
+
+ // The attribute run provides attributes specific to the range of text at the specified offset.
+ AtkAttributeSet* attributeSet;
+ AtkText* text = ATK_TEXT(m_element.get());
+ gint start = 0, end = 0;
+ for (int i = location; i < location + length; i = end) {
+ AtkAttributeSet* attributeSet = atk_text_get_run_attributes(text, i, &start, &end);
+ GUniquePtr<gchar> substring(replaceCharactersForResults(atk_text_get_text(text, start, end)));
+ builder.append(String::format("\n\tRange attributes for '%s':\n\t\t", substring.get()));
+ builder.append(attributeSetToString(attributeSet, "\n\t\t"));
+ }
+
+ atk_attribute_set_free(attributeSet);
+
+ return JSStringCreateWithUTF8CString(builder.toString().utf8().data());
}
bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location, unsigned length)
@@ -1279,13 +1632,19 @@ bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location
return false;
}
-unsigned AccessibilityUIElement::uiElementCountForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly)
+unsigned AccessibilityUIElement::uiElementCountForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly)
{
// FIXME: implement
return 0;
}
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly)
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly)
+{
+ // FIXME: implement
+ return nullptr;
+}
+
+JSRetainPtr<JSStringRef> AccessibilityUIElement::selectTextWithCriteria(JSContextRef context, JSStringRef ambiguityResolution, JSValueRef searchStrings, JSStringRef replacementString, JSStringRef activity)
{
// FIXME: implement
return nullptr;
@@ -1370,7 +1729,7 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::columnIndexRange()
return indexRangeInTable(m_element.get(), false);
}
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::cellForColumnAndRow(unsigned col, unsigned row)
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::cellForColumnAndRow(unsigned col, unsigned row)
{
if (!ATK_IS_TABLE(m_element.get()))
return nullptr;
@@ -1378,16 +1737,16 @@ PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::cellForColumnAndRow(u
// Adopt the AtkObject representing the cell because
// at_table_ref_at() transfers full ownership.
GRefPtr<AtkObject> foundCell = adoptGRef(atk_table_ref_at(ATK_TABLE(m_element.get()), row, col));
- return foundCell ? AccessibilityUIElement::create(foundCell.get()) : nullptr;
+ return foundCell ? AccessibilityUIElement::create(foundCell.get()).ptr() : nullptr;
}
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::horizontalScrollbar() const
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::horizontalScrollbar() const
{
// FIXME: implement
return nullptr;
}
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::verticalScrollbar() const
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::verticalScrollbar() const
{
// FIXME: implement
return nullptr;
@@ -1445,6 +1804,30 @@ void AccessibilityUIElement::setSelectedChild(AccessibilityUIElement* element) c
// FIXME: implement
}
+void AccessibilityUIElement::setSelectedChildAtIndex(unsigned index) const
+{
+ if (!ATK_IS_SELECTION(m_element.get()))
+ return;
+
+ atk_selection_add_selection(ATK_SELECTION(m_element.get()), index);
+}
+
+void AccessibilityUIElement::removeSelectionAtIndex(unsigned index) const
+{
+ if (!ATK_IS_SELECTION(m_element.get()))
+ return;
+
+ atk_selection_remove_selection(ATK_SELECTION(m_element.get()), index);
+}
+
+void AccessibilityUIElement::clearSelectedChildren() const
+{
+ if (!ATK_IS_SELECTION(m_element.get()))
+ return;
+
+ atk_selection_clear_selection(ATK_SELECTION(m_element.get()));
+}
+
JSRetainPtr<JSStringRef> AccessibilityUIElement::accessibilityValue() const
{
// FIXME: implement
@@ -1457,7 +1840,7 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::documentEncoding()
return JSStringCreateWithCharacters(0, 0);
AtkRole role = atk_object_get_role(ATK_OBJECT(m_element.get()));
- if (role != ATK_ROLE_DOCUMENT_FRAME)
+ if (role != ATK_ROLE_DOCUMENT_WEB)
return JSStringCreateWithCharacters(0, 0);
return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element.get()), "Encoding"));
@@ -1469,7 +1852,7 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::documentURI()
return JSStringCreateWithCharacters(0, 0);
AtkRole role = atk_object_get_role(ATK_OBJECT(m_element.get()));
- if (role != ATK_ROLE_DOCUMENT_FRAME)
+ if (role != ATK_ROLE_DOCUMENT_WEB)
return JSStringCreateWithCharacters(0, 0);
return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element.get()), "URI"));
@@ -1552,13 +1935,23 @@ bool AccessibilityUIElement::isIgnored() const
return false;
}
+bool AccessibilityUIElement::isSingleLine() const
+{
+ return checkElementState(m_element.get(), ATK_STATE_SINGLE_LINE);
+}
+
+bool AccessibilityUIElement::isMultiLine() const
+{
+ return checkElementState(m_element.get(), ATK_STATE_MULTI_LINE);
+}
+
bool AccessibilityUIElement::hasPopup() const
{
if (!ATK_IS_OBJECT(m_element.get()))
return false;
String hasPopupValue = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, "haspopup");
- return equalIgnoringCase(hasPopupValue, "true");
+ return equalLettersIgnoringASCIICase(hasPopupValue, "true");
}
void AccessibilityUIElement::takeFocus()
@@ -1582,7 +1975,13 @@ void AccessibilityUIElement::removeSelection()
}
// Text markers
-PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForElement(AccessibilityUIElement* element)
+RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::lineTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
+{
+ // FIXME: implement
+ return nullptr;
+}
+
+RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForElement(AccessibilityUIElement* element)
{
// FIXME: implement
return nullptr;
@@ -1594,13 +1993,13 @@ int AccessibilityUIElement::textMarkerRangeLength(AccessibilityTextMarkerRange*
return 0;
}
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousTextMarker(AccessibilityTextMarker* textMarker)
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousTextMarker(AccessibilityTextMarker* textMarker)
{
// FIXME: implement
return nullptr;
}
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextTextMarker(AccessibilityTextMarker* textMarker)
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextTextMarker(AccessibilityTextMarker* textMarker)
{
// FIXME: implement
return nullptr;
@@ -1612,43 +2011,43 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForTextMarkerRange(Access
return JSStringCreateWithCharacters(0, 0);
}
-PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker)
+RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker)
{
// FIXME: implement
return nullptr;
}
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range)
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range)
{
// FIXME: implement
return nullptr;
}
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range)
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range)
{
// FIXME: implement
return nullptr;
}
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForBounds(int x, int y, int width, int height)
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForBounds(int x, int y, int width, int height)
{
// FIXME: implement
return nullptr;
}
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForBounds(int x, int y, int width, int height)
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForBounds(int x, int y, int width, int height)
{
// FIXME: implement
return nullptr;
}
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForPoint(int x, int y)
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForPoint(int x, int y)
{
// FIXME: implement
return nullptr;
}
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::accessibilityElementForTextMarker(AccessibilityTextMarker* marker)
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::accessibilityElementForTextMarker(AccessibilityTextMarker* marker)
{
// FIXME: implement
return nullptr;
@@ -1672,28 +2071,43 @@ bool AccessibilityUIElement::isTextMarkerValid(AccessibilityTextMarker* textMark
return false;
}
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForIndex(int textIndex)
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForIndex(int textIndex)
{
// FIXME: implement
return nullptr;
}
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarker()
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarker()
{
// FIXME: implement
return nullptr;
}
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarker()
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarker()
{
// FIXME: implement
return nullptr;
}
+bool AccessibilityUIElement::setSelectedVisibleTextRange(AccessibilityTextMarkerRange*)
+{
+ return false;
+}
+
void AccessibilityUIElement::scrollToMakeVisible()
{
// FIXME: implement
}
+
+void AccessibilityUIElement::scrollToGlobalPoint(int x, int y)
+{
+ // FIXME: implement
+}
+
+void AccessibilityUIElement::scrollToMakeVisibleWithSubFocus(int x, int y, int width, int height)
+{
+ // FIXME: implement
+}
JSRetainPtr<JSStringRef> AccessibilityUIElement::supportedActions() const
{
diff --git a/Tools/WebKitTestRunner/InjectedBundle/gtk/ActivateFontsGtk.cpp b/Tools/WebKitTestRunner/InjectedBundle/gtk/ActivateFontsGtk.cpp
index 7c9dab7b9..496c1bcbf 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/gtk/ActivateFontsGtk.cpp
+++ b/Tools/WebKitTestRunner/InjectedBundle/gtk/ActivateFontsGtk.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2005, 2006 Apple Inc. All rights reserved.
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
* Copyright (C) 2010 Igalia S.L.
*
@@ -12,7 +12,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -34,8 +34,8 @@
#include "InjectedBundleUtilities.h"
#include <fontconfig/fontconfig.h>
#include <gtk/gtk.h>
-#include <wtf/gobject/GUniquePtr.h>
-#include <wtf/gobject/GlibUtilities.h>
+#include <wtf/glib/GLibUtilities.h>
+#include <wtf/glib/GUniquePtr.h>
namespace WTR {
@@ -68,7 +68,7 @@ CString getOutputDir()
static CString getFontsPath()
{
CString webkitOutputDir = getOutputDir();
- GUniquePtr<char> fontsPath(g_build_filename(webkitOutputDir.data(), "Dependencies", "Root", "webkitgtk-test-fonts", nullptr));
+ GUniquePtr<char> fontsPath(g_build_filename(webkitOutputDir.data(), "DependenciesGTK", "Root", "webkitgtk-test-fonts", nullptr));
if (g_file_test(fontsPath.get(), static_cast<GFileTest>(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
return fontsPath.get();
diff --git a/Tools/WebKitTestRunner/InjectedBundle/gtk/InjectedBundleUtilities.cpp b/Tools/WebKitTestRunner/InjectedBundle/gtk/InjectedBundleUtilities.cpp
index febdaad19..afbd3f74a 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/gtk/InjectedBundleUtilities.cpp
+++ b/Tools/WebKitTestRunner/InjectedBundle/gtk/InjectedBundleUtilities.cpp
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -30,8 +30,8 @@
#include "InjectedBundleUtilities.h"
#include <gtk/gtk.h>
-#include <wtf/gobject/GUniquePtr.h>
-#include <wtf/gobject/GlibUtilities.h>
+#include <wtf/glib/GLibUtilities.h>
+#include <wtf/glib/GUniquePtr.h>
namespace WTR {
diff --git a/Tools/WebKitTestRunner/InjectedBundle/gtk/InjectedBundleUtilities.h b/Tools/WebKitTestRunner/InjectedBundle/gtk/InjectedBundleUtilities.h
index 50f89dead..4062c6d44 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/gtk/InjectedBundleUtilities.h
+++ b/Tools/WebKitTestRunner/InjectedBundle/gtk/InjectedBundleUtilities.h
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
diff --git a/Tools/WebKitTestRunner/InjectedBundle/gtk/TestRunnerGtk.cpp b/Tools/WebKitTestRunner/InjectedBundle/gtk/TestRunnerGtk.cpp
index 254374884..a9f7f409c 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/gtk/TestRunnerGtk.cpp
+++ b/Tools/WebKitTestRunner/InjectedBundle/gtk/TestRunnerGtk.cpp
@@ -30,37 +30,25 @@
#include "InjectedBundle.h"
#include "InjectedBundleUtilities.h"
#include <glib.h>
-#include <wtf/gobject/GUniquePtr.h>
+#include <wtf/glib/GUniquePtr.h>
namespace WTR {
-static gboolean waitToDumpWatchdogTimerCallback(gpointer)
-{
- InjectedBundle::shared().testRunner()->waitToDumpWatchdogTimerFired();
- return FALSE;
-}
-
void TestRunner::platformInitialize()
{
- m_waitToDumpWatchdogTimer = 0;
}
void TestRunner::invalidateWaitToDumpWatchdogTimer()
{
- if (!m_waitToDumpWatchdogTimer)
- return;
- g_source_remove(m_waitToDumpWatchdogTimer);
- m_waitToDumpWatchdogTimer = 0;
+ m_waitToDumpWatchdogTimer.stop();
}
void TestRunner::initializeWaitToDumpWatchdogTimerIfNeeded()
{
- if (m_waitToDumpWatchdogTimer)
+ if (m_waitToDumpWatchdogTimer.isActive())
return;
- m_waitToDumpWatchdogTimer = g_timeout_add(waitToDumpWatchdogTimerInterval * 1000,
- waitToDumpWatchdogTimerCallback, 0);
- g_source_set_name_by_id(m_waitToDumpWatchdogTimer, "[WebKit] waitToDumpWatchdogTimerCallback");
+ m_waitToDumpWatchdogTimer.startOneShot(m_timeout / 1000.0);
}
JSRetainPtr<JSStringRef> TestRunner::pathToLocalResource(JSStringRef url)
@@ -78,4 +66,9 @@ JSRetainPtr<JSStringRef> TestRunner::pathToLocalResource(JSStringRef url)
return JSStringCreateWithUTF8CString(testURI.get());
}
+JSRetainPtr<JSStringRef> TestRunner::inspectorTestStubURL()
+{
+ return JSStringCreateWithUTF8CString("resource:///org/webkitgtk/inspector/UserInterface/TestStub.html");
+}
+
} // namespace WTR
diff --git a/Tools/WebKitTestRunner/Options.cpp b/Tools/WebKitTestRunner/Options.cpp
index 8fa6e6e0f..53f0253ac 100644
--- a/Tools/WebKitTestRunner/Options.cpp
+++ b/Tools/WebKitTestRunner/Options.cpp
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2013 University of Szeged. All rights reserved.
* Copyright (C) 2013 Samsung Electronics. All rights reserved.
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,10 +32,8 @@
namespace WTR {
-Options::Options(double defaultLongTimeout, double defaultShortTimeout)
- : longTimeout(defaultLongTimeout)
- , shortTimeout(defaultShortTimeout)
- , useWaitToDumpWatchdogTimer(true)
+Options::Options()
+ : useWaitToDumpWatchdogTimer(true)
, forceNoTimeout(false)
, verbose(false)
, gcBetweenTests(false)
@@ -43,28 +42,13 @@ Options::Options(double defaultLongTimeout, double defaultShortTimeout)
, forceComplexText(false)
, shouldUseAcceleratedDrawing(false)
, shouldUseRemoteLayerTree(false)
- , defaultLongTimeout(defaultLongTimeout)
- , defaultShortTimeout(defaultShortTimeout)
+ , shouldShowWebView(false)
{
}
-bool handleOptionTimeout(Options& options, const char*, const char* argument)
-{
- options.longTimeout = atoi(argument);
- // Scale up the short timeout to match.
- options.shortTimeout = options.defaultShortTimeout * options.longTimeout / options.defaultLongTimeout;
- return true;
-}
-
bool handleOptionNoTimeout(Options& options, const char*, const char*)
{
options.useWaitToDumpWatchdogTimer = false;
- return true;
-}
-
-bool handleOptionNoTimeoutAtAll(Options& options, const char*, const char*)
-{
- options.useWaitToDumpWatchdogTimer = false;
options.forceNoTimeout = true;
return true;
}
@@ -111,6 +95,18 @@ bool handleOptionRemoteLayerTree(Options& options, const char*, const char*)
return true;
}
+bool handleOptionShowWebView(Options& options, const char*, const char*)
+{
+ options.shouldShowWebView = true;
+ return true;
+}
+
+bool handleOptionAllowedHost(Options& options, const char*, const char* host)
+{
+ options.allowedHosts.push_back(host);
+ return true;
+}
+
bool handleOptionUnmatched(Options& options, const char* option, const char*)
{
if (option[0] && option[1] && option[0] == '-' && option[1] == '-')
@@ -122,9 +118,7 @@ bool handleOptionUnmatched(Options& options, const char* option, const char*)
OptionsHandler::OptionsHandler(Options& o)
: options(o)
{
- optionList.append(Option("--timeout", "Sets long timeout to <param> and scales short timeout.", handleOptionTimeout, true));
- optionList.append(Option("--no-timeout", "Disables timeout.", handleOptionNoTimeout));
- optionList.append(Option("--no-timeout-at-all", "Disables all timeouts.", handleOptionNoTimeoutAtAll));
+ optionList.append(Option("--no-timeout", "Disables all timeouts.", handleOptionNoTimeout));
optionList.append(Option("--verbose", "Turns on messages.", handleOptionVerbose));
optionList.append(Option("--gc-between-tests", "Garbage collection between tests.", handleOptionGcBetweenTests));
optionList.append(Option("--pixel-tests", "Check pixels.", handleOptionPixelTests));
@@ -133,6 +127,9 @@ OptionsHandler::OptionsHandler(Options& o)
optionList.append(Option("--complex-text", "Force complex tests.", handleOptionComplexText));
optionList.append(Option("--accelerated-drawing", "Use accelerated drawing.", handleOptionAcceleratedDrawing));
optionList.append(Option("--remote-layer-tree", "Use remote layer tree.", handleOptionRemoteLayerTree));
+ optionList.append(Option("--allowed-host", "Allows access to the specified host from tests.", handleOptionAllowedHost, true));
+ optionList.append(Option("--show-webview", "Show the WebView during test runs (for Debugging)", handleOptionShowWebView));
+
optionList.append(Option(0, 0, handleOptionUnmatched));
}
diff --git a/Tools/WebKitTestRunner/Options.h b/Tools/WebKitTestRunner/Options.h
index a89d25c77..5549fe464 100644
--- a/Tools/WebKitTestRunner/Options.h
+++ b/Tools/WebKitTestRunner/Options.h
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2013 University of Szeged. All rights reserved.
* Copyright (C) 2013 Samsung Electronics. All rights reserved.
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -36,9 +37,7 @@
namespace WTR {
struct Options {
- Options(double, double);
- double longTimeout;
- double shortTimeout;
+ Options();
bool useWaitToDumpWatchdogTimer;
bool forceNoTimeout;
bool verbose;
@@ -48,9 +47,9 @@ struct Options {
bool forceComplexText;
bool shouldUseAcceleratedDrawing;
bool shouldUseRemoteLayerTree;
+ bool shouldShowWebView;
std::vector<std::string> paths;
- double defaultLongTimeout;
- double defaultShortTimeout;
+ std::vector<std::string> allowedHosts;
};
class Option {
diff --git a/Tools/WebKitTestRunner/PixelDumpSupport.cpp b/Tools/WebKitTestRunner/PixelDumpSupport.cpp
index 76974737f..37b3047cb 100644
--- a/Tools/WebKitTestRunner/PixelDumpSupport.cpp
+++ b/Tools/WebKitTestRunner/PixelDumpSupport.cpp
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
diff --git a/Tools/WebKitTestRunner/PixelDumpSupport.h b/Tools/WebKitTestRunner/PixelDumpSupport.h
index 41c6e38ea..324667f10 100644
--- a/Tools/WebKitTestRunner/PixelDumpSupport.h
+++ b/Tools/WebKitTestRunner/PixelDumpSupport.h
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
diff --git a/Tools/WebKitTestRunner/PlatformGTK.cmake b/Tools/WebKitTestRunner/PlatformGTK.cmake
new file mode 100644
index 000000000..af53e220d
--- /dev/null
+++ b/Tools/WebKitTestRunner/PlatformGTK.cmake
@@ -0,0 +1,60 @@
+add_custom_target(WebKitTestRunner-forwarding-headers
+ COMMAND ${PERL_EXECUTABLE} ${WEBKIT2_DIR}/Scripts/generate-forwarding-headers.pl --include-path ${WEBKIT_TESTRUNNER_DIR} --include-path ${WEBKIT_TESTRUNNER_SHARED_DIR} --output ${FORWARDING_HEADERS_DIR} --platform gtk --platform soup
+)
+
+set(ForwardingHeadersForWebKitTestRunner_NAME WebKitTestRunner-forwarding-headers)
+
+list(APPEND WebKitTestRunner_SOURCES
+ ${WEBKIT_TESTRUNNER_DIR}/cairo/TestInvocationCairo.cpp
+
+ ${WEBKIT_TESTRUNNER_DIR}/gtk/EventSenderProxyGtk.cpp
+ ${WEBKIT_TESTRUNNER_DIR}/gtk/PlatformWebViewGtk.cpp
+ ${WEBKIT_TESTRUNNER_DIR}/gtk/TestControllerGtk.cpp
+ ${WEBKIT_TESTRUNNER_DIR}/gtk/main.cpp
+)
+
+list(APPEND WebKitTestRunner_INCLUDE_DIRECTORIES
+ ${FORWARDING_HEADERS_DIR}
+)
+
+list(APPEND WebKitTestRunner_SYSTEM_INCLUDE_DIRECTORIES
+ ${ATK_INCLUDE_DIRS}
+ ${CAIRO_INCLUDE_DIRS}
+ ${GTK3_INCLUDE_DIRS}
+ ${GLIB_INCLUDE_DIRS}
+)
+
+list(APPEND WebKitTestRunner_LIBRARIES
+ ${ATK_LIBRARIES}
+ ${CAIRO_LIBRARIES}
+ ${GTK3_LIBRARIES}
+ ${GLIB_LIBRARIES}
+ WTF
+ WebCore
+ WebCorePlatformGTK
+)
+
+set(WebKitTestRunnerInjectedBundle_LIBRARIES
+ ${ATK_LIBRARIES}
+ ${FONTCONFIG_LIBRARIES}
+ ${GLIB_LIBRARIES}
+ ${GTK3_LIBRARIES}
+ WebCoreTestSupport
+ WebKit2
+)
+
+list(APPEND WebKitTestRunnerInjectedBundle_SOURCES
+ ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/atk/AccessibilityControllerAtk.cpp
+ ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/atk/AccessibilityNotificationHandlerAtk.cpp
+ ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/atk/AccessibilityUIElementAtk.cpp
+
+ ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/gtk/ActivateFontsGtk.cpp
+ ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/gtk/InjectedBundleGtk.cpp
+ ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/gtk/InjectedBundleUtilities.cpp
+ ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/gtk/TestRunnerGtk.cpp
+)
+
+add_definitions(
+ -DFONTS_CONF_DIR="${TOOLS_DIR}/WebKitTestRunner/gtk/fonts"
+ -DTOP_LEVEL_DIR="${CMAKE_SOURCE_DIR}"
+)
diff --git a/Tools/WebKitTestRunner/PlatformWebView.h b/Tools/WebKitTestRunner/PlatformWebView.h
index fa8d1236c..aa0ab2e49 100644
--- a/Tools/WebKitTestRunner/PlatformWebView.h
+++ b/Tools/WebKitTestRunner/PlatformWebView.h
@@ -26,29 +26,28 @@
#ifndef PlatformWebView_h
#define PlatformWebView_h
-#include <WebKit2/WKRetainPtr.h>
+#include "TestOptions.h"
+#include <WebKit/WKRetainPtr.h>
-#if defined(__APPLE__) && __APPLE__
-#ifdef __OBJC__
-@class WKView;
-@class WebKitTestRunnerWindow;
+#if PLATFORM(COCOA) && !defined(BUILDING_GTK__)
+#include <WebKit/WKFoundation.h>
+OBJC_CLASS NSView;
+OBJC_CLASS UIView;
+OBJC_CLASS TestRunnerWKWebView;
+OBJC_CLASS WKWebViewConfiguration;
+OBJC_CLASS WebKitTestRunnerWindow;
+
+#if WK_API_ENABLED
+typedef TestRunnerWKWebView *PlatformWKView;
#else
-class WKView;
-class WebKitTestRunnerWindow;
+typedef NSView *PlatformWKView;
#endif
-typedef WKView* PlatformWKView;
-typedef WebKitTestRunnerWindow* PlatformWindow;
+typedef WebKitTestRunnerWindow *PlatformWindow;
#elif defined(BUILDING_GTK__)
typedef struct _GtkWidget GtkWidget;
typedef WKViewRef PlatformWKView;
typedef GtkWidget* PlatformWindow;
#elif PLATFORM(EFL)
-typedef struct _Ecore_Evas Ecore_Evas;
-#if USE(EO)
-typedef struct _Eo_Opaque Evas_Object;
-#else
-typedef struct _Evas_Object Evas_Object;
-#endif
typedef Evas_Object* PlatformWKView;
typedef Ecore_Evas* PlatformWindow;
#endif
@@ -57,43 +56,60 @@ namespace WTR {
class PlatformWebView {
public:
- PlatformWebView(WKContextRef, WKPageGroupRef, WKPageRef relatedPage, WKDictionaryRef options = 0);
+#if PLATFORM(COCOA)
+ PlatformWebView(WKWebViewConfiguration*, const TestOptions&);
+#else
+ PlatformWebView(WKPageConfigurationRef, const TestOptions&);
+#endif
~PlatformWebView();
WKPageRef page();
PlatformWKView platformView() { return m_view; }
PlatformWindow platformWindow() { return m_window; }
- void resizeTo(unsigned width, unsigned height);
- void focus();
+ static PlatformWindow keyWindow();
- // Window snapshot is always enabled by default on all other platform.
- static bool windowSnapshotEnabled() { return true; }
+ enum class WebViewSizingMode {
+ Default,
+ HeightRespectsStatusBar
+ };
+
+ void resizeTo(unsigned width, unsigned height, WebViewSizingMode = WebViewSizingMode::Default);
+ void focus();
WKRect windowFrame();
- void setWindowFrame(WKRect);
+ void setWindowFrame(WKRect, WebViewSizingMode = WebViewSizingMode::Default);
void didInitializeClients();
void addChromeInputField();
void removeChromeInputField();
void makeWebViewFirstResponder();
- void setWindowIsKey(bool isKey) { m_windowIsKey = isKey; }
+ void setWindowIsKey(bool);
bool windowIsKey() const { return m_windowIsKey; }
+
+ void removeFromWindow();
+ void addToWindow();
-#if PLATFORM(MAC) || PLATFORM(EFL)
- bool viewSupportsOptions(WKDictionaryRef) const;
-#else
- bool viewSupportsOptions(WKDictionaryRef) const { return true; }
-#endif
+ bool viewSupportsOptions(const TestOptions&) const;
WKRetainPtr<WKImageRef> windowSnapshotImage();
- WKDictionaryRef options() const { return m_options.get(); }
+ const TestOptions& options() const { return m_options; }
+
+ void changeWindowScaleIfNeeded(float newScale);
+ void setNavigationGesturesEnabled(bool);
+
+#if PLATFORM(GTK)
+ void dismissAllPopupMenus();
+#endif
private:
+ void forceWindowFramesChanged();
+
PlatformWKView m_view;
PlatformWindow m_window;
bool m_windowIsKey;
- WKRetainPtr<WKDictionaryRef> m_options;
+ const TestOptions m_options;
+
#if PLATFORM(EFL)
bool m_usingFixedLayout;
#endif
diff --git a/Tools/WebKitTestRunner/StringFunctions.h b/Tools/WebKitTestRunner/StringFunctions.h
index 551d86740..752731cbf 100644
--- a/Tools/WebKitTestRunner/StringFunctions.h
+++ b/Tools/WebKitTestRunner/StringFunctions.h
@@ -29,12 +29,12 @@
#include <JavaScriptCore/JSRetainPtr.h>
#include <JavaScriptCore/JavaScript.h>
+#include <WebKit/WKRetainPtr.h>
+#include <WebKit/WKString.h>
+#include <WebKit/WKStringPrivate.h>
+#include <WebKit/WKURL.h>
#include <sstream>
#include <string>
-#include <WebKit2/WKRetainPtr.h>
-#include <WebKit2/WKString.h>
-#include <WebKit2/WKStringPrivate.h>
-#include <WebKit2/WKURL.h>
#include <wtf/Platform.h>
#include <wtf/StdLibExtras.h>
#include <wtf/Vector.h>
@@ -87,7 +87,7 @@ inline WTF::String toWTFString(WKStringRef string)
{
size_t bufferSize = WKStringGetMaximumUTF8CStringSize(string);
auto buffer = std::make_unique<char[]>(bufferSize);
- size_t stringLength = WKStringGetUTF8CString(string, buffer.get(), bufferSize);
+ size_t stringLength = WKStringGetUTF8CStringNonStrict(string, buffer.get(), bufferSize);
return WTF::String::fromUTF8WithLatin1Fallback(buffer.get(), stringLength - 1);
}
diff --git a/Tools/WebKitTestRunner/TestController.cpp b/Tools/WebKitTestRunner/TestController.cpp
index 397815e63..df5392e74 100644
--- a/Tools/WebKitTestRunner/TestController.cpp
+++ b/Tools/WebKitTestRunner/TestController.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2014-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,33 +31,55 @@
#include "PlatformWebView.h"
#include "StringFunctions.h"
#include "TestInvocation.h"
-#include <WebKit2/WKAuthenticationChallenge.h>
-#include <WebKit2/WKAuthenticationDecisionListener.h>
-#include <WebKit2/WKContextPrivate.h>
-#include <WebKit2/WKCredential.h>
-#include <WebKit2/WKIconDatabase.h>
-#include <WebKit2/WKNotification.h>
-#include <WebKit2/WKNotificationManager.h>
-#include <WebKit2/WKNotificationPermissionRequest.h>
-#include <WebKit2/WKNumber.h>
-#include <WebKit2/WKPageGroup.h>
-#include <WebKit2/WKPagePrivate.h>
-#include <WebKit2/WKPreferencesPrivate.h>
-#include <WebKit2/WKRetainPtr.h>
+#include "WebCoreTestSupport.h"
+#include <WebCore/UUID.h>
+#include <WebKit/WKArray.h>
+#include <WebKit/WKAuthenticationChallenge.h>
+#include <WebKit/WKAuthenticationDecisionListener.h>
+#include <WebKit/WKContextConfigurationRef.h>
+#include <WebKit/WKContextPrivate.h>
+#include <WebKit/WKCookieManager.h>
+#include <WebKit/WKCredential.h>
+#include <WebKit/WKFrameHandleRef.h>
+#include <WebKit/WKFrameInfoRef.h>
+#include <WebKit/WKIconDatabase.h>
+#include <WebKit/WKNavigationResponseRef.h>
+#include <WebKit/WKNotification.h>
+#include <WebKit/WKNotificationManager.h>
+#include <WebKit/WKNotificationPermissionRequest.h>
+#include <WebKit/WKNumber.h>
+#include <WebKit/WKOpenPanelResultListener.h>
+#include <WebKit/WKPageGroup.h>
+#include <WebKit/WKPageInjectedBundleClient.h>
+#include <WebKit/WKPagePrivate.h>
+#include <WebKit/WKPluginInformation.h>
+#include <WebKit/WKPreferencesRefPrivate.h>
+#include <WebKit/WKProtectionSpace.h>
+#include <WebKit/WKResourceLoadStatisticsManager.h>
+#include <WebKit/WKRetainPtr.h>
+#include <WebKit/WKSecurityOriginRef.h>
+#include <WebKit/WKTextChecker.h>
+#include <WebKit/WKUserMediaPermissionCheck.h>
#include <algorithm>
#include <cstdio>
#include <ctype.h>
+#include <fstream>
+#include <runtime/InitializeThreading.h>
#include <stdlib.h>
#include <string>
-#include <wtf/PassOwnPtr.h>
+#include <unistd.h>
+#include <wtf/CryptographicallyRandomNumber.h>
+#include <wtf/HexNumber.h>
+#include <wtf/MainThread.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RunLoop.h>
+#include <wtf/SetForScope.h>
#include <wtf/text/CString.h>
+#include <wtf/text/WTFString.h>
-#if PLATFORM(MAC)
-#include <WebKit2/WKPagePrivateMac.h>
-#endif
-
-#if !PLATFORM(MAC)
-#include <WebKit2/WKTextChecker.h>
+#if PLATFORM(COCOA)
+#include <WebKit/WKContextPrivateMac.h>
+#include <WebKit/WKPagePrivateMac.h>
#endif
namespace WTR {
@@ -68,12 +90,9 @@ const unsigned TestController::viewHeight = 600;
const unsigned TestController::w3cSVGViewWidth = 480;
const unsigned TestController::w3cSVGViewHeight = 360;
-// defaultLongTimeout + defaultShortTimeout should be less than 80,
-// the default timeout value of the test harness so we can detect an
-// unresponsive web process.
-static const double defaultLongTimeout = 60;
-static const double defaultShortTimeout = 15;
-static const double defaultNoTimeout = -1;
+const double TestController::defaultShortTimeout = 5.0;
+
+const double TestController::noTimeout = -1;
static WKURLRef blankURL()
{
@@ -81,40 +100,21 @@ static WKURLRef blankURL()
return staticBlankURL;
}
+static WKDataRef copyWebCryptoMasterKey(WKPageRef, const void*)
+{
+ // Any 128 bit key would do, all we need for testing is to implement the callback.
+ return WKDataCreate((const uint8_t*)"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 16);
+}
+
static TestController* controller;
-TestController& TestController::shared()
+TestController& TestController::singleton()
{
ASSERT(controller);
return *controller;
}
TestController::TestController(int argc, const char* argv[])
- : m_verbose(false)
- , m_printSeparators(false)
- , m_usingServerMode(false)
- , m_gcBetweenTests(false)
- , m_shouldDumpPixelsForAllTests(false)
- , m_state(Initial)
- , m_doneResetting(false)
- , m_longTimeout(defaultLongTimeout)
- , m_shortTimeout(defaultShortTimeout)
- , m_noTimeout(defaultNoTimeout)
- , m_useWaitToDumpWatchdogTimer(true)
- , m_forceNoTimeout(false)
- , m_timeout(0)
- , m_didPrintWebProcessCrashedMessage(false)
- , m_shouldExitWhenWebProcessCrashes(true)
- , m_beforeUnloadReturnValue(true)
- , m_isGeolocationPermissionSet(false)
- , m_isGeolocationPermissionAllowed(false)
- , m_policyDelegateEnabled(false)
- , m_policyDelegatePermissive(false)
- , m_handlesAuthenticationChallenges(false)
- , m_shouldBlockAllPlugins(false)
- , m_forceComplexText(false)
- , m_shouldUseAcceleratedDrawing(false)
- , m_shouldUseRemoteLayerTree(false)
{
initialize(argc, argv);
controller = this;
@@ -124,7 +124,9 @@ TestController::TestController(int argc, const char* argv[])
TestController::~TestController()
{
- WKIconDatabaseClose(WKContextGetIconDatabase(m_context.get()));
+ // The context will be null if WebKitTestRunner was in server mode, but ran no tests.
+ if (m_context)
+ WKIconDatabaseClose(WKContextGetIconDatabase(m_context.get()));
platformDestroy();
}
@@ -144,7 +146,13 @@ static void setWindowFrame(WKPageRef page, WKRect frame, const void* clientInfo)
static bool runBeforeUnloadConfirmPanel(WKPageRef page, WKStringRef message, WKFrameRef frame, const void*)
{
printf("CONFIRM NAVIGATION: %s\n", toSTD(message).c_str());
- return TestController::shared().beforeUnloadReturnValue();
+ return TestController::singleton().beforeUnloadReturnValue();
+}
+
+static void runOpenPanel(WKPageRef page, WKFrameRef frame, WKOpenPanelParametersRef parameters, WKOpenPanelResultListenerRef resultListenerRef, const void*)
+{
+ printf("OPEN FILE PANEL\n");
+ WKOpenPanelResultListenerCancel(resultListenerRef);
}
void TestController::runModal(WKPageRef page, const void* clientInfo)
@@ -177,34 +185,44 @@ static void unfocus(WKPageRef page, const void* clientInfo)
static void decidePolicyForGeolocationPermissionRequest(WKPageRef, WKFrameRef, WKSecurityOriginRef, WKGeolocationPermissionRequestRef permissionRequest, const void* clientInfo)
{
- TestController::shared().handleGeolocationPermissionRequest(permissionRequest);
+ TestController::singleton().handleGeolocationPermissionRequest(permissionRequest);
}
-int TestController::getCustomTimeout()
+static void decidePolicyForUserMediaPermissionRequest(WKPageRef, WKFrameRef frame, WKSecurityOriginRef userMediaDocumentOrigin, WKSecurityOriginRef topLevelDocumentOrigin, WKUserMediaPermissionRequestRef permissionRequest, const void* clientInfo)
{
- return m_timeout;
+ TestController::singleton().handleUserMediaPermissionRequest(frame, userMediaDocumentOrigin, topLevelDocumentOrigin, permissionRequest);
}
-WKPageRef TestController::createOtherPage(WKPageRef oldPage, WKURLRequestRef, WKDictionaryRef, WKEventModifiers, WKEventMouseButton, const void* clientInfo)
+static void checkUserMediaPermissionForOrigin(WKPageRef, WKFrameRef frame, WKSecurityOriginRef userMediaDocumentOrigin, WKSecurityOriginRef topLevelDocumentOrigin, WKUserMediaPermissionCheckRef checkRequest, const void*)
+{
+ TestController::singleton().handleCheckOfUserMediaPermissionForOrigin(frame, userMediaDocumentOrigin, topLevelDocumentOrigin, checkRequest);
+}
+
+static void requestPointerLock(WKPageRef page, const void*)
+{
+ WKPageDidAllowPointerLock(page);
+}
+
+WKPageRef TestController::createOtherPage(WKPageRef oldPage, WKPageConfigurationRef configuration, WKNavigationActionRef navigationAction, WKWindowFeaturesRef windowFeatures, const void *clientInfo)
{
PlatformWebView* parentView = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
- PlatformWebView* view = new PlatformWebView(WKPageGetContext(oldPage), WKPageGetPageGroup(oldPage), oldPage, parentView->options());
+ PlatformWebView* view = platformCreateOtherPage(parentView, configuration, parentView->options());
WKPageRef newPage = view->page();
view->resizeTo(800, 600);
- WKPageUIClientV2 otherPageUIClient = {
- { 2, view },
+ WKPageUIClientV8 otherPageUIClient = {
+ { 8, view },
0, // createNewPage_deprecatedForUseWithV0
0, // showPage
closeOtherPage,
0, // takeFocus
focus,
unfocus,
- 0, // runJavaScriptAlert
- 0, // runJavaScriptConfirm
- 0, // runJavaScriptPrompt
+ 0, // runJavaScriptAlert_deprecatedForUseWithV0
+ 0, // runJavaScriptAlert_deprecatedForUseWithV0
+ 0, // runJavaScriptAlert_deprecatedForUseWithV0
0, // setStatusText
0, // mouseDidMoveOverElement_deprecatedForUseWithV0
0, // missingPluginButtonClicked
@@ -224,7 +242,7 @@ WKPageRef TestController::createOtherPage(WKPageRef oldPage, WKURLRequestRef, WK
0, // didDraw
0, // pageDidScroll
0, // exceededDatabaseQuota
- 0, // runOpenPanel
+ runOpenPanel,
decidePolicyForGeolocationPermissionRequest,
0, // headerHeight
0, // footerHeight
@@ -235,18 +253,66 @@ WKPageRef TestController::createOtherPage(WKPageRef oldPage, WKURLRequestRef, WK
0, // didCompleteRubberBandForMainFrame
0, // saveDataToFileInDownloadsFolder
0, // shouldInterruptJavaScript
- createOtherPage,
+ 0, // createNewPage_deprecatedForUseWithV1
0, // mouseDidMoveOverElement
0, // decidePolicyForNotificationPermissionRequest
0, // unavailablePluginButtonClicked_deprecatedForUseWithV1
0, // showColorPicker
0, // hideColorPicker
0, // unavailablePluginButtonClicked
+ 0, // pinnedStateDidChange
+ 0, // didBeginTrackingPotentialLongMousePress
+ 0, // didRecognizeLongMousePress
+ 0, // didCancelTrackingPotentialLongMousePress
+ 0, // isPlayingAudioDidChange
+ decidePolicyForUserMediaPermissionRequest,
+ 0, // didClickAutofillButton
+ 0, // runJavaScriptAlert
+ 0, // runJavaScriptConfirm
+ 0, // runJavaScriptPrompt
+ 0, // mediaSessionMetadataDidChange
+ createOtherPage,
+ 0, // runJavaScriptAlert
+ 0, // runJavaScriptConfirm
+ 0, // runJavaScriptPrompt
+ checkUserMediaPermissionForOrigin,
+ 0, // runBeforeUnloadConfirmPanel
+ 0, // fullscreenMayReturnToInline
+ requestPointerLock,
+ 0,
};
WKPageSetPageUIClient(newPage, &otherPageUIClient.base);
+
+ WKPageNavigationClientV0 pageNavigationClient = {
+ { 0, &TestController::singleton() },
+ decidePolicyForNavigationAction,
+ decidePolicyForNavigationResponse,
+ decidePolicyForPluginLoad,
+ 0, // didStartProvisionalNavigation
+ 0, // didReceiveServerRedirectForProvisionalNavigation
+ 0, // didFailProvisionalNavigation
+ 0, // didCommitNavigation
+ 0, // didFinishNavigation
+ 0, // didFailNavigation
+ 0, // didFailProvisionalLoadInSubframe
+ 0, // didFinishDocumentLoad
+ 0, // didSameDocumentNavigation
+ 0, // renderingProgressDidChange
+ canAuthenticateAgainstProtectionSpace,
+ didReceiveAuthenticationChallenge,
+ processDidCrash,
+ copyWebCryptoMasterKey,
+ didBeginNavigationGesture,
+ willEndNavigationGesture,
+ didEndNavigationGesture,
+ didRemoveNavigationGestureSnapshot
+ };
+ WKPageSetPageNavigationClient(newPage, &pageNavigationClient.base);
view->didInitializeClients();
+ TestController::singleton().updateWindowScaleForTest(view, *TestController::singleton().m_currentInvocation);
+
WKRetain(newPage);
return newPage;
}
@@ -262,12 +328,14 @@ const char* TestController::libraryPathForTesting()
return platformLibraryPathForTesting();
}
-
void TestController::initialize(int argc, const char* argv[])
{
+ JSC::initializeThreading();
+ RunLoop::initializeMainRunLoop();
+
platformInitialize();
- Options options(defaultLongTimeout, defaultShortTimeout);
+ Options options;
OptionsHandler optionsHandler(options);
if (argc < 2) {
@@ -277,8 +345,6 @@ void TestController::initialize(int argc, const char* argv[])
if (!optionsHandler.parse(argc, argv))
exit(1);
- m_longTimeout = options.longTimeout;
- m_shortTimeout = options.shortTimeout;
m_useWaitToDumpWatchdogTimer = options.useWaitToDumpWatchdogTimer;
m_forceNoTimeout = options.forceNoTimeout;
m_verbose = options.verbose;
@@ -288,6 +354,8 @@ void TestController::initialize(int argc, const char* argv[])
m_shouldUseAcceleratedDrawing = options.shouldUseAcceleratedDrawing;
m_shouldUseRemoteLayerTree = options.shouldUseRemoteLayerTree;
m_paths = options.paths;
+ m_allowedHosts = options.allowedHosts;
+ m_shouldShowWebView = options.shouldShowWebView;
if (options.printSupportedFeatures) {
// FIXME: On Windows, DumpRenderTree uses this to expose whether it supports 3d
@@ -305,32 +373,50 @@ void TestController::initialize(int argc, const char* argv[])
initializeInjectedBundlePath();
initializeTestPluginDirectory();
+#if PLATFORM(MAC)
+ WebCoreTestSupport::installMockGamepadProvider();
+#endif
WKRetainPtr<WKStringRef> pageGroupIdentifier(AdoptWK, WKStringCreateWithUTF8CString("WebKitTestRunnerPageGroup"));
m_pageGroup.adopt(WKPageGroupCreateWithIdentifier(pageGroupIdentifier.get()));
+}
- m_context.adopt(WKContextCreateWithInjectedBundlePath(injectedBundlePath()));
- m_geolocationProvider = adoptPtr(new GeolocationProviderMock(m_context.get()));
-
-#if PLATFORM(IOS) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED > 1080)
- WKContextSetUsesNetworkProcess(m_context.get(), true);
- WKContextSetProcessModel(m_context.get(), kWKProcessModelMultipleSecondaryProcesses);
-#endif
+WKRetainPtr<WKContextConfigurationRef> TestController::generateContextConfiguration() const
+{
+ auto configuration = adoptWK(WKContextConfigurationCreate());
+ WKContextConfigurationSetInjectedBundlePath(configuration.get(), injectedBundlePath());
+ WKContextConfigurationSetFullySynchronousModeIsAllowedForTesting(configuration.get(), true);
if (const char* dumpRenderTreeTemp = libraryPathForTesting()) {
String temporaryFolder = String::fromUTF8(dumpRenderTreeTemp);
- // WebCore::pathByAppendingComponent is not used here because of the namespace,
- // which leads us to this ugly #ifdef and file path concatenation.
const char separator = '/';
- WKContextSetApplicationCacheDirectory(m_context.get(), toWK(temporaryFolder + separator + "ApplicationCache").get());
- WKContextSetDatabaseDirectory(m_context.get(), toWK(temporaryFolder + separator + "Databases").get());
- WKContextSetLocalStorageDirectory(m_context.get(), toWK(temporaryFolder + separator + "LocalStorage").get());
- WKContextSetDiskCacheDirectory(m_context.get(), toWK(temporaryFolder + separator + "Cache").get());
- WKContextSetCookieStorageDirectory(m_context.get(), toWK(temporaryFolder + separator + "Cookies").get());
- WKContextSetIconDatabasePath(m_context.get(), toWK(temporaryFolder + separator + "IconDatabase" + separator + "WebpageIcons.db").get());
+ WKContextConfigurationSetApplicationCacheDirectory(configuration.get(), toWK(temporaryFolder + separator + "ApplicationCache").get());
+ WKContextConfigurationSetDiskCacheDirectory(configuration.get(), toWK(temporaryFolder + separator + "Cache").get());
+ WKContextConfigurationSetIndexedDBDatabaseDirectory(configuration.get(), toWK(temporaryFolder + separator + "Databases" + separator + "IndexedDB").get());
+ WKContextConfigurationSetLocalStorageDirectory(configuration.get(), toWK(temporaryFolder + separator + "LocalStorage").get());
+ WKContextConfigurationSetWebSQLDatabaseDirectory(configuration.get(), toWK(temporaryFolder + separator + "Databases" + separator + "WebSQL").get());
+ WKContextConfigurationSetMediaKeysStorageDirectory(configuration.get(), toWK(temporaryFolder + separator + "MediaKeys").get());
+ }
+ return configuration;
+}
+
+WKRetainPtr<WKPageConfigurationRef> TestController::generatePageConfiguration(WKContextConfigurationRef configuration)
+{
+ m_context = platformAdjustContext(adoptWK(WKContextCreateWithConfiguration(configuration)).get(), configuration);
+
+ m_geolocationProvider = std::make_unique<GeolocationProviderMock>(m_context.get());
+
+ if (const char* dumpRenderTreeTemp = libraryPathForTesting()) {
+ String temporaryFolder = String::fromUTF8(dumpRenderTreeTemp);
+
+ // FIXME: This should be migrated to WKContextConfigurationRef.
+ // Disable icon database to avoid fetching <http://127.0.0.1:8000/favicon.ico> and making tests flaky.
+ // Invividual tests can enable it using testRunner.setIconDatabaseEnabled, although it's not currently supported in WebKitTestRunner.
+ WKContextSetIconDatabasePath(m_context.get(), toWK(emptyString()).get());
}
+ WKContextSetDiskCacheSpeculativeValidationEnabled(m_context.get(), true);
WKContextUseTestingNetworkSession(m_context.get());
WKContextSetCacheModel(m_context.get(), kWKCacheModelDocumentBrowser);
@@ -340,10 +426,30 @@ void TestController::initialize(int argc, const char* argv[])
{ 1, this },
didReceiveMessageFromInjectedBundle,
didReceiveSynchronousMessageFromInjectedBundle,
- 0 // getInjectedBundleInitializationUserData
+ getInjectedBundleInitializationUserData,
};
WKContextSetInjectedBundleClient(m_context.get(), &injectedBundleClient.base);
+ WKContextClientV2 contextClient = {
+ { 2, this },
+ 0, // plugInAutoStartOriginHashesChanged
+ networkProcessDidCrash,
+ 0, // plugInInformationBecameAvailable
+ 0, // copyWebCryptoMasterKey
+ databaseProcessDidCrash,
+ };
+ WKContextSetClient(m_context.get(), &contextClient.base);
+
+ WKContextHistoryClientV0 historyClient = {
+ { 0, this },
+ didNavigateWithNavigationData,
+ didPerformClientRedirect,
+ didPerformServerRedirect,
+ didUpdateHistoryTitle,
+ 0, // populateVisitedLinks
+ };
+ WKContextSetHistoryClient(m_context.get(), &historyClient.base);
+
WKNotificationManagerRef notificationManager = WKContextGetNotificationManager(m_context.get());
WKNotificationProviderV0 notificationKit = m_webNotificationProvider.provider();
WKNotificationManagerSetProvider(notificationManager, &notificationKit.base);
@@ -354,34 +460,40 @@ void TestController::initialize(int argc, const char* argv[])
if (m_forceComplexText)
WKContextSetAlwaysUsesComplexTextCodePath(m_context.get(), true);
- // Some preferences (notably mock scroll bars setting) currently cannot be re-applied to an existing view, so we need to set them now.
- resetPreferencesToConsistentValues();
-
- WKRetainPtr<WKMutableDictionaryRef> viewOptions;
- if (m_shouldUseRemoteLayerTree) {
- viewOptions = adoptWK(WKMutableDictionaryCreate());
- WKRetainPtr<WKStringRef> useRemoteLayerTreeKey = adoptWK(WKStringCreateWithUTF8CString("RemoteLayerTree"));
- WKRetainPtr<WKBooleanRef> useRemoteLayerTreeValue = adoptWK(WKBooleanCreate(m_shouldUseRemoteLayerTree));
- WKDictionarySetItem(viewOptions.get(), useRemoteLayerTreeKey.get(), useRemoteLayerTreeValue.get());
- }
-
- createWebViewWithOptions(viewOptions.get());
+ auto pageConfiguration = adoptWK(WKPageConfigurationCreate());
+ WKPageConfigurationSetContext(pageConfiguration.get(), m_context.get());
+ WKPageConfigurationSetPageGroup(pageConfiguration.get(), m_pageGroup.get());
+ WKPageConfigurationSetUserContentController(pageConfiguration.get(), adoptWK(WKUserContentControllerCreate()).get());
+ return pageConfiguration;
}
-void TestController::createWebViewWithOptions(WKDictionaryRef options)
+void TestController::createWebViewWithOptions(const TestOptions& options)
{
- m_mainWebView = adoptPtr(new PlatformWebView(m_context.get(), m_pageGroup.get(), 0, options));
- WKPageUIClientV2 pageUIClient = {
- { 2, m_mainWebView.get() },
+ auto contextConfiguration = generateContextConfiguration();
+
+ WKRetainPtr<WKMutableArrayRef> overrideLanguages = adoptWK(WKMutableArrayCreate());
+ for (auto& language : options.overrideLanguages)
+ WKArrayAppendItem(overrideLanguages.get(), adoptWK(WKStringCreateWithUTF8CString(language.utf8().data())).get());
+ WKContextConfigurationSetOverrideLanguages(contextConfiguration.get(), overrideLanguages.get());
+
+ auto configuration = generatePageConfiguration(contextConfiguration.get());
+
+ // Some preferences (notably mock scroll bars setting) currently cannot be re-applied to an existing view, so we need to set them now.
+ // FIXME: Migrate these preferences to WKContextConfigurationRef.
+ resetPreferencesToConsistentValues(options);
+
+ platformCreateWebView(configuration.get(), options);
+ WKPageUIClientV8 pageUIClient = {
+ { 8, m_mainWebView.get() },
0, // createNewPage_deprecatedForUseWithV0
0, // showPage
0, // close
0, // takeFocus
focus,
unfocus,
- 0, // runJavaScriptAlert
- 0, // runJavaScriptConfirm
- 0, // runJavaScriptPrompt
+ 0, // runJavaScriptAlert_deprecatedForUseWithV0
+ 0, // runJavaScriptAlert_deprecatedForUseWithV0
+ 0, // runJavaScriptAlert_deprecatedForUseWithV0
0, // setStatusText
0, // mouseDidMoveOverElement_deprecatedForUseWithV0
0, // missingPluginButtonClicked
@@ -401,7 +513,7 @@ void TestController::createWebViewWithOptions(WKDictionaryRef options)
0, // didDraw
0, // pageDidScroll
0, // exceededDatabaseQuota,
- 0, // runOpenPanel
+ runOpenPanel,
decidePolicyForGeolocationPermissionRequest,
0, // headerHeight
0, // footerHeight
@@ -412,98 +524,128 @@ void TestController::createWebViewWithOptions(WKDictionaryRef options)
0, // didCompleteRubberBandForMainFrame
0, // saveDataToFileInDownloadsFolder
0, // shouldInterruptJavaScript
- createOtherPage,
+ 0, // createNewPage_deprecatedForUseWithV1
0, // mouseDidMoveOverElement
decidePolicyForNotificationPermissionRequest, // decidePolicyForNotificationPermissionRequest
0, // unavailablePluginButtonClicked_deprecatedForUseWithV1
0, // showColorPicker
0, // hideColorPicker
unavailablePluginButtonClicked,
+ 0, // pinnedStateDidChange
+ 0, // didBeginTrackingPotentialLongMousePress
+ 0, // didRecognizeLongMousePress
+ 0, // didCancelTrackingPotentialLongMousePress
+ 0, // isPlayingAudioDidChange
+ decidePolicyForUserMediaPermissionRequest,
+ 0, // didClickAutofillButton
+ 0, // runJavaScriptAlert
+ 0, // runJavaScriptConfirm
+ 0, // runJavaScriptPrompt
+ 0, // mediaSessionMetadataDidChange
+ createOtherPage,
+ 0, // runJavaScriptAlert
+ 0, // runJavaScriptConfirm
+ 0, // runJavaScriptPrompt
+ checkUserMediaPermissionForOrigin,
+ 0, // runBeforeUnloadConfirmPanel
+ 0, // fullscreenMayReturnToInline
+ requestPointerLock,
+ 0,
};
WKPageSetPageUIClient(m_mainWebView->page(), &pageUIClient.base);
- WKPageLoaderClientV4 pageLoaderClient = {
- { 4, this },
- 0, // didStartProvisionalLoadForFrame
- 0, // didReceiveServerRedirectForProvisionalLoadForFrame
- 0, // didFailProvisionalLoadWithErrorForFrame
- didCommitLoadForFrame,
- 0, // didFinishDocumentLoadForFrame
- didFinishLoadForFrame,
- 0, // didFailLoadWithErrorForFrame
- 0, // didSameDocumentNavigationForFrame
- 0, // didReceiveTitleForFrame
- 0, // didFirstLayoutForFrame
- 0, // didFirstVisuallyNonEmptyLayoutForFrame
- 0, // didRemoveFrameFromHierarchy
- 0, // didFailToInitializePlugin
- 0, // didDisplayInsecureContentForFrame
- 0, // canAuthenticateAgainstProtectionSpaceInFrame
- didReceiveAuthenticationChallengeInFrame, // didReceiveAuthenticationChallengeInFrame
- 0, // didStartProgress
- 0, // didChangeProgress
- 0, // didFinishProgress
- 0, // didBecomeUnresponsive
- 0, // didBecomeResponsive
+ WKPageNavigationClientV0 pageNavigationClient = {
+ { 0, this },
+ decidePolicyForNavigationAction,
+ decidePolicyForNavigationResponse,
+ decidePolicyForPluginLoad,
+ 0, // didStartProvisionalNavigation
+ 0, // didReceiveServerRedirectForProvisionalNavigation
+ 0, // didFailProvisionalNavigation
+ didCommitNavigation,
+ didFinishNavigation,
+ 0, // didFailNavigation
+ 0, // didFailProvisionalLoadInSubframe
+ 0, // didFinishDocumentLoad
+ 0, // didSameDocumentNavigation
+ 0, // renderingProgressDidChange
+ canAuthenticateAgainstProtectionSpace,
+ didReceiveAuthenticationChallenge,
processDidCrash,
- 0, // didChangeBackForwardList
- 0, // shouldGoToBackForwardListItem
- 0, // didRunInsecureContentForFrame
- 0, // didDetectXSSForFrame
- 0, // didNewFirstVisuallyNonEmptyLayout_unavailable
- 0, // willGoToBackForwardListItem
- 0, // interactionOccurredWhileProcessUnresponsive
- 0, // pluginDidFail_deprecatedForUseWithV1
- 0, // didReceiveIntentForFrame
- 0, // registerIntentServiceForFrame
- 0, // didLayout
- 0, // pluginLoadPolicy_deprecatedForUseWithV2
- 0, // pluginDidFail
- pluginLoadPolicy, // pluginLoadPolicy
- 0, // webGLLoadPolicy
+ copyWebCryptoMasterKey,
+ didBeginNavigationGesture,
+ willEndNavigationGesture,
+ didEndNavigationGesture,
+ didRemoveNavigationGestureSnapshot
};
- WKPageSetPageLoaderClient(m_mainWebView->page(), &pageLoaderClient.base);
-
- WKPagePolicyClientV1 pagePolicyClient = {
- { 1, this },
- 0, // decidePolicyForNavigationAction_deprecatedForUseWithV0
- 0, // decidePolicyForNewWindowAction
- 0, // decidePolicyForResponse_deprecatedForUseWithV0
- 0, // unableToImplementPolicy
- decidePolicyForNavigationAction,
- decidePolicyForResponse,
+ WKPageSetPageNavigationClient(m_mainWebView->page(), &pageNavigationClient.base);
+
+ WKContextDownloadClientV0 downloadClient = {
+ { 0, this },
+ downloadDidStart,
+ 0, // didReceiveAuthenticationChallenge
+ 0, // didReceiveResponse
+ 0, // didReceiveData
+ 0, // shouldDecodeSourceDataOfMIMEType
+ decideDestinationWithSuggestedFilename,
+ 0, // didCreateDestination
+ downloadDidFinish,
+ downloadDidFail,
+ downloadDidCancel,
+ 0 // processDidCrash;
+ };
+ WKContextSetDownloadClient(context(), &downloadClient.base);
+
+ // this should just be done on the page?
+ WKPageInjectedBundleClientV0 injectedBundleClient = {
+ { 0, this },
+ didReceivePageMessageFromInjectedBundle,
+ didReceiveSynchronousPageMessageFromInjectedBundle
};
- WKPageSetPagePolicyClient(m_mainWebView->page(), &pagePolicyClient.base);
+ WKPageSetPageInjectedBundleClient(m_mainWebView->page(), &injectedBundleClient.base);
m_mainWebView->didInitializeClients();
+
+ // Generally, the tests should default to running at 1x. updateWindowScaleForTest() will adjust the scale to
+ // something else for specific tests that need to run at a different window scale.
+ m_mainWebView->changeWindowScaleIfNeeded(1);
}
-void TestController::ensureViewSupportsOptions(WKDictionaryRef options)
+void TestController::ensureViewSupportsOptionsForTest(const TestInvocation& test)
{
- if (m_mainWebView && !m_mainWebView->viewSupportsOptions(options)) {
- WKPageSetPageUIClient(m_mainWebView->page(), 0);
- WKPageSetPageLoaderClient(m_mainWebView->page(), 0);
- WKPageSetPagePolicyClient(m_mainWebView->page(), 0);
+ auto options = test.options();
+
+ if (m_mainWebView) {
+ if (m_mainWebView->viewSupportsOptions(options))
+ return;
+
+ WKPageSetPageUIClient(m_mainWebView->page(), nullptr);
+ WKPageSetPageNavigationClient(m_mainWebView->page(), nullptr);
WKPageClose(m_mainWebView->page());
-
- m_mainWebView = nullptr;
- createWebViewWithOptions(options);
- resetStateToConsistentValues();
+ m_mainWebView = nullptr;
}
+
+ createWebViewWithOptions(options);
+
+ if (!resetStateToConsistentValues(options))
+ TestInvocation::dumpWebProcessUnresponsiveness("<unknown> - TestController::run - Failed to reset state to consistent values\n");
}
-void TestController::resetPreferencesToConsistentValues()
+void TestController::resetPreferencesToConsistentValues(const TestOptions& options)
{
// Reset preferences
- WKPreferencesRef preferences = WKPageGroupGetPreferences(m_pageGroup.get());
+ WKPreferencesRef preferences = platformPreferences();
WKPreferencesResetTestRunnerOverrides(preferences);
+ WKPreferencesEnableAllExperimentalFeatures(preferences);
+ WKPreferencesSetPageVisibilityBasedProcessSuppressionEnabled(preferences, false);
WKPreferencesSetOfflineWebApplicationCacheEnabled(preferences, true);
WKPreferencesSetFontSmoothingLevel(preferences, kWKFontSmoothingLevelNoSubpixelAntiAliasing);
WKPreferencesSetXSSAuditorEnabled(preferences, false);
WKPreferencesSetWebAudioEnabled(preferences, true);
+ WKPreferencesSetMediaStreamEnabled(preferences, true);
WKPreferencesSetDeveloperExtrasEnabled(preferences, true);
- WKPreferencesSetJavaScriptExperimentsEnabled(preferences, true);
+ WKPreferencesSetJavaScriptRuntimeFlags(preferences, kWKJavaScriptRuntimeFlagsAllEnabled);
WKPreferencesSetJavaScriptCanOpenWindowsAutomatically(preferences, true);
WKPreferencesSetJavaScriptCanAccessClipboard(preferences, true);
WKPreferencesSetDOMPasteAllowed(preferences, true);
@@ -518,7 +660,14 @@ void TestController::resetPreferencesToConsistentValues()
WKPreferencesSetArtificialPluginInitializationDelayEnabled(preferences, false);
WKPreferencesSetTabToLinksEnabled(preferences, false);
WKPreferencesSetInteractiveFormValidationEnabled(preferences, true);
- WKPreferencesSetMockScrollbarsEnabled(preferences, true);
+
+ WKPreferencesSetMockScrollbarsEnabled(preferences, options.useMockScrollbars);
+ WKPreferencesSetNeedsSiteSpecificQuirks(preferences, options.needsSiteSpecificQuirks);
+ WKPreferencesSetIntersectionObserverEnabled(preferences, options.enableIntersectionObserver);
+ WKPreferencesSetModernMediaControlsEnabled(preferences, options.enableModernMediaControls);
+
+ static WKStringRef defaultTextEncoding = WKStringCreateWithUTF8CString("ISO-8859-1");
+ WKPreferencesSetDefaultTextEncodingName(preferences, defaultTextEncoding);
static WKStringRef standardFontFamily = WKStringCreateWithUTF8CString("Times");
static WKStringRef cursiveFontFamily = WKStringCreateWithUTF8CString("Apple Chancery");
@@ -528,6 +677,7 @@ void TestController::resetPreferencesToConsistentValues()
static WKStringRef sansSerifFontFamily = WKStringCreateWithUTF8CString("Helvetica");
static WKStringRef serifFontFamily = WKStringCreateWithUTF8CString("Times");
+ WKPreferencesSetMinimumFontSize(preferences, 0);
WKPreferencesSetStandardFontFamily(preferences, standardFontFamily);
WKPreferencesSetCursiveFontFamily(preferences, cursiveFontFamily);
WKPreferencesSetFantasyFontFamily(preferences, fantasyFontFamily);
@@ -535,21 +685,40 @@ void TestController::resetPreferencesToConsistentValues()
WKPreferencesSetPictographFontFamily(preferences, pictographFontFamily);
WKPreferencesSetSansSerifFontFamily(preferences, sansSerifFontFamily);
WKPreferencesSetSerifFontFamily(preferences, serifFontFamily);
- WKPreferencesSetScreenFontSubstitutionEnabled(preferences, true);
WKPreferencesSetAsynchronousSpellCheckingEnabled(preferences, false);
#if ENABLE(WEB_AUDIO)
WKPreferencesSetMediaSourceEnabled(preferences, true);
#endif
+ WKPreferencesSetHiddenPageDOMTimerThrottlingEnabled(preferences, false);
+ WKPreferencesSetHiddenPageCSSAnimationSuspensionEnabled(preferences, false);
+
WKPreferencesSetAcceleratedDrawingEnabled(preferences, m_shouldUseAcceleratedDrawing);
+ // FIXME: We should be testing the default.
+ WKPreferencesSetStorageBlockingPolicy(preferences, kWKAllowAllStorage);
+
+ WKPreferencesSetResourceTimingEnabled(preferences, true);
+
+ WKPreferencesSetMediaPlaybackAllowsInline(preferences, true);
+ WKPreferencesSetInlineMediaPlaybackRequiresPlaysInlineAttribute(preferences, false);
+
+ WKCookieManagerDeleteAllCookies(WKContextGetCookieManager(m_context.get()));
+
+ WKPreferencesSetMockCaptureDevicesEnabled(preferences, true);
+
+ platformResetPreferencesToConsistentValues();
}
-bool TestController::resetStateToConsistentValues()
+bool TestController::resetStateToConsistentValues(const TestOptions& options)
{
- m_state = Resetting;
-
+ SetForScope<State> changeState(m_state, Resetting);
m_beforeUnloadReturnValue = true;
+ // This setting differs between the antique and modern Mac WebKit2 API.
+ // For now, maintain the antique behavior, because some tests depend on it!
+ // FIXME: We should be testing the default.
+ WKPageSetBackgroundExtendsBeyondPage(m_mainWebView->page(), false);
+
WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("Reset"));
WKRetainPtr<WKMutableDictionaryRef> resetMessageBody = adoptWK(WKMutableDictionaryCreate());
@@ -557,39 +726,58 @@ bool TestController::resetStateToConsistentValues()
WKRetainPtr<WKBooleanRef> shouldGCValue = adoptWK(WKBooleanCreate(m_gcBetweenTests));
WKDictionarySetItem(resetMessageBody.get(), shouldGCKey.get(), shouldGCValue.get());
- WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), resetMessageBody.get());
+ WKRetainPtr<WKStringRef> allowedHostsKey = adoptWK(WKStringCreateWithUTF8CString("AllowedHosts"));
+ WKRetainPtr<WKMutableArrayRef> allowedHostsValue = adoptWK(WKMutableArrayCreate());
+ for (auto& host : m_allowedHosts) {
+ WKRetainPtr<WKStringRef> wkHost = adoptWK(WKStringCreateWithUTF8CString(host.c_str()));
+ WKArrayAppendItem(allowedHostsValue.get(), wkHost.get());
+ }
+ WKDictionarySetItem(resetMessageBody.get(), allowedHostsKey.get(), allowedHostsValue.get());
+
+ WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), resetMessageBody.get());
+
+ WKContextSetShouldUseFontSmoothing(TestController::singleton().context(), false);
- WKContextSetShouldUseFontSmoothing(TestController::shared().context(), false);
+ WKContextSetCacheModel(TestController::singleton().context(), kWKCacheModelDocumentBrowser);
- WKContextSetCacheModel(TestController::shared().context(), kWKCacheModelDocumentBrowser);
+ WKContextClearCachedCredentials(TestController::singleton().context());
// FIXME: This function should also ensure that there is only one page open.
// Reset the EventSender for each test.
- m_eventSenderProxy = adoptPtr(new EventSenderProxy(this));
+ m_eventSenderProxy = std::make_unique<EventSenderProxy>(this);
// FIXME: Is this needed? Nothing in TestController changes preferences during tests, and if there is
// some other code doing this, it should probably be responsible for cleanup too.
- resetPreferencesToConsistentValues();
+ resetPreferencesToConsistentValues(options);
-#if !PLATFORM(MAC)
+#if !PLATFORM(COCOA)
WKTextCheckerContinuousSpellCheckingEnabledStateChanged(true);
#endif
- // in the case that a test using the chrome input field failed, be sure to clean up for the next test
+ // Make sure the view is in the window (a test can unparent it).
+ m_mainWebView->addToWindow();
+
+ // In the case that a test using the chrome input field failed, be sure to clean up for the next test.
m_mainWebView->removeChromeInputField();
m_mainWebView->focus();
// Re-set to the default backing scale factor by setting the custom scale factor to 0.
WKPageSetCustomBackingScaleFactor(m_mainWebView->page(), 0);
+ WKPageClearWheelEventTestTrigger(m_mainWebView->page());
+
#if PLATFORM(EFL)
- // EFL use a real window while other ports such as Qt don't.
+ // EFL uses a real window while other ports such as Qt don't.
// In EFL, we need to resize the window to the original size after calls to window.resizeTo.
WKRect rect = m_mainWebView->windowFrame();
m_mainWebView->setWindowFrame(WKRectMake(rect.origin.x, rect.origin.y, TestController::viewWidth, TestController::viewHeight));
#endif
+ WKPageSetMuted(m_mainWebView->page(), true);
+
+ WKPageClearUserMediaState(m_mainWebView->page());
+
// Reset notification permissions
m_webNotificationProvider.reset();
@@ -598,33 +786,250 @@ bool TestController::resetStateToConsistentValues()
m_isGeolocationPermissionSet = false;
m_isGeolocationPermissionAllowed = false;
+ // Reset UserMedia permissions.
+ m_userMediaPermissionRequests.clear();
+ m_cachedUserMediaPermissions.clear();
+ m_isUserMediaPermissionSet = false;
+ m_isUserMediaPermissionAllowed = false;
+
// Reset Custom Policy Delegate.
setCustomPolicyDelegate(false, false);
+ m_shouldDownloadUndisplayableMIMETypes = false;
+
m_workQueueManager.clearWorkQueue();
+ m_rejectsProtectionSpaceAndContinueForAuthenticationChallenges = false;
m_handlesAuthenticationChallenges = false;
m_authenticationUsername = String();
m_authenticationPassword = String();
m_shouldBlockAllPlugins = false;
+ m_shouldLogHistoryClientCallbacks = false;
+ m_shouldLogCanAuthenticateAgainstProtectionSpace = false;
+
+ setHidden(false);
+
+ platformResetStateToConsistentValues();
+
// Reset main page back to about:blank
m_doneResetting = false;
+ m_shouldDecideNavigationPolicyAfterDelay = false;
+
+ setNavigationGesturesEnabled(false);
+
+ setIgnoresViewportScaleLimits(options.ignoresViewportScaleLimits);
+
WKPageLoadURL(m_mainWebView->page(), blankURL());
- runUntil(m_doneResetting, ShortTimeout);
+ runUntil(m_doneResetting, m_currentInvocation->shortTimeout());
return m_doneResetting;
}
-struct TestCommand {
- TestCommand() : shouldDumpPixels(false), timeout(0) { }
+void TestController::terminateWebContentProcess()
+{
+ WKPageTerminate(m_mainWebView->page());
+}
- std::string pathOrURL;
- bool shouldDumpPixels;
- std::string expectedPixelHash;
- int timeout;
-};
+void TestController::reattachPageToWebProcess()
+{
+ // Loading a web page is the only way to reattach an existing page to a process.
+ m_doneResetting = false;
+ WKPageLoadURL(m_mainWebView->page(), blankURL());
+ runUntil(m_doneResetting, m_currentInvocation->shortTimeout());
+}
+
+const char* TestController::webProcessName()
+{
+ // FIXME: Find a way to not hardcode the process name.
+#if PLATFORM(COCOA)
+ return "com.apple.WebKit.WebContent.Development";
+#else
+ return "WebProcess";
+#endif
+}
+
+const char* TestController::networkProcessName()
+{
+ // FIXME: Find a way to not hardcode the process name.
+#if PLATFORM(COCOA)
+ return "com.apple.WebKit.Networking.Development";
+#else
+ return "NetworkProcess";
+#endif
+}
+
+const char* TestController::databaseProcessName()
+{
+ // FIXME: Find a way to not hardcode the process name.
+#if PLATFORM(COCOA)
+ return "com.apple.WebKit.Databases.Development";
+#else
+ return "DatabaseProcess";
+#endif
+}
+
+static std::string testPath(WKURLRef url)
+{
+ auto scheme = adoptWK(WKURLCopyScheme(url));
+ if (WKStringIsEqualToUTF8CStringIgnoringCase(scheme.get(), "file")) {
+ auto path = adoptWK(WKURLCopyPath(url));
+ auto buffer = std::vector<char>(WKStringGetMaximumUTF8CStringSize(path.get()));
+ auto length = WKStringGetUTF8CString(path.get(), buffer.data(), buffer.size());
+ return std::string(buffer.data(), length);
+ }
+ return std::string();
+}
+
+static WKURLRef createTestURL(const char* pathOrURL)
+{
+ if (strstr(pathOrURL, "http://") || strstr(pathOrURL, "https://") || strstr(pathOrURL, "file://"))
+ return WKURLCreateWithUTF8CString(pathOrURL);
+
+ // Creating from filesytem path.
+ size_t length = strlen(pathOrURL);
+ if (!length)
+ return 0;
+
+ const char separator = '/';
+ bool isAbsolutePath = pathOrURL[0] == separator;
+ const char* filePrefix = "file://";
+ static const size_t prefixLength = strlen(filePrefix);
+
+ std::unique_ptr<char[]> buffer;
+ if (isAbsolutePath) {
+ buffer = std::make_unique<char[]>(prefixLength + length + 1);
+ strcpy(buffer.get(), filePrefix);
+ strcpy(buffer.get() + prefixLength, pathOrURL);
+ } else {
+ buffer = std::make_unique<char[]>(prefixLength + PATH_MAX + length + 2); // 1 for the separator
+ strcpy(buffer.get(), filePrefix);
+ if (!getcwd(buffer.get() + prefixLength, PATH_MAX))
+ return 0;
+ size_t numCharacters = strlen(buffer.get());
+ buffer[numCharacters] = separator;
+ strcpy(buffer.get() + numCharacters + 1, pathOrURL);
+ }
+
+ return WKURLCreateWithUTF8CString(buffer.get());
+}
+
+static bool parseBooleanTestHeaderValue(const std::string& value)
+{
+ if (value == "true")
+ return true;
+ if (value == "false")
+ return false;
+
+ LOG_ERROR("Found unexpected value '%s' for boolean option. Expected 'true' or 'false'.", value.c_str());
+ return false;
+}
+
+static void updateTestOptionsFromTestHeader(TestOptions& testOptions, const std::string& pathOrURL, const std::string& absolutePath)
+{
+ std::string filename = absolutePath;
+ if (filename.empty()) {
+ // Gross. Need to reduce conversions between all the string types and URLs.
+ WKRetainPtr<WKURLRef> wkURL(AdoptWK, createTestURL(pathOrURL.c_str()));
+ filename = testPath(wkURL.get());
+ }
+
+ if (filename.empty())
+ return;
+
+ std::string options;
+ std::ifstream testFile(filename.data());
+ if (!testFile.good())
+ return;
+ getline(testFile, options);
+ std::string beginString("webkit-test-runner [ ");
+ std::string endString(" ]");
+ size_t beginLocation = options.find(beginString);
+ if (beginLocation == std::string::npos)
+ return;
+ size_t endLocation = options.find(endString, beginLocation);
+ if (endLocation == std::string::npos) {
+ LOG_ERROR("Could not find end of test header in %s", filename.c_str());
+ return;
+ }
+ std::string pairString = options.substr(beginLocation + beginString.size(), endLocation - (beginLocation + beginString.size()));
+ size_t pairStart = 0;
+ while (pairStart < pairString.size()) {
+ size_t pairEnd = pairString.find(" ", pairStart);
+ if (pairEnd == std::string::npos)
+ pairEnd = pairString.size();
+ size_t equalsLocation = pairString.find("=", pairStart);
+ if (equalsLocation == std::string::npos) {
+ LOG_ERROR("Malformed option in test header (could not find '=' character) in %s", filename.c_str());
+ break;
+ }
+ auto key = pairString.substr(pairStart, equalsLocation - pairStart);
+ auto value = pairString.substr(equalsLocation + 1, pairEnd - (equalsLocation + 1));
+ if (key == "language")
+ String(value.c_str()).split(",", false, testOptions.overrideLanguages);
+ if (key == "useThreadedScrolling")
+ testOptions.useThreadedScrolling = parseBooleanTestHeaderValue(value);
+ if (key == "useFlexibleViewport")
+ testOptions.useFlexibleViewport = parseBooleanTestHeaderValue(value);
+ if (key == "useDataDetection")
+ testOptions.useDataDetection = parseBooleanTestHeaderValue(value);
+ if (key == "useMockScrollbars")
+ testOptions.useMockScrollbars = parseBooleanTestHeaderValue(value);
+ if (key == "needsSiteSpecificQuirks")
+ testOptions.needsSiteSpecificQuirks = parseBooleanTestHeaderValue(value);
+ if (key == "ignoresViewportScaleLimits")
+ testOptions.ignoresViewportScaleLimits = parseBooleanTestHeaderValue(value);
+ if (key == "useCharacterSelectionGranularity")
+ testOptions.useCharacterSelectionGranularity = parseBooleanTestHeaderValue(value);
+ if (key == "enableIntersectionObserver")
+ testOptions.enableIntersectionObserver = parseBooleanTestHeaderValue(value);
+ if (key == "enableModernMediaControls")
+ testOptions.enableModernMediaControls = parseBooleanTestHeaderValue(value);
+ if (key == "enablePointerLock")
+ testOptions.enablePointerLock = parseBooleanTestHeaderValue(value);
+ pairStart = pairEnd + 1;
+ }
+}
+
+TestOptions TestController::testOptionsForTest(const TestCommand& command) const
+{
+ TestOptions options(command.pathOrURL);
+
+ options.useRemoteLayerTree = m_shouldUseRemoteLayerTree;
+ options.shouldShowWebView = m_shouldShowWebView;
+
+ updatePlatformSpecificTestOptionsForTest(options, command.pathOrURL);
+ updateTestOptionsFromTestHeader(options, command.pathOrURL, command.absolutePath);
+
+ return options;
+}
+
+void TestController::updateWebViewSizeForTest(const TestInvocation& test)
+{
+ unsigned width = viewWidth;
+ unsigned height = viewHeight;
+ if (test.options().isSVGTest) {
+ width = w3cSVGViewWidth;
+ height = w3cSVGViewHeight;
+ }
+
+ mainWebView()->resizeTo(width, height);
+}
+
+void TestController::updateWindowScaleForTest(PlatformWebView* view, const TestInvocation& test)
+{
+ view->changeWindowScaleIfNeeded(test.options().deviceScaleFactor);
+}
+
+void TestController::configureViewForTest(const TestInvocation& test)
+{
+ ensureViewSupportsOptionsForTest(test);
+ updateWebViewSizeForTest(test);
+ updateWindowScaleForTest(mainWebView(), test);
+
+ platformConfigureViewForTest(test);
+}
class CommandTokenizer {
public:
@@ -696,7 +1101,11 @@ TestCommand parseInputLine(const std::string& inputLine)
result.shouldDumpPixels = true;
if (tokenizer.hasNext())
result.expectedPixelHash = tokenizer.next();
- } else
+ } else if (arg == std::string("--dump-jsconsolelog-in-stderr"))
+ result.dumpJSConsoleLogInStdErr = true;
+ else if (arg == std::string("--absolutePath"))
+ result.absolutePath = tokenizer.next();
+ else
die(inputLine);
}
return result;
@@ -704,18 +1113,26 @@ TestCommand parseInputLine(const std::string& inputLine)
bool TestController::runTest(const char* inputLine)
{
+ WKTextCheckerSetTestingMode(true);
TestCommand command = parseInputLine(std::string(inputLine));
m_state = RunningTest;
+
+ TestOptions options = testOptionsForTest(command);
+
+ WKRetainPtr<WKURLRef> wkURL(AdoptWK, createTestURL(command.pathOrURL.c_str()));
+ m_currentInvocation = std::make_unique<TestInvocation>(wkURL.get(), options);
- m_currentInvocation = adoptPtr(new TestInvocation(command.pathOrURL));
if (command.shouldDumpPixels || m_shouldDumpPixelsForAllTests)
m_currentInvocation->setIsPixelTest(command.expectedPixelHash);
if (command.timeout > 0)
m_currentInvocation->setCustomTimeout(command.timeout);
+ m_currentInvocation->setDumpJSConsoleLogInStdErr(command.dumpJSConsoleLogInStdErr);
+
+ platformWillRunTest(*m_currentInvocation);
m_currentInvocation->invoke();
- m_currentInvocation.clear();
+ m_currentInvocation = nullptr;
return true;
}
@@ -738,11 +1155,6 @@ void TestController::runTestingServerLoop()
void TestController::run()
{
- if (!resetStateToConsistentValues()) {
- TestInvocation::dumpWebProcessUnresponsiveness("<unknown> - TestController::run - Failed to reset state to consistent values\n");
- return;
- }
-
if (m_usingServerMode)
runTestingServerLoop();
else {
@@ -753,26 +1165,10 @@ void TestController::run()
}
}
-void TestController::runUntil(bool& done, TimeoutDuration timeoutDuration)
+void TestController::runUntil(bool& done, double timeout)
{
- double timeout = m_noTimeout;
- if (!m_forceNoTimeout) {
- switch (timeoutDuration) {
- case ShortTimeout:
- timeout = m_shortTimeout;
- break;
- case LongTimeout:
- timeout = m_longTimeout;
- break;
- case CustomTimeout:
- timeout = m_timeout;
- break;
- case NoTimeout:
- default:
- timeout = m_noTimeout;
- break;
- }
- }
+ if (m_forceNoTimeout)
+ timeout = noTimeout;
platformRunUntil(done, timeout);
}
@@ -789,6 +1185,33 @@ void TestController::didReceiveSynchronousMessageFromInjectedBundle(WKContextRef
*returnData = static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody).leakRef();
}
+WKTypeRef TestController::getInjectedBundleInitializationUserData(WKContextRef, const void* clientInfo)
+{
+ return static_cast<TestController*>(const_cast<void*>(clientInfo))->getInjectedBundleInitializationUserData().leakRef();
+}
+
+// WKPageInjectedBundleClient
+
+void TestController::didReceivePageMessageFromInjectedBundle(WKPageRef page, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo)
+{
+ static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveMessageFromInjectedBundle(messageName, messageBody);
+}
+
+void TestController::didReceiveSynchronousPageMessageFromInjectedBundle(WKPageRef page, WKStringRef messageName, WKTypeRef messageBody, WKTypeRef* returnData, const void* clientInfo)
+{
+ *returnData = static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody).leakRef();
+}
+
+void TestController::networkProcessDidCrash(WKContextRef context, const void *clientInfo)
+{
+ static_cast<TestController*>(const_cast<void*>(clientInfo))->networkProcessDidCrash();
+}
+
+void TestController::databaseProcessDidCrash(WKContextRef context, const void *clientInfo)
+{
+ static_cast<TestController*>(const_cast<void*>(clientInfo))->databaseProcessDidCrash();
+}
+
void TestController::didReceiveKeyDownMessageFromInjectedBundle(WKDictionaryRef messageBodyDictionary, bool synchronous)
{
WKRetainPtr<WKStringRef> keyKey = adoptWK(WKStringCreateWithUTF8CString("Key"));
@@ -800,18 +1223,15 @@ void TestController::didReceiveKeyDownMessageFromInjectedBundle(WKDictionaryRef
WKRetainPtr<WKStringRef> locationKey = adoptWK(WKStringCreateWithUTF8CString("Location"));
unsigned location = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, locationKey.get()))));
- if (synchronous)
- WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
-
m_eventSenderProxy->keyDown(key, modifiers, location);
-
- if (synchronous)
- WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
}
void TestController::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
{
if (WKStringIsEqualToUTF8CString(messageName, "EventSender")) {
+ if (m_state != RunningTest)
+ return;
+
ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
@@ -826,7 +1246,6 @@ void TestController::didReceiveMessageFromInjectedBundle(WKStringRef messageName
WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
// Forward to WebProcess
- WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown"))
m_eventSenderProxy->mouseDown(button, modifiers);
else
@@ -841,6 +1260,53 @@ void TestController::didReceiveMessageFromInjectedBundle(WKStringRef messageName
return;
}
+ if (WKStringIsEqualToUTF8CString(subMessageName, "MouseScrollBy")) {
+ WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
+ double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
+
+ WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
+ double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
+
+ // Forward to WebProcess
+ m_eventSenderProxy->mouseScrollBy(x, y);
+ return;
+ }
+
+ if (WKStringIsEqualToUTF8CString(subMessageName, "MouseScrollByWithWheelAndMomentumPhases")) {
+ WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
+ double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
+
+ WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
+ double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
+
+ WKRetainPtr<WKStringRef> phaseKey = adoptWK(WKStringCreateWithUTF8CString("Phase"));
+ int phase = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, phaseKey.get()))));
+ WKRetainPtr<WKStringRef> momentumKey = adoptWK(WKStringCreateWithUTF8CString("Momentum"));
+ int momentum = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, momentumKey.get()))));
+
+ // Forward to WebProcess
+ m_eventSenderProxy->mouseScrollByWithWheelAndMomentumPhases(x, y, phase, momentum);
+
+ return;
+ }
+
+ if (WKStringIsEqualToUTF8CString(subMessageName, "SwipeGestureWithWheelAndMomentumPhases")) {
+ WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
+ double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
+
+ WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
+ double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
+
+ WKRetainPtr<WKStringRef> phaseKey = adoptWK(WKStringCreateWithUTF8CString("Phase"));
+ int phase = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, phaseKey.get()))));
+ WKRetainPtr<WKStringRef> momentumKey = adoptWK(WKStringCreateWithUTF8CString("Momentum"));
+ int momentum = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, momentumKey.get()))));
+
+ m_eventSenderProxy->swipeGestureWithWheelAndMomentumPhases(x, y, phase, momentum);
+
+ return;
+ }
+
ASSERT_NOT_REACHED();
}
@@ -853,6 +1319,9 @@ void TestController::didReceiveMessageFromInjectedBundle(WKStringRef messageName
WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
{
if (WKStringIsEqualToUTF8CString(messageName, "EventSender")) {
+ if (m_state != RunningTest)
+ return nullptr;
+
ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
@@ -873,12 +1342,10 @@ WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedB
WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get()))));
// Forward to WebProcess
- WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown"))
m_eventSenderProxy->mouseDown(button, modifiers);
else
m_eventSenderProxy->mouseUp(button, modifiers);
- WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
return 0;
}
@@ -890,25 +1357,39 @@ WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedB
double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
// Forward to WebProcess
- WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
m_eventSenderProxy->mouseMoveTo(x, y);
- WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
return 0;
}
- if (WKStringIsEqualToUTF8CString(subMessageName, "MouseScrollBy")) {
- WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
- double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get())));
+#if PLATFORM(MAC)
+ if (WKStringIsEqualToUTF8CString(subMessageName, "MouseForceClick")) {
+ m_eventSenderProxy->mouseForceClick();
+ return 0;
+ }
- WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y"));
- double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get())));
+ if (WKStringIsEqualToUTF8CString(subMessageName, "StartAndCancelMouseForceClick")) {
+ m_eventSenderProxy->startAndCancelMouseForceClick();
+ return 0;
+ }
- // Forward to WebProcess
- WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
- m_eventSenderProxy->mouseScrollBy(x, y);
- WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
+ if (WKStringIsEqualToUTF8CString(subMessageName, "MouseForceDown")) {
+ m_eventSenderProxy->mouseForceDown();
+ return 0;
+ }
+
+ if (WKStringIsEqualToUTF8CString(subMessageName, "MouseForceUp")) {
+ m_eventSenderProxy->mouseForceUp();
+ return 0;
+ }
+
+ if (WKStringIsEqualToUTF8CString(subMessageName, "MouseForceChanged")) {
+ WKRetainPtr<WKStringRef> forceKey = adoptWK(WKStringCreateWithUTF8CString("Force"));
+ double force = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, forceKey.get())));
+
+ m_eventSenderProxy->mouseForceChanged(force);
return 0;
}
+#endif // PLATFORM(MAC)
if (WKStringIsEqualToUTF8CString(subMessageName, "ContinuousMouseScrollBy")) {
WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X"));
@@ -921,9 +1402,7 @@ WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedB
bool paged = static_cast<bool>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, pagedKey.get()))));
// Forward to WebProcess
- WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
m_eventSenderProxy->continuousMouseScrollBy(x, y, paged);
- WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
return 0;
}
@@ -984,30 +1463,22 @@ WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedB
}
if (WKStringIsEqualToUTF8CString(subMessageName, "TouchStart")) {
- WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
m_eventSenderProxy->touchStart();
- WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
return 0;
}
if (WKStringIsEqualToUTF8CString(subMessageName, "TouchMove")) {
- WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
m_eventSenderProxy->touchMove();
- WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
return 0;
}
if (WKStringIsEqualToUTF8CString(subMessageName, "TouchEnd")) {
- WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
m_eventSenderProxy->touchEnd();
- WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
return 0;
}
if (WKStringIsEqualToUTF8CString(subMessageName, "TouchCancel")) {
- WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true);
m_eventSenderProxy->touchCancel();
- WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false);
return 0;
}
@@ -1035,21 +1506,47 @@ WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedB
return m_currentInvocation->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody);
}
-// WKPageLoaderClient
+WKRetainPtr<WKTypeRef> TestController::getInjectedBundleInitializationUserData()
+{
+ return nullptr;
+}
-void TestController::didCommitLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef, const void* clientInfo)
+// WKContextClient
+
+void TestController::networkProcessDidCrash()
{
- static_cast<TestController*>(const_cast<void*>(clientInfo))->didCommitLoadForFrame(page, frame);
+ pid_t pid = WKContextGetNetworkProcessIdentifier(m_context.get());
+ fprintf(stderr, "#CRASHED - %s (pid %ld)\n", networkProcessName(), static_cast<long>(pid));
+ exit(1);
}
-void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef, const void* clientInfo)
+void TestController::databaseProcessDidCrash()
{
- static_cast<TestController*>(const_cast<void*>(clientInfo))->didFinishLoadForFrame(page, frame);
+ pid_t pid = WKContextGetDatabaseProcessIdentifier(m_context.get());
+ fprintf(stderr, "#CRASHED - %s (pid %ld)\n", databaseProcessName(), static_cast<long>(pid));
+ exit(1);
}
-void TestController::didReceiveAuthenticationChallengeInFrame(WKPageRef page, WKFrameRef frame, WKAuthenticationChallengeRef authenticationChallenge, const void *clientInfo)
+// WKPageNavigationClient
+
+void TestController::didCommitNavigation(WKPageRef page, WKNavigationRef navigation, WKTypeRef, const void* clientInfo)
{
- static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveAuthenticationChallengeInFrame(page, frame, authenticationChallenge);
+ static_cast<TestController*>(const_cast<void*>(clientInfo))->didCommitNavigation(page, navigation);
+}
+
+void TestController::didFinishNavigation(WKPageRef page, WKNavigationRef navigation, WKTypeRef, const void* clientInfo)
+{
+ static_cast<TestController*>(const_cast<void*>(clientInfo))->didFinishNavigation(page, navigation);
+}
+
+bool TestController::canAuthenticateAgainstProtectionSpace(WKPageRef page, WKProtectionSpaceRef protectionSpace, const void* clientInfo)
+{
+ return static_cast<TestController*>(const_cast<void*>(clientInfo))->canAuthenticateAgainstProtectionSpace(page, protectionSpace);
+}
+
+void TestController::didReceiveAuthenticationChallenge(WKPageRef page, WKAuthenticationChallengeRef authenticationChallenge, const void *clientInfo)
+{
+ static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveAuthenticationChallenge(page, /*frame,*/ authenticationChallenge);
}
void TestController::processDidCrash(WKPageRef page, const void* clientInfo)
@@ -1057,52 +1554,114 @@ void TestController::processDidCrash(WKPageRef page, const void* clientInfo)
static_cast<TestController*>(const_cast<void*>(clientInfo))->processDidCrash();
}
-WKPluginLoadPolicy TestController::pluginLoadPolicy(WKPageRef page, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription, const void* clientInfo)
+void TestController::didBeginNavigationGesture(WKPageRef page, const void *clientInfo)
+{
+ static_cast<TestController*>(const_cast<void*>(clientInfo))->didBeginNavigationGesture(page);
+}
+
+void TestController::willEndNavigationGesture(WKPageRef page, WKBackForwardListItemRef backForwardListItem, const void *clientInfo)
+{
+ static_cast<TestController*>(const_cast<void*>(clientInfo))->willEndNavigationGesture(page, backForwardListItem);
+}
+
+void TestController::didEndNavigationGesture(WKPageRef page, WKBackForwardListItemRef backForwardListItem, const void *clientInfo)
+{
+ static_cast<TestController*>(const_cast<void*>(clientInfo))->didEndNavigationGesture(page, backForwardListItem);
+}
+
+void TestController::didRemoveNavigationGestureSnapshot(WKPageRef page, const void *clientInfo)
+{
+ static_cast<TestController*>(const_cast<void*>(clientInfo))->didRemoveNavigationGestureSnapshot(page);
+}
+
+WKPluginLoadPolicy TestController::decidePolicyForPluginLoad(WKPageRef page, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription, const void* clientInfo)
{
- return static_cast<TestController*>(const_cast<void*>(clientInfo))->pluginLoadPolicy(page, currentPluginLoadPolicy, pluginInformation, unavailabilityDescription);
+ return static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForPluginLoad(page, currentPluginLoadPolicy, pluginInformation, unavailabilityDescription);
}
-WKPluginLoadPolicy TestController::pluginLoadPolicy(WKPageRef, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription)
+WKPluginLoadPolicy TestController::decidePolicyForPluginLoad(WKPageRef, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription)
{
if (m_shouldBlockAllPlugins)
return kWKPluginLoadPolicyBlocked;
+
+#if PLATFORM(MAC)
+ WKStringRef bundleIdentifier = (WKStringRef)WKDictionaryGetItemForKey(pluginInformation, WKPluginInformationBundleIdentifierKey());
+ if (!bundleIdentifier)
+ return currentPluginLoadPolicy;
+
+ if (WKStringIsEqualToUTF8CString(bundleIdentifier, "com.apple.QuickTime Plugin.plugin"))
+ return currentPluginLoadPolicy;
+
+ if (WKStringIsEqualToUTF8CString(bundleIdentifier, "com.apple.testnetscapeplugin"))
+ return currentPluginLoadPolicy;
+
+ RELEASE_ASSERT_NOT_REACHED(); // Please don't use any other plug-ins in tests, as they will not be installed on all machines.
+#else
return currentPluginLoadPolicy;
+#endif
}
-void TestController::didCommitLoadForFrame(WKPageRef page, WKFrameRef frame)
+void TestController::didCommitNavigation(WKPageRef page, WKNavigationRef navigation)
{
- if (!WKFrameIsMainFrame(frame))
- return;
-
mainWebView()->focus();
}
-void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame)
+bool TestController::canAuthenticateAgainstProtectionSpace(WKPageRef page, WKProtectionSpaceRef protectionSpace)
{
- if (m_state != Resetting)
- return;
+ if (m_shouldLogCanAuthenticateAgainstProtectionSpace)
+ m_currentInvocation->outputText("canAuthenticateAgainstProtectionSpace\n");
+ WKProtectionSpaceAuthenticationScheme authenticationScheme = WKProtectionSpaceGetAuthenticationScheme(protectionSpace);
+
+ if (authenticationScheme == kWKProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested) {
+ std::string host = toSTD(adoptWK(WKProtectionSpaceCopyHost(protectionSpace)).get());
+ return host == "localhost" || host == "127.0.0.1";
+ }
+
+ return authenticationScheme <= kWKProtectionSpaceAuthenticationSchemeHTTPDigest;
+}
- if (!WKFrameIsMainFrame(frame))
+void TestController::didFinishNavigation(WKPageRef page, WKNavigationRef navigation)
+{
+ if (m_state != Resetting)
return;
- WKRetainPtr<WKURLRef> wkURL(AdoptWK, WKFrameCopyURL(frame));
+ WKRetainPtr<WKURLRef> wkURL(AdoptWK, WKFrameCopyURL(WKPageGetMainFrame(page)));
if (!WKURLIsEqual(wkURL.get(), blankURL()))
return;
m_doneResetting = true;
- shared().notifyDone();
+ singleton().notifyDone();
}
-void TestController::didReceiveAuthenticationChallengeInFrame(WKPageRef page, WKFrameRef frame, WKAuthenticationChallengeRef authenticationChallenge)
+void TestController::didReceiveAuthenticationChallenge(WKPageRef page, WKAuthenticationChallengeRef authenticationChallenge)
{
- String message;
+ WKProtectionSpaceRef protectionSpace = WKAuthenticationChallengeGetProtectionSpace(authenticationChallenge);
+ WKAuthenticationDecisionListenerRef decisionListener = WKAuthenticationChallengeGetDecisionListener(authenticationChallenge);
+
+ if (WKProtectionSpaceGetAuthenticationScheme(protectionSpace) == kWKProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested) {
+ // Any non-empty credential signals to accept the server trust. Since the cross-platform API
+ // doesn't expose a way to create a credential from server trust, we use a password credential.
+
+ WKRetainPtr<WKCredentialRef> credential = adoptWK(WKCredentialCreate(toWK("accept server trust").get(), toWK("").get(), kWKCredentialPersistenceNone));
+ WKAuthenticationDecisionListenerUseCredential(decisionListener, credential.get());
+ return;
+ }
+
+ if (m_rejectsProtectionSpaceAndContinueForAuthenticationChallenges) {
+ m_currentInvocation->outputText("Simulating reject protection space and continue for authentication challenge\n");
+ WKAuthenticationDecisionListenerRejectProtectionSpaceAndContinue(decisionListener);
+ return;
+ }
+
+ std::string host = toSTD(adoptWK(WKProtectionSpaceCopyHost(protectionSpace)).get());
+ int port = WKProtectionSpaceGetPort(protectionSpace);
+ String message = String::format("%s:%d - didReceiveAuthenticationChallenge - ", host.c_str(), port);
if (!m_handlesAuthenticationChallenges)
- message = "<unknown> - didReceiveAuthenticationChallenge - Simulating cancelled authentication sheet\n";
+ message.append("Simulating cancelled authentication sheet\n");
else
- message = String::format("<unknown> - didReceiveAuthenticationChallenge - Responding with %s:%s\n", m_authenticationUsername.utf8().data(), m_authenticationPassword.utf8().data());
+ message.append(String::format("Responding with %s:%s\n", m_authenticationUsername.utf8().data(), m_authenticationPassword.utf8().data()));
m_currentInvocation->outputText(message);
- WKAuthenticationDecisionListenerRef decisionListener = WKAuthenticationChallengeGetDecisionListener(authenticationChallenge);
if (!m_handlesAuthenticationChallenges) {
WKAuthenticationDecisionListenerUseCredential(decisionListener, 0);
return;
@@ -1113,17 +1672,103 @@ void TestController::didReceiveAuthenticationChallengeInFrame(WKPageRef page, WK
WKAuthenticationDecisionListenerUseCredential(decisionListener, credential.get());
}
+
+// WKContextDownloadClient
+
+void TestController::downloadDidStart(WKContextRef context, WKDownloadRef download, const void* clientInfo)
+{
+ static_cast<TestController*>(const_cast<void*>(clientInfo))->downloadDidStart(context, download);
+}
+
+WKStringRef TestController::decideDestinationWithSuggestedFilename(WKContextRef context, WKDownloadRef download, WKStringRef filename, bool* allowOverwrite, const void* clientInfo)
+{
+ return static_cast<TestController*>(const_cast<void*>(clientInfo))->decideDestinationWithSuggestedFilename(context, download, filename, allowOverwrite);
+}
+
+void TestController::downloadDidFinish(WKContextRef context, WKDownloadRef download, const void* clientInfo)
+{
+ static_cast<TestController*>(const_cast<void*>(clientInfo))->downloadDidFinish(context, download);
+}
+
+void TestController::downloadDidFail(WKContextRef context, WKDownloadRef download, WKErrorRef error, const void* clientInfo)
+{
+ static_cast<TestController*>(const_cast<void*>(clientInfo))->downloadDidFail(context, download, error);
+}
+
+void TestController::downloadDidCancel(WKContextRef context, WKDownloadRef download, const void* clientInfo)
+{
+ static_cast<TestController*>(const_cast<void*>(clientInfo))->downloadDidCancel(context, download);
+}
+
+void TestController::downloadDidStart(WKContextRef context, WKDownloadRef download)
+{
+ m_currentInvocation->outputText("Download started.\n");
+}
+
+WKStringRef TestController::decideDestinationWithSuggestedFilename(WKContextRef, WKDownloadRef, WKStringRef filename, bool*& allowOverwrite)
+{
+ String suggestedFilename = toWTFString(filename);
+
+ StringBuilder builder;
+ builder.append("Downloading URL with suggested filename \"");
+ builder.append(suggestedFilename);
+ builder.append("\"\n");
+
+ m_currentInvocation->outputText(builder.toString());
+
+ const char* dumpRenderTreeTemp = libraryPathForTesting();
+ if (!dumpRenderTreeTemp)
+ return nullptr;
+
+ *allowOverwrite = true;
+ String temporaryFolder = String::fromUTF8(dumpRenderTreeTemp);
+ if (suggestedFilename.isEmpty())
+ suggestedFilename = "Unknown";
+
+ return toWK(temporaryFolder + "/" + suggestedFilename).leakRef();
+}
+
+void TestController::downloadDidFinish(WKContextRef, WKDownloadRef)
+{
+ m_currentInvocation->outputText("Download completed.\n");
+ m_currentInvocation->notifyDownloadDone();
+}
+
+void TestController::downloadDidFail(WKContextRef, WKDownloadRef, WKErrorRef error)
+{
+ String message = String::format("Download failed.\n");
+ m_currentInvocation->outputText(message);
+
+ WKRetainPtr<WKStringRef> errorDomain = adoptWK(WKErrorCopyDomain(error));
+ WKRetainPtr<WKStringRef> errorDescription = adoptWK(WKErrorCopyLocalizedDescription(error));
+ int errorCode = WKErrorGetErrorCode(error);
+
+ StringBuilder errorBuilder;
+ errorBuilder.append("Failed: ");
+ errorBuilder.append(toWTFString(errorDomain));
+ errorBuilder.append(", code=");
+ errorBuilder.appendNumber(errorCode);
+ errorBuilder.append(", description=");
+ errorBuilder.append(toWTFString(errorDescription));
+ errorBuilder.append("\n");
+
+ m_currentInvocation->outputText(errorBuilder.toString());
+ m_currentInvocation->notifyDownloadDone();
+}
+
+void TestController::downloadDidCancel(WKContextRef, WKDownloadRef)
+{
+ m_currentInvocation->outputText("Download cancelled.\n");
+ m_currentInvocation->notifyDownloadDone();
+}
+
void TestController::processDidCrash()
{
// This function can be called multiple times when crash logs are being saved on Windows, so
// ensure we only print the crashed message once.
if (!m_didPrintWebProcessCrashedMessage) {
-#if PLATFORM(MAC)
pid_t pid = WKPageGetProcessIdentifier(m_mainWebView->page());
- fprintf(stderr, "#CRASHED - WebProcess (pid %ld)\n", static_cast<long>(pid));
-#else
- fputs("#CRASHED - WebProcess\n", stderr);
-#endif
+ fprintf(stderr, "#CRASHED - %s (pid %ld)\n", webProcessName(), static_cast<long>(pid));
fflush(stderr);
m_didPrintWebProcessCrashedMessage = true;
}
@@ -1132,9 +1777,29 @@ void TestController::processDidCrash()
exit(1);
}
+void TestController::didBeginNavigationGesture(WKPageRef)
+{
+ m_currentInvocation->didBeginSwipe();
+}
+
+void TestController::willEndNavigationGesture(WKPageRef, WKBackForwardListItemRef)
+{
+ m_currentInvocation->willEndSwipe();
+}
+
+void TestController::didEndNavigationGesture(WKPageRef, WKBackForwardListItemRef)
+{
+ m_currentInvocation->didEndSwipe();
+}
+
+void TestController::didRemoveNavigationGestureSnapshot(WKPageRef)
+{
+ m_currentInvocation->didRemoveSwipeSnapshot();
+}
+
void TestController::simulateWebNotificationClick(uint64_t notificationID)
{
- m_webNotificationProvider.simulateWebNotificationClick(notificationID);
+ m_webNotificationProvider.simulateWebNotificationClick(mainWebView()->page(), notificationID);
}
void TestController::setGeolocationPermission(bool enabled)
@@ -1160,16 +1825,223 @@ void TestController::handleGeolocationPermissionRequest(WKGeolocationPermissionR
decidePolicyForGeolocationPermissionRequestIfPossible();
}
-void TestController::setCustomPolicyDelegate(bool enabled, bool permissive)
+bool TestController::isGeolocationProviderActive() const
{
- m_policyDelegateEnabled = enabled;
- m_policyDelegatePermissive = permissive;
+ return m_geolocationProvider->isActive();
+}
+
+static String originUserVisibleName(WKSecurityOriginRef origin)
+{
+ if (!origin)
+ return emptyString();
+
+ std::string host = toSTD(adoptWK(WKSecurityOriginCopyHost(origin))).c_str();
+ std::string protocol = toSTD(adoptWK(WKSecurityOriginCopyProtocol(origin))).c_str();
+
+ if (!host.length() || !protocol.length())
+ return emptyString();
+
+ unsigned short port = WKSecurityOriginGetPort(origin);
+ if (port)
+ return String::format("%s://%s:%d", protocol.c_str(), host.c_str(), port);
+
+ return String::format("%s://%s", protocol.c_str(), host.c_str());
+}
+
+static String userMediaOriginHash(WKSecurityOriginRef userMediaDocumentOrigin, WKSecurityOriginRef topLevelDocumentOrigin)
+{
+ String userMediaDocumentOriginString = originUserVisibleName(userMediaDocumentOrigin);
+ String topLevelDocumentOriginString = originUserVisibleName(topLevelDocumentOrigin);
+
+ if (topLevelDocumentOriginString.isEmpty())
+ return userMediaDocumentOriginString;
+
+ return String::format("%s-%s", userMediaDocumentOriginString.utf8().data(), topLevelDocumentOriginString.utf8().data());
+}
+
+static String userMediaOriginHash(WKStringRef userMediaDocumentOriginString, WKStringRef topLevelDocumentOriginString)
+{
+ auto userMediaDocumentOrigin = adoptWK(WKSecurityOriginCreateFromString(userMediaDocumentOriginString));
+ if (!WKStringGetLength(topLevelDocumentOriginString))
+ return userMediaOriginHash(userMediaDocumentOrigin.get(), nullptr);
+
+ auto topLevelDocumentOrigin = adoptWK(WKSecurityOriginCreateFromString(topLevelDocumentOriginString));
+ return userMediaOriginHash(userMediaDocumentOrigin.get(), topLevelDocumentOrigin.get());
+}
+
+void TestController::setUserMediaPermission(bool enabled)
+{
+ m_isUserMediaPermissionSet = true;
+ m_isUserMediaPermissionAllowed = enabled;
+ decidePolicyForUserMediaPermissionRequestIfPossible();
+}
+
+static String createCanonicalUUIDString()
+{
+ unsigned randomData[4];
+ cryptographicallyRandomValues(reinterpret_cast<unsigned char*>(randomData), sizeof(randomData));
+
+ // Format as Version 4 UUID.
+ StringBuilder builder;
+ builder.reserveCapacity(36);
+ appendUnsignedAsHexFixedSize(randomData[0], builder, 8, Lowercase);
+ builder.append('-');
+ appendUnsignedAsHexFixedSize(randomData[1] >> 16, builder, 4, Lowercase);
+ builder.appendLiteral("-4");
+ appendUnsignedAsHexFixedSize(randomData[1] & 0x00000fff, builder, 3, Lowercase);
+ builder.append('-');
+ appendUnsignedAsHexFixedSize((randomData[2] >> 30) | 0x8, builder, 1, Lowercase);
+ appendUnsignedAsHexFixedSize((randomData[2] >> 16) & 0x00000fff, builder, 3, Lowercase);
+ builder.append('-');
+ appendUnsignedAsHexFixedSize(randomData[2] & 0x0000ffff, builder, 4, Lowercase);
+ appendUnsignedAsHexFixedSize(randomData[3], builder, 8, Lowercase);
+ return builder.toString();
+}
+
+class OriginSettings : public RefCounted<OriginSettings> {
+public:
+ explicit OriginSettings()
+ {
+ }
+
+ bool persistentPermission() const { return m_persistentPermission; }
+ void setPersistentPermission(bool permission) { m_persistentPermission = permission; }
+
+ String persistentSalt() const { return m_persistentSalt; }
+ void setPersistentSalt(const String& salt) { m_persistentSalt = salt; }
+
+ HashMap<uint64_t, String>& ephemeralSalts() { return m_ephemeralSalts; }
+
+ void incrementRequestCount() { ++m_requestCount; }
+ void resetRequestCount() { m_requestCount = 0; }
+ unsigned requestCount() const { return m_requestCount; }
+
+private:
+ HashMap<uint64_t, String> m_ephemeralSalts;
+ String m_persistentSalt;
+ unsigned m_requestCount { 0 };
+ bool m_persistentPermission { false };
+};
+
+String TestController::saltForOrigin(WKFrameRef frame, String originHash)
+{
+ auto& settings = settingsForOrigin(originHash);
+ auto& ephemeralSalts = settings.ephemeralSalts();
+ auto frameInfo = adoptWK(WKFrameCreateFrameInfo(frame));
+ auto frameHandle = WKFrameInfoGetFrameHandleRef(frameInfo.get());
+ uint64_t frameIdentifier = WKFrameHandleGetFrameID(frameHandle);
+ String frameSalt = ephemeralSalts.get(frameIdentifier);
+
+ if (settings.persistentPermission()) {
+ if (frameSalt.length())
+ return frameSalt;
+
+ if (!settings.persistentSalt().length())
+ settings.setPersistentSalt(createCanonicalUUIDString());
+
+ return settings.persistentSalt();
+ }
+
+ if (!frameSalt.length()) {
+ frameSalt = createCanonicalUUIDString();
+ ephemeralSalts.add(frameIdentifier, frameSalt);
+ }
+
+ return frameSalt;
+}
+
+void TestController::setUserMediaPersistentPermissionForOrigin(bool permission, WKStringRef userMediaDocumentOriginString, WKStringRef topLevelDocumentOriginString)
+{
+ auto originHash = userMediaOriginHash(userMediaDocumentOriginString, topLevelDocumentOriginString);
+ auto& settings = settingsForOrigin(originHash);
+ settings.setPersistentPermission(permission);
+}
+
+void TestController::handleCheckOfUserMediaPermissionForOrigin(WKFrameRef frame, WKSecurityOriginRef userMediaDocumentOrigin, WKSecurityOriginRef topLevelDocumentOrigin, const WKUserMediaPermissionCheckRef& checkRequest)
+{
+ auto originHash = userMediaOriginHash(userMediaDocumentOrigin, topLevelDocumentOrigin);
+ auto salt = saltForOrigin(frame, originHash);
+ WKRetainPtr<WKStringRef> saltString = adoptWK(WKStringCreateWithUTF8CString(salt.utf8().data()));
+
+ WKUserMediaPermissionCheckSetUserMediaAccessInfo(checkRequest, saltString.get(), settingsForOrigin(originHash).persistentPermission());
}
-void TestController::setVisibilityState(WKPageVisibilityState visibilityState, bool isInitialState)
+void TestController::handleUserMediaPermissionRequest(WKFrameRef frame, WKSecurityOriginRef userMediaDocumentOrigin, WKSecurityOriginRef topLevelDocumentOrigin, WKUserMediaPermissionRequestRef request)
{
- setHidden(visibilityState != kWKPageVisibilityStateVisible);
- WKPageSetVisibilityState(m_mainWebView->page(), visibilityState, isInitialState);
+ auto originHash = userMediaOriginHash(userMediaDocumentOrigin, topLevelDocumentOrigin);
+ m_userMediaPermissionRequests.append(std::make_pair(originHash, request));
+ decidePolicyForUserMediaPermissionRequestIfPossible();
+}
+
+OriginSettings& TestController::settingsForOrigin(const String& originHash)
+{
+ RefPtr<OriginSettings> settings = m_cachedUserMediaPermissions.get(originHash);
+ if (!settings) {
+ settings = adoptRef(*new OriginSettings());
+ m_cachedUserMediaPermissions.add(originHash, settings);
+ }
+
+ return *settings;
+}
+
+unsigned TestController::userMediaPermissionRequestCountForOrigin(WKStringRef userMediaDocumentOriginString, WKStringRef topLevelDocumentOriginString)
+{
+ auto originHash = userMediaOriginHash(userMediaDocumentOriginString, topLevelDocumentOriginString);
+ return settingsForOrigin(originHash).requestCount();
+}
+
+void TestController::resetUserMediaPermissionRequestCountForOrigin(WKStringRef userMediaDocumentOriginString, WKStringRef topLevelDocumentOriginString)
+{
+ auto originHash = userMediaOriginHash(userMediaDocumentOriginString, topLevelDocumentOriginString);
+ settingsForOrigin(originHash).resetRequestCount();
+}
+
+void TestController::decidePolicyForUserMediaPermissionRequestIfPossible()
+{
+ if (!m_isUserMediaPermissionSet)
+ return;
+
+ for (auto& pair : m_userMediaPermissionRequests) {
+ auto originHash = pair.first;
+ auto request = pair.second.get();
+
+ auto& settings = settingsForOrigin(originHash);
+ settings.incrementRequestCount();
+
+ if (!m_isUserMediaPermissionAllowed && !settings.persistentPermission()) {
+ WKUserMediaPermissionRequestDeny(request, kWKPermissionDenied);
+ continue;
+ }
+
+ WKRetainPtr<WKArrayRef> audioDeviceUIDs = adoptWK(WKUserMediaPermissionRequestAudioDeviceUIDs(request));
+ WKRetainPtr<WKArrayRef> videoDeviceUIDs = adoptWK(WKUserMediaPermissionRequestVideoDeviceUIDs(request));
+
+ if (!WKArrayGetSize(videoDeviceUIDs.get()) && !WKArrayGetSize(audioDeviceUIDs.get())) {
+ WKUserMediaPermissionRequestDeny(request, kWKNoConstraints);
+ continue;
+ }
+
+ WKRetainPtr<WKStringRef> videoDeviceUID;
+ if (WKArrayGetSize(videoDeviceUIDs.get()))
+ videoDeviceUID = reinterpret_cast<WKStringRef>(WKArrayGetItemAtIndex(videoDeviceUIDs.get(), 0));
+ else
+ videoDeviceUID = adoptWK(WKStringCreateWithUTF8CString(""));
+
+ WKRetainPtr<WKStringRef> audioDeviceUID;
+ if (WKArrayGetSize(audioDeviceUIDs.get()))
+ audioDeviceUID = reinterpret_cast<WKStringRef>(WKArrayGetItemAtIndex(audioDeviceUIDs.get(), 0));
+ else
+ audioDeviceUID = adoptWK(WKStringCreateWithUTF8CString(""));
+
+ WKUserMediaPermissionRequestAllow(request, audioDeviceUID.get(), videoDeviceUID.get());
+ }
+ m_userMediaPermissionRequests.clear();
+}
+
+void TestController::setCustomPolicyDelegate(bool enabled, bool permissive)
+{
+ m_policyDelegateEnabled = enabled;
+ m_policyDelegatePermissive = permissive;
}
void TestController::decidePolicyForGeolocationPermissionRequestIfPossible()
@@ -1189,7 +2061,7 @@ void TestController::decidePolicyForGeolocationPermissionRequestIfPossible()
void TestController::decidePolicyForNotificationPermissionRequest(WKPageRef page, WKSecurityOriginRef origin, WKNotificationPermissionRequestRef request, const void*)
{
- TestController::shared().decidePolicyForNotificationPermissionRequest(page, origin, request);
+ TestController::singleton().decidePolicyForNotificationPermissionRequest(page, origin, request);
}
void TestController::decidePolicyForNotificationPermissionRequest(WKPageRef, WKSecurityOriginRef, WKNotificationPermissionRequestRef request)
@@ -1202,37 +2074,219 @@ void TestController::unavailablePluginButtonClicked(WKPageRef, WKPluginUnavailab
printf("MISSING PLUGIN BUTTON PRESSED\n");
}
-void TestController::decidePolicyForNavigationAction(WKPageRef, WKFrameRef, WKFrameNavigationType, WKEventModifiers, WKEventMouseButton, WKFrameRef, WKURLRequestRef, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo)
+void TestController::decidePolicyForNavigationAction(WKPageRef, WKNavigationActionRef navigationAction, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo)
{
static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForNavigationAction(listener);
}
void TestController::decidePolicyForNavigationAction(WKFramePolicyListenerRef listener)
{
- if (m_policyDelegateEnabled && !m_policyDelegatePermissive) {
- WKFramePolicyListenerIgnore(listener);
- return;
- }
+ WKRetainPtr<WKFramePolicyListenerRef> retainedListener { listener };
+ const bool shouldIgnore { m_policyDelegateEnabled && !m_policyDelegatePermissive };
+ auto decisionFunction = [shouldIgnore, retainedListener]() {
+ if (shouldIgnore)
+ WKFramePolicyListenerIgnore(retainedListener.get());
+ else
+ WKFramePolicyListenerUse(retainedListener.get());
+ };
- WKFramePolicyListenerUse(listener);
+ if (m_shouldDecideNavigationPolicyAfterDelay)
+ RunLoop::main().dispatch(WTFMove(decisionFunction));
+ else
+ decisionFunction();
}
-void TestController::decidePolicyForResponse(WKPageRef, WKFrameRef frame, WKURLResponseRef response, WKURLRequestRef, bool canShowMIMEType, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo)
+void TestController::decidePolicyForNavigationResponse(WKPageRef, WKNavigationResponseRef navigationResponse, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo)
{
- static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForResponse(frame, response, listener);
+ static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForNavigationResponse(navigationResponse, listener);
}
-void TestController::decidePolicyForResponse(WKFrameRef frame, WKURLResponseRef response, WKFramePolicyListenerRef listener)
+void TestController::decidePolicyForNavigationResponse(WKNavigationResponseRef navigationResponse, WKFramePolicyListenerRef listener)
{
// Even though Response was already checked by WKBundlePagePolicyClient, the check did not include plugins
// so we have to re-check again.
- WKRetainPtr<WKStringRef> wkMIMEType(AdoptWK, WKURLResponseCopyMIMEType(response));
- if (WKFrameCanShowMIMEType(frame, wkMIMEType.get())) {
+ if (WKNavigationResponseCanShowMIMEType(navigationResponse)) {
WKFramePolicyListenerUse(listener);
return;
}
- WKFramePolicyListenerIgnore(listener);
+ if (m_shouldDownloadUndisplayableMIMETypes)
+ WKFramePolicyListenerDownload(listener);
+ else
+ WKFramePolicyListenerIgnore(listener);
+}
+
+void TestController::didNavigateWithNavigationData(WKContextRef, WKPageRef, WKNavigationDataRef navigationData, WKFrameRef frame, const void* clientInfo)
+{
+ static_cast<TestController*>(const_cast<void*>(clientInfo))->didNavigateWithNavigationData(navigationData, frame);
}
+void TestController::didNavigateWithNavigationData(WKNavigationDataRef navigationData, WKFrameRef)
+{
+ if (m_state != RunningTest)
+ return;
+
+ if (!m_shouldLogHistoryClientCallbacks)
+ return;
+
+ // URL
+ WKRetainPtr<WKURLRef> urlWK = adoptWK(WKNavigationDataCopyURL(navigationData));
+ WKRetainPtr<WKStringRef> urlStringWK = adoptWK(WKURLCopyString(urlWK.get()));
+ // Title
+ WKRetainPtr<WKStringRef> titleWK = adoptWK(WKNavigationDataCopyTitle(navigationData));
+ // HTTP method
+ WKRetainPtr<WKURLRequestRef> requestWK = adoptWK(WKNavigationDataCopyOriginalRequest(navigationData));
+ WKRetainPtr<WKStringRef> methodWK = adoptWK(WKURLRequestCopyHTTPMethod(requestWK.get()));
+
+ // FIXME: Determine whether the navigation was successful / a client redirect rather than hard-coding the message here.
+ m_currentInvocation->outputText(String::format("WebView navigated to url \"%s\" with title \"%s\" with HTTP equivalent method \"%s\". The navigation was successful and was not a client redirect.\n",
+ toSTD(urlStringWK).c_str(), toSTD(titleWK).c_str(), toSTD(methodWK).c_str()));
+}
+
+void TestController::didPerformClientRedirect(WKContextRef, WKPageRef, WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef frame, const void* clientInfo)
+{
+ static_cast<TestController*>(const_cast<void*>(clientInfo))->didPerformClientRedirect(sourceURL, destinationURL, frame);
+}
+
+void TestController::didPerformClientRedirect(WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef)
+{
+ if (m_state != RunningTest)
+ return;
+
+ if (!m_shouldLogHistoryClientCallbacks)
+ return;
+
+ WKRetainPtr<WKStringRef> sourceStringWK = adoptWK(WKURLCopyString(sourceURL));
+ WKRetainPtr<WKStringRef> destinationStringWK = adoptWK(WKURLCopyString(destinationURL));
+
+ m_currentInvocation->outputText(String::format("WebView performed a client redirect from \"%s\" to \"%s\".\n", toSTD(sourceStringWK).c_str(), toSTD(destinationStringWK).c_str()));
+}
+
+void TestController::didPerformServerRedirect(WKContextRef, WKPageRef, WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef frame, const void* clientInfo)
+{
+ static_cast<TestController*>(const_cast<void*>(clientInfo))->didPerformServerRedirect(sourceURL, destinationURL, frame);
+}
+
+void TestController::didPerformServerRedirect(WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef)
+{
+ if (m_state != RunningTest)
+ return;
+
+ if (!m_shouldLogHistoryClientCallbacks)
+ return;
+
+ WKRetainPtr<WKStringRef> sourceStringWK = adoptWK(WKURLCopyString(sourceURL));
+ WKRetainPtr<WKStringRef> destinationStringWK = adoptWK(WKURLCopyString(destinationURL));
+
+ m_currentInvocation->outputText(String::format("WebView performed a server redirect from \"%s\" to \"%s\".\n", toSTD(sourceStringWK).c_str(), toSTD(destinationStringWK).c_str()));
+}
+
+void TestController::didUpdateHistoryTitle(WKContextRef, WKPageRef, WKStringRef title, WKURLRef URL, WKFrameRef frame, const void* clientInfo)
+{
+ static_cast<TestController*>(const_cast<void*>(clientInfo))->didUpdateHistoryTitle(title, URL, frame);
+}
+
+void TestController::didUpdateHistoryTitle(WKStringRef title, WKURLRef URL, WKFrameRef)
+{
+ if (m_state != RunningTest)
+ return;
+
+ if (!m_shouldLogHistoryClientCallbacks)
+ return;
+
+ WKRetainPtr<WKStringRef> urlStringWK(AdoptWK, WKURLCopyString(URL));
+ m_currentInvocation->outputText(String::format("WebView updated the title for history URL \"%s\" to \"%s\".\n", toSTD(urlStringWK).c_str(), toSTD(title).c_str()));
+}
+
+void TestController::setNavigationGesturesEnabled(bool value)
+{
+ m_mainWebView->setNavigationGesturesEnabled(value);
+}
+
+void TestController::setIgnoresViewportScaleLimits(bool ignoresViewportScaleLimits)
+{
+ WKPageSetIgnoresViewportScaleLimits(m_mainWebView->page(), ignoresViewportScaleLimits);
+}
+
+void TestController::setStatisticsPrevalentResource(WKStringRef hostName, bool value)
+{
+ WKResourceLoadStatisticsManagerSetPrevalentResource(hostName, value);
+}
+
+bool TestController::isStatisticsPrevalentResource(WKStringRef hostName)
+{
+ return WKResourceLoadStatisticsManagerIsPrevalentResource(hostName);
+}
+
+void TestController::setStatisticsHasHadUserInteraction(WKStringRef hostName, bool value)
+{
+ WKResourceLoadStatisticsManagerSetHasHadUserInteraction(hostName, value);
+}
+
+bool TestController::isStatisticsHasHadUserInteraction(WKStringRef hostName)
+{
+ return WKResourceLoadStatisticsManagerIsHasHadUserInteraction(hostName);
+}
+
+void TestController::setStatisticsTimeToLiveUserInteraction(double seconds)
+{
+ WKResourceLoadStatisticsManagerSetTimeToLiveUserInteraction(seconds);
+}
+
+void TestController::statisticsFireDataModificationHandler()
+{
+ WKResourceLoadStatisticsManagerFireDataModificationHandler();
+}
+
+void TestController::setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool value)
+{
+ WKResourceLoadStatisticsManagerSetNotifyPagesWhenDataRecordsWereScanned(value);
+}
+
+void TestController::setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(bool value)
+{
+ WKResourceLoadStatisticsManagerSetShouldClassifyResourcesBeforeDataRecordsRemoval(value);
+}
+
+void TestController::setStatisticsMinimumTimeBetweeenDataRecordsRemoval(double seconds)
+{
+ WKResourceLoadStatisticsManagerSetMinimumTimeBetweeenDataRecordsRemoval(seconds);
+}
+void TestController::statisticsResetToConsistentState()
+{
+ WKResourceLoadStatisticsManagerResetToConsistentState();
+}
+
+#if !PLATFORM(COCOA)
+void TestController::platformWillRunTest(const TestInvocation&)
+{
+}
+
+void TestController::platformCreateWebView(WKPageConfigurationRef configuration, const TestOptions& options)
+{
+ m_mainWebView = std::make_unique<PlatformWebView>(configuration, options);
+}
+
+PlatformWebView* TestController::platformCreateOtherPage(PlatformWebView* parentView, WKPageConfigurationRef configuration, const TestOptions& options)
+{
+ return new PlatformWebView(configuration, options);
+}
+
+WKContextRef TestController::platformAdjustContext(WKContextRef context, WKContextConfigurationRef contextConfiguration)
+{
+ return context;
+}
+
+void TestController::platformResetStateToConsistentValues()
+{
+
+}
+
+unsigned TestController::imageCountInGeneralPasteboard() const
+{
+ return 0;
+}
+
+#endif
+
} // namespace WTR
diff --git a/Tools/WebKitTestRunner/TestController.h b/Tools/WebKitTestRunner/TestController.h
index 10031a176..cc753c297 100644
--- a/Tools/WebKitTestRunner/TestController.h
+++ b/Tools/WebKitTestRunner/TestController.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2015-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,22 +29,28 @@
#include "GeolocationProviderMock.h"
#include "WebNotificationProvider.h"
#include "WorkQueueManager.h"
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKRetainPtr.h>
#include <string>
#include <vector>
-#include <wtf/OwnPtr.h>
+#include <wtf/HashMap.h>
#include <wtf/Vector.h>
+#include <wtf/text/StringHash.h>
+
+OBJC_CLASS WKWebViewConfiguration;
namespace WTR {
class TestInvocation;
+class OriginSettings;
class PlatformWebView;
class EventSenderProxy;
+struct TestCommand;
+struct TestOptions;
// FIXME: Rename this TestRunner?
class TestController {
public:
- static TestController& shared();
+ static TestController& singleton();
static const unsigned viewWidth;
static const unsigned viewHeight;
@@ -52,29 +58,32 @@ public:
static const unsigned w3cSVGViewWidth;
static const unsigned w3cSVGViewHeight;
+ static const double defaultShortTimeout;
+ static const double noTimeout;
+
TestController(int argc, const char* argv[]);
~TestController();
bool verbose() const { return m_verbose; }
- WKStringRef injectedBundlePath() { return m_injectedBundlePath.get(); }
- WKStringRef testPluginDirectory() { return m_testPluginDirectory.get(); }
+ WKStringRef injectedBundlePath() const { return m_injectedBundlePath.get(); }
+ WKStringRef testPluginDirectory() const { return m_testPluginDirectory.get(); }
PlatformWebView* mainWebView() { return m_mainWebView.get(); }
WKContextRef context() { return m_context.get(); }
EventSenderProxy* eventSenderProxy() { return m_eventSenderProxy.get(); }
- void ensureViewSupportsOptions(WKDictionaryRef options);
bool shouldUseRemoteLayerTree() const { return m_shouldUseRemoteLayerTree; }
// Runs the run loop until `done` is true or the timeout elapses.
- enum TimeoutDuration { ShortTimeout, LongTimeout, NoTimeout, CustomTimeout };
bool useWaitToDumpWatchdogTimer() { return m_useWaitToDumpWatchdogTimer; }
- void runUntil(bool& done, TimeoutDuration);
+ void runUntil(bool& done, double timeoutSeconds);
void notifyDone();
- int getCustomTimeout();
+ bool shouldShowWebView() const { return m_shouldShowWebView; }
+ bool usingServerMode() const { return m_usingServerMode; }
+ void configureViewForTest(const TestInvocation&);
bool beforeUnloadReturnValue() const { return m_beforeUnloadReturnValue; }
void setBeforeUnloadReturnValue(bool value) { m_beforeUnloadReturnValue = value; }
@@ -86,27 +95,75 @@ public:
void setMockGeolocationPosition(double latitude, double longitude, double accuracy, bool providesAltitude, double altitude, bool providesAltitudeAccuracy, double altitudeAccuracy, bool providesHeading, double heading, bool providesSpeed, double speed);
void setMockGeolocationPositionUnavailableError(WKStringRef errorMessage);
void handleGeolocationPermissionRequest(WKGeolocationPermissionRequestRef);
+ bool isGeolocationProviderActive() const;
+
+ // MediaStream.
+ String saltForOrigin(WKFrameRef, String);
+ void getUserMediaInfoForOrigin(WKFrameRef, WKStringRef originKey, bool&, WKRetainPtr<WKStringRef>&);
+ WKStringRef getUserMediaSaltForOrigin(WKFrameRef, WKStringRef originKey);
+ void setUserMediaPermission(bool);
+ void setUserMediaPersistentPermissionForOrigin(bool, WKStringRef userMediaDocumentOriginString, WKStringRef topLevelDocumentOriginString);
+ void handleUserMediaPermissionRequest(WKFrameRef, WKSecurityOriginRef, WKSecurityOriginRef, WKUserMediaPermissionRequestRef);
+ void handleCheckOfUserMediaPermissionForOrigin(WKFrameRef, WKSecurityOriginRef, WKSecurityOriginRef, const WKUserMediaPermissionCheckRef&);
+ OriginSettings& settingsForOrigin(const String&);
+ unsigned userMediaPermissionRequestCountForOrigin(WKStringRef userMediaDocumentOriginString, WKStringRef topLevelDocumentOriginString);
+ void resetUserMediaPermissionRequestCountForOrigin(WKStringRef userMediaDocumentOriginString, WKStringRef topLevelDocumentOriginString);
// Policy delegate.
void setCustomPolicyDelegate(bool enabled, bool permissive);
// Page Visibility.
- void setVisibilityState(WKPageVisibilityState, bool isInitialState);
+ void setHidden(bool);
+
+ unsigned imageCountInGeneralPasteboard() const;
+
+ bool resetStateToConsistentValues(const TestOptions&);
+ void resetPreferencesToConsistentValues(const TestOptions&);
- bool resetStateToConsistentValues();
- void resetPreferencesToConsistentValues();
+ void terminateWebContentProcess();
+ void reattachPageToWebProcess();
+
+ static const char* webProcessName();
+ static const char* networkProcessName();
+ static const char* databaseProcessName();
WorkQueueManager& workQueueManager() { return m_workQueueManager; }
+ void setRejectsProtectionSpaceAndContinueForAuthenticationChallenges(bool value) { m_rejectsProtectionSpaceAndContinueForAuthenticationChallenges = value; }
void setHandlesAuthenticationChallenges(bool value) { m_handlesAuthenticationChallenges = value; }
void setAuthenticationUsername(String username) { m_authenticationUsername = username; }
void setAuthenticationPassword(String password) { m_authenticationPassword = password; }
void setBlockAllPlugins(bool shouldBlock) { m_shouldBlockAllPlugins = shouldBlock; }
+ void setShouldLogHistoryClientCallbacks(bool shouldLog) { m_shouldLogHistoryClientCallbacks = shouldLog; }
+ void setShouldLogCanAuthenticateAgainstProtectionSpace(bool shouldLog) { m_shouldLogCanAuthenticateAgainstProtectionSpace = shouldLog; }
+
+ bool isCurrentInvocation(TestInvocation* invocation) const { return invocation == m_currentInvocation.get(); }
+
+ void setShouldDecideNavigationPolicyAfterDelay(bool value) { m_shouldDecideNavigationPolicyAfterDelay = value; }
+
+ void setNavigationGesturesEnabled(bool value);
+ void setIgnoresViewportScaleLimits(bool);
+
+ void setShouldDownloadUndisplayableMIMETypes(bool value) { m_shouldDownloadUndisplayableMIMETypes = value; }
+
+ void setStatisticsPrevalentResource(WKStringRef hostName, bool value);
+ bool isStatisticsPrevalentResource(WKStringRef hostName);
+ void setStatisticsHasHadUserInteraction(WKStringRef hostName, bool value);
+ bool isStatisticsHasHadUserInteraction(WKStringRef hostName);
+ void setStatisticsTimeToLiveUserInteraction(double seconds);
+ void statisticsFireDataModificationHandler();
+ void setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool);
+ void setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(bool);
+ void setStatisticsMinimumTimeBetweeenDataRecordsRemoval(double);
+ void statisticsResetToConsistentState();
+
private:
+ WKRetainPtr<WKPageConfigurationRef> generatePageConfiguration(WKContextConfigurationRef);
+ WKRetainPtr<WKContextConfigurationRef> generateContextConfiguration() const;
void initialize(int argc, const char* argv[]);
- void createWebViewWithOptions(WKDictionaryRef);
+ void createWebViewWithOptions(const TestOptions&);
void run();
void runTestingServerLoop();
@@ -114,34 +171,87 @@ private:
void platformInitialize();
void platformDestroy();
+ WKContextRef platformAdjustContext(WKContextRef, WKContextConfigurationRef);
void platformInitializeContext();
+ void platformCreateWebView(WKPageConfigurationRef, const TestOptions&);
+ static PlatformWebView* platformCreateOtherPage(PlatformWebView* parentView, WKPageConfigurationRef, const TestOptions&);
+ void platformResetPreferencesToConsistentValues();
+ void platformResetStateToConsistentValues();
+#if PLATFORM(COCOA)
+ void cocoaResetStateToConsistentValues();
+#endif
+ void platformConfigureViewForTest(const TestInvocation&);
+ void platformWillRunTest(const TestInvocation&);
void platformRunUntil(bool& done, double timeout);
void platformDidCommitLoadForFrame(WKPageRef, WKFrameRef);
+ WKPreferencesRef platformPreferences();
void initializeInjectedBundlePath();
void initializeTestPluginDirectory();
+ void ensureViewSupportsOptionsForTest(const TestInvocation&);
+ TestOptions testOptionsForTest(const TestCommand&) const;
+ void updatePlatformSpecificTestOptionsForTest(TestOptions&, const std::string& pathOrURL) const;
+
+ void updateWebViewSizeForTest(const TestInvocation&);
+ void updateWindowScaleForTest(PlatformWebView*, const TestInvocation&);
+
void decidePolicyForGeolocationPermissionRequestIfPossible();
+ void decidePolicyForUserMediaPermissionRequestIfPossible();
// WKContextInjectedBundleClient
static void didReceiveMessageFromInjectedBundle(WKContextRef, WKStringRef messageName, WKTypeRef messageBody, const void*);
static void didReceiveSynchronousMessageFromInjectedBundle(WKContextRef, WKStringRef messageName, WKTypeRef messageBody, WKTypeRef* returnData, const void*);
+ static WKTypeRef getInjectedBundleInitializationUserData(WKContextRef, const void *clientInfo);
+
+ // WKPageInjectedBundleClient
+ static void didReceivePageMessageFromInjectedBundle(WKPageRef, WKStringRef messageName, WKTypeRef messageBody, const void*);
+ static void didReceiveSynchronousPageMessageFromInjectedBundle(WKPageRef, WKStringRef messageName, WKTypeRef messageBody, WKTypeRef* returnData, const void*);
void didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody);
WKRetainPtr<WKTypeRef> didReceiveSynchronousMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody);
+ WKRetainPtr<WKTypeRef> getInjectedBundleInitializationUserData();
void didReceiveKeyDownMessageFromInjectedBundle(WKDictionaryRef messageBodyDictionary, bool synchronous);
- // WKPageLoaderClient
- static void didCommitLoadForFrame(WKPageRef, WKFrameRef, WKTypeRef userData, const void*);
- void didCommitLoadForFrame(WKPageRef, WKFrameRef);
+ // WKContextClient
+ static void networkProcessDidCrash(WKContextRef, const void*);
+ void networkProcessDidCrash();
+ static void databaseProcessDidCrash(WKContextRef, const void*);
+ void databaseProcessDidCrash();
- static void didFinishLoadForFrame(WKPageRef, WKFrameRef, WKTypeRef userData, const void*);
- void didFinishLoadForFrame(WKPageRef, WKFrameRef);
+ // WKPageNavigationClient
+ static void didCommitNavigation(WKPageRef, WKNavigationRef, WKTypeRef userData, const void*);
+ void didCommitNavigation(WKPageRef, WKNavigationRef);
+ static void didFinishNavigation(WKPageRef, WKNavigationRef, WKTypeRef userData, const void*);
+ void didFinishNavigation(WKPageRef, WKNavigationRef);
+
+
+ // WKContextDownloadClient
+ static void downloadDidStart(WKContextRef, WKDownloadRef, const void*);
+ void downloadDidStart(WKContextRef, WKDownloadRef);
+ static WKStringRef decideDestinationWithSuggestedFilename(WKContextRef, WKDownloadRef, WKStringRef filename, bool* allowOverwrite, const void *clientInfo);
+ WKStringRef decideDestinationWithSuggestedFilename(WKContextRef, WKDownloadRef, WKStringRef filename, bool*& allowOverwrite);
+ static void downloadDidFinish(WKContextRef, WKDownloadRef, const void*);
+ void downloadDidFinish(WKContextRef, WKDownloadRef);
+ static void downloadDidFail(WKContextRef, WKDownloadRef, WKErrorRef, const void*);
+ void downloadDidFail(WKContextRef, WKDownloadRef, WKErrorRef);
+ static void downloadDidCancel(WKContextRef, WKDownloadRef, const void*);
+ void downloadDidCancel(WKContextRef, WKDownloadRef);
+
static void processDidCrash(WKPageRef, const void* clientInfo);
void processDidCrash();
- static WKPluginLoadPolicy pluginLoadPolicy(WKPageRef, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription, const void* clientInfo);
- WKPluginLoadPolicy pluginLoadPolicy(WKPageRef, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription);
+ static void didBeginNavigationGesture(WKPageRef, const void*);
+ static void willEndNavigationGesture(WKPageRef, WKBackForwardListItemRef, const void*);
+ static void didEndNavigationGesture(WKPageRef, WKBackForwardListItemRef, const void*);
+ static void didRemoveNavigationGestureSnapshot(WKPageRef, const void*);
+ void didBeginNavigationGesture(WKPageRef);
+ void willEndNavigationGesture(WKPageRef, WKBackForwardListItemRef);
+ void didEndNavigationGesture(WKPageRef, WKBackForwardListItemRef);
+ void didRemoveNavigationGestureSnapshot(WKPageRef);
+
+ static WKPluginLoadPolicy decidePolicyForPluginLoad(WKPageRef, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription, const void* clientInfo);
+ WKPluginLoadPolicy decidePolicyForPluginLoad(WKPageRef, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription);
static void decidePolicyForNotificationPermissionRequest(WKPageRef, WKSecurityOriginRef, WKNotificationPermissionRequestRef, const void*);
@@ -149,40 +259,54 @@ private:
static void unavailablePluginButtonClicked(WKPageRef, WKPluginUnavailabilityReason, WKDictionaryRef, const void*);
- static void didReceiveAuthenticationChallengeInFrame(WKPageRef, WKFrameRef, WKAuthenticationChallengeRef, const void *clientInfo);
- void didReceiveAuthenticationChallengeInFrame(WKPageRef, WKFrameRef, WKAuthenticationChallengeRef);
+ static bool canAuthenticateAgainstProtectionSpace(WKPageRef, WKProtectionSpaceRef, const void*);
+ bool canAuthenticateAgainstProtectionSpace(WKPageRef, WKProtectionSpaceRef);
+
+ static void didReceiveAuthenticationChallenge(WKPageRef, WKAuthenticationChallengeRef, const void*);
+ void didReceiveAuthenticationChallenge(WKPageRef, WKAuthenticationChallengeRef);
- // WKPagePolicyClient
- static void decidePolicyForNavigationAction(WKPageRef, WKFrameRef, WKFrameNavigationType, WKEventModifiers, WKEventMouseButton, WKFrameRef, WKURLRequestRef, WKFramePolicyListenerRef, WKTypeRef, const void*);
+ static void decidePolicyForNavigationAction(WKPageRef, WKNavigationActionRef, WKFramePolicyListenerRef, WKTypeRef, const void*);
void decidePolicyForNavigationAction(WKFramePolicyListenerRef);
- static void decidePolicyForResponse(WKPageRef, WKFrameRef, WKURLResponseRef, WKURLRequestRef, bool canShowMIMEType, WKFramePolicyListenerRef, WKTypeRef, const void*);
- void decidePolicyForResponse(WKFrameRef, WKURLResponseRef, WKFramePolicyListenerRef);
+ static void decidePolicyForNavigationResponse(WKPageRef, WKNavigationResponseRef, WKFramePolicyListenerRef, WKTypeRef, const void*);
+ void decidePolicyForNavigationResponse(WKNavigationResponseRef, WKFramePolicyListenerRef);
+
+ // WKContextHistoryClient
+ static void didNavigateWithNavigationData(WKContextRef, WKPageRef, WKNavigationDataRef, WKFrameRef, const void*);
+ void didNavigateWithNavigationData(WKNavigationDataRef, WKFrameRef);
+
+ static void didPerformClientRedirect(WKContextRef, WKPageRef, WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef, const void*);
+ void didPerformClientRedirect(WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef);
- static WKPageRef createOtherPage(WKPageRef oldPage, WKURLRequestRef, WKDictionaryRef, WKEventModifiers, WKEventMouseButton, const void*);
+ static void didPerformServerRedirect(WKContextRef, WKPageRef, WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef, const void*);
+ void didPerformServerRedirect(WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef);
+
+ static void didUpdateHistoryTitle(WKContextRef, WKPageRef, WKStringRef title, WKURLRef, WKFrameRef, const void*);
+ void didUpdateHistoryTitle(WKStringRef title, WKURLRef, WKFrameRef);
+
+ static WKPageRef createOtherPage(WKPageRef, WKPageConfigurationRef, WKNavigationActionRef, WKWindowFeaturesRef, const void*);
static void runModal(WKPageRef, const void* clientInfo);
static void runModal(PlatformWebView*);
- void setHidden(bool);
-
static const char* libraryPathForTesting();
static const char* platformLibraryPathForTesting();
- OwnPtr<TestInvocation> m_currentInvocation;
+ std::unique_ptr<TestInvocation> m_currentInvocation;
- bool m_verbose;
- bool m_printSeparators;
- bool m_usingServerMode;
- bool m_gcBetweenTests;
- bool m_shouldDumpPixelsForAllTests;
+ bool m_verbose { false };
+ bool m_printSeparators { false };
+ bool m_usingServerMode { false };
+ bool m_gcBetweenTests { false };
+ bool m_shouldDumpPixelsForAllTests { false };
std::vector<std::string> m_paths;
+ std::vector<std::string> m_allowedHosts;
WKRetainPtr<WKStringRef> m_injectedBundlePath;
WKRetainPtr<WKStringRef> m_testPluginDirectory;
WebNotificationProvider m_webNotificationProvider;
- OwnPtr<PlatformWebView> m_mainWebView;
+ std::unique_ptr<PlatformWebView> m_mainWebView;
WKRetainPtr<WKContextRef> m_context;
WKRetainPtr<WKPageGroupRef> m_pageGroup;
@@ -191,45 +315,65 @@ private:
Resetting,
RunningTest
};
- State m_state;
- bool m_doneResetting;
+ State m_state { Initial };
+ bool m_doneResetting { false };
- double m_longTimeout;
- double m_shortTimeout;
- double m_noTimeout;
- bool m_useWaitToDumpWatchdogTimer;
- bool m_forceNoTimeout;
+ bool m_useWaitToDumpWatchdogTimer { true };
+ bool m_forceNoTimeout { false };
- int m_timeout;
-
- bool m_didPrintWebProcessCrashedMessage;
- bool m_shouldExitWhenWebProcessCrashes;
+ bool m_didPrintWebProcessCrashedMessage { false };
+ bool m_shouldExitWhenWebProcessCrashes { true };
- bool m_beforeUnloadReturnValue;
+ bool m_beforeUnloadReturnValue { true };
- OwnPtr<GeolocationProviderMock> m_geolocationProvider;
+ std::unique_ptr<GeolocationProviderMock> m_geolocationProvider;
Vector<WKRetainPtr<WKGeolocationPermissionRequestRef> > m_geolocationPermissionRequests;
- bool m_isGeolocationPermissionSet;
- bool m_isGeolocationPermissionAllowed;
+ bool m_isGeolocationPermissionSet { false };
+ bool m_isGeolocationPermissionAllowed { false };
+
+ HashMap<String, RefPtr<OriginSettings>> m_cachedUserMediaPermissions;
+
+ typedef Vector<std::pair<String, WKRetainPtr<WKUserMediaPermissionRequestRef>>> PermissionRequestList;
+ PermissionRequestList m_userMediaPermissionRequests;
+
+ bool m_isUserMediaPermissionSet { false };
+ bool m_isUserMediaPermissionAllowed { false };
- bool m_policyDelegateEnabled;
- bool m_policyDelegatePermissive;
+ bool m_policyDelegateEnabled { false };
+ bool m_policyDelegatePermissive { false };
+ bool m_shouldDownloadUndisplayableMIMETypes { false };
- bool m_handlesAuthenticationChallenges;
+ bool m_rejectsProtectionSpaceAndContinueForAuthenticationChallenges { false };
+ bool m_handlesAuthenticationChallenges { false };
String m_authenticationUsername;
String m_authenticationPassword;
- bool m_shouldBlockAllPlugins;
+ bool m_shouldBlockAllPlugins { false };
- bool m_forceComplexText;
- bool m_shouldUseAcceleratedDrawing;
- bool m_shouldUseRemoteLayerTree;
+ bool m_forceComplexText { false };
+ bool m_shouldUseAcceleratedDrawing { false };
+ bool m_shouldUseRemoteLayerTree { false };
- OwnPtr<EventSenderProxy> m_eventSenderProxy;
+ bool m_shouldLogCanAuthenticateAgainstProtectionSpace { false };
+ bool m_shouldLogHistoryClientCallbacks { false };
+ bool m_shouldShowWebView { false };
+
+ bool m_shouldDecideNavigationPolicyAfterDelay { false };
+
+ std::unique_ptr<EventSenderProxy> m_eventSenderProxy;
WorkQueueManager m_workQueueManager;
};
+struct TestCommand {
+ std::string pathOrURL;
+ std::string absolutePath;
+ bool shouldDumpPixels { false };
+ std::string expectedPixelHash;
+ int timeout { 0 };
+ bool dumpJSConsoleLogInStdErr { false };
+};
+
} // namespace WTR
#endif // TestController_h
diff --git a/Tools/WebKitTestRunner/TestInvocation.cpp b/Tools/WebKitTestRunner/TestInvocation.cpp
index cac2ba8b8..b0a0442cc 100644
--- a/Tools/WebKitTestRunner/TestInvocation.cpp
+++ b/Tools/WebKitTestRunner/TestInvocation.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010, 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2010-2017 Apple Inc. All rights reserved.
* Copyright (C) 2012 Intel Corporation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,196 +30,144 @@
#include "PlatformWebView.h"
#include "StringFunctions.h"
#include "TestController.h"
+#include "UIScriptController.h"
+#include "WebCoreTestSupport.h"
+#include <WebKit/WKContextPrivate.h>
+#include <WebKit/WKCookieManager.h>
+#include <WebKit/WKData.h>
+#include <WebKit/WKDictionary.h>
+#include <WebKit/WKInspector.h>
+#include <WebKit/WKPagePrivate.h>
+#include <WebKit/WKRetainPtr.h>
+#include <WebKit/WKWebsiteDataStoreRef.h>
#include <climits>
#include <cstdio>
-#include <WebKit2/WKContextPrivate.h>
-#include <WebKit2/WKData.h>
-#include <WebKit2/WKDictionary.h>
-#include <WebKit2/WKInspector.h>
-#include <WebKit2/WKRetainPtr.h>
-#include <wtf/PassOwnPtr.h>
+#include <unistd.h>
#include <wtf/StdLibExtras.h>
#include <wtf/text/CString.h>
-#if PLATFORM(MAC)
-#if !PLATFORM(IOS)
+#if PLATFORM(MAC) && !PLATFORM(IOS)
#include <Carbon/Carbon.h>
#endif
-#include <WebKit2/WKPagePrivateMac.h>
-#endif
-#include <unistd.h> // For getcwd.
+#if PLATFORM(COCOA)
+#include <WebKit/WKPagePrivateMac.h>
+#endif
+using namespace JSC;
using namespace WebKit;
using namespace std;
namespace WTR {
-static WKURLRef createWKURL(const char* pathOrURL)
+TestInvocation::TestInvocation(WKURLRef url, const TestOptions& options)
+ : m_options(options)
+ , m_url(url)
{
- if (strstr(pathOrURL, "http://") || strstr(pathOrURL, "https://") || strstr(pathOrURL, "file://"))
- return WKURLCreateWithUTF8CString(pathOrURL);
+ WKRetainPtr<WKStringRef> urlString = adoptWK(WKURLCopyString(m_url.get()));
- // Creating from filesytem path.
- size_t length = strlen(pathOrURL);
- if (!length)
- return 0;
-
- const char separator = '/';
- bool isAbsolutePath = pathOrURL[0] == separator;
- const char* filePrefix = "file://";
- static const size_t prefixLength = strlen(filePrefix);
-
- std::unique_ptr<char[]> buffer;
- if (isAbsolutePath) {
- buffer = std::make_unique<char[]>(prefixLength + length + 1);
- strcpy(buffer.get(), filePrefix);
- strcpy(buffer.get() + prefixLength, pathOrURL);
- } else {
- buffer = std::make_unique<char[]>(prefixLength + PATH_MAX + length + 2); // 1 for the separator
- strcpy(buffer.get(), filePrefix);
- if (!getcwd(buffer.get() + prefixLength, PATH_MAX))
- return 0;
- size_t numCharacters = strlen(buffer.get());
- buffer[numCharacters] = separator;
- strcpy(buffer.get() + numCharacters + 1, pathOrURL);
- }
-
- return WKURLCreateWithUTF8CString(buffer.get());
-}
+ size_t stringLength = WKStringGetLength(urlString.get());
-TestInvocation::TestInvocation(const std::string& pathOrURL)
- : m_url(AdoptWK, createWKURL(pathOrURL.c_str()))
- , m_pathOrURL(pathOrURL)
- , m_dumpPixels(false)
- , m_timeout(0)
- , m_gotInitialResponse(false)
- , m_gotFinalMessage(false)
- , m_gotRepaint(false)
- , m_error(false)
- , m_webProcessIsUnresponsive(false)
-{
+ Vector<char> urlVector;
+ urlVector.resize(stringLength + 1);
+
+ WKStringGetUTF8CString(urlString.get(), urlVector.data(), stringLength + 1);
+
+ m_urlString = String(urlVector.data(), stringLength);
}
TestInvocation::~TestInvocation()
{
+ if (m_pendingUIScriptInvocationData)
+ m_pendingUIScriptInvocationData->testInvocation = nullptr;
}
-void TestInvocation::setIsPixelTest(const std::string& expectedPixelHash)
+WKURLRef TestInvocation::url() const
{
- m_dumpPixels = true;
- m_expectedPixelHash = expectedPixelHash;
+ return m_url.get();
}
-void TestInvocation::setCustomTimeout(int timeout)
+bool TestInvocation::urlContains(const char* searchString) const
{
- m_timeout = timeout;
+ return m_urlString.contains(searchString, false);
}
-static void sizeWebViewForCurrentTest(const char* pathOrURL)
+void TestInvocation::setIsPixelTest(const std::string& expectedPixelHash)
{
- bool isSVGW3CTest = strstr(pathOrURL, "svg/W3C-SVG-1.1") || strstr(pathOrURL, "svg\\W3C-SVG-1.1");
-
- if (isSVGW3CTest)
- TestController::shared().mainWebView()->resizeTo(TestController::w3cSVGViewWidth, TestController::w3cSVGViewHeight);
- else
- TestController::shared().mainWebView()->resizeTo(TestController::viewWidth, TestController::viewHeight);
+ m_dumpPixels = true;
+ m_expectedPixelHash = expectedPixelHash;
}
-static bool shouldLogFrameLoadDelegates(const char* pathOrURL)
+double TestInvocation::shortTimeout() const
{
- return strstr(pathOrURL, "loading/");
-}
+ if (!m_timeout) {
+ // Running WKTR directly, without webkitpy.
+ return TestController::defaultShortTimeout;
+ }
-#if ENABLE(INSPECTOR) && !PLATFORM(IOS)
-static bool shouldOpenWebInspector(const char* pathOrURL)
-{
- return strstr(pathOrURL, "inspector/") || strstr(pathOrURL, "inspector\\");
+ // This is not exactly correct for the way short timeout is used - it should not depend on whether a test is "slow",
+ // but it currently does. There is no way to know what a normal test's timeout is, as webkitpy only passes timeouts
+ // for each test individually.
+ // But there shouldn't be any observable negative consequences from this.
+ return m_timeout / 1000. / 2;
}
-#endif
-#if PLATFORM(MAC)
-static bool shouldUseThreadedScrolling(const char* pathOrURL)
+bool TestInvocation::shouldLogFrameLoadDelegates() const
{
- return strstr(pathOrURL, "tiled-drawing/") || strstr(pathOrURL, "tiled-drawing\\");
+ return urlContains("loading/");
}
-#endif
-static void updateThreadedScrollingForCurrentTest(const char* pathOrURL)
+bool TestInvocation::shouldLogHistoryClientCallbacks() const
{
-#if PLATFORM(MAC)
- WKRetainPtr<WKMutableDictionaryRef> viewOptions = adoptWK(WKMutableDictionaryCreate());
- WKRetainPtr<WKStringRef> useThreadedScrollingKey = adoptWK(WKStringCreateWithUTF8CString("ThreadedScrolling"));
- WKRetainPtr<WKBooleanRef> useThreadedScrollingValue = adoptWK(WKBooleanCreate(shouldUseThreadedScrolling(pathOrURL)));
- WKDictionarySetItem(viewOptions.get(), useThreadedScrollingKey.get(), useThreadedScrollingValue.get());
-
- WKRetainPtr<WKStringRef> useRemoteLayerTreeKey = adoptWK(WKStringCreateWithUTF8CString("RemoteLayerTree"));
- WKRetainPtr<WKBooleanRef> useRemoteLayerTreeValue = adoptWK(WKBooleanCreate(TestController::shared().shouldUseRemoteLayerTree()));
- WKDictionarySetItem(viewOptions.get(), useRemoteLayerTreeKey.get(), useRemoteLayerTreeValue.get());
-
- TestController::shared().ensureViewSupportsOptions(viewOptions.get());
-#else
- UNUSED_PARAM(pathOrURL);
-#endif
+ return urlContains("globalhistory/");
}
-static bool shouldUseFixedLayout(const char* pathOrURL)
+void TestInvocation::invoke()
{
-#if ENABLE(CSS_DEVICE_ADAPTATION)
- if (strstr(pathOrURL, "device-adapt/") || strstr(pathOrURL, "device-adapt\\"))
- return true;
-#endif
+ TestController::singleton().configureViewForTest(*this);
-#if USE(TILED_BACKING_STORE) && PLATFORM(EFL)
- if (strstr(pathOrURL, "sticky/") || strstr(pathOrURL, "sticky\\"))
- return true;
-#endif
- return false;
+ WKPageSetAddsVisitedLinks(TestController::singleton().mainWebView()->page(), false);
- UNUSED_PARAM(pathOrURL);
-}
-
-static void updateLayoutType(const char* pathOrURL)
-{
- WKRetainPtr<WKMutableDictionaryRef> viewOptions = adoptWK(WKMutableDictionaryCreate());
- WKRetainPtr<WKStringRef> useFixedLayoutKey = adoptWK(WKStringCreateWithUTF8CString("UseFixedLayout"));
- WKRetainPtr<WKBooleanRef> useFixedLayoutValue = adoptWK(WKBooleanCreate(shouldUseFixedLayout(pathOrURL)));
- WKDictionarySetItem(viewOptions.get(), useFixedLayoutKey.get(), useFixedLayoutValue.get());
+ m_textOutput.clear();
- TestController::shared().ensureViewSupportsOptions(viewOptions.get());
-}
+ TestController::singleton().setShouldLogHistoryClientCallbacks(shouldLogHistoryClientCallbacks());
-void TestInvocation::invoke()
-{
- TestController::TimeoutDuration timeoutToUse = TestController::LongTimeout;
- sizeWebViewForCurrentTest(m_pathOrURL.c_str());
- updateLayoutType(m_pathOrURL.c_str());
- updateThreadedScrollingForCurrentTest(m_pathOrURL.c_str());
+ WKCookieManagerSetHTTPCookieAcceptPolicy(WKContextGetCookieManager(TestController::singleton().context()), kWKHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain);
- m_textOutput.clear();
+ // FIXME: We should clear out visited links here.
WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("BeginTest"));
WKRetainPtr<WKMutableDictionaryRef> beginTestMessageBody = adoptWK(WKMutableDictionaryCreate());
WKRetainPtr<WKStringRef> dumpFrameLoadDelegatesKey = adoptWK(WKStringCreateWithUTF8CString("DumpFrameLoadDelegates"));
- WKRetainPtr<WKBooleanRef> dumpFrameLoadDelegatesValue = adoptWK(WKBooleanCreate(shouldLogFrameLoadDelegates(m_pathOrURL.c_str())));
+ WKRetainPtr<WKBooleanRef> dumpFrameLoadDelegatesValue = adoptWK(WKBooleanCreate(shouldLogFrameLoadDelegates()));
WKDictionarySetItem(beginTestMessageBody.get(), dumpFrameLoadDelegatesKey.get(), dumpFrameLoadDelegatesValue.get());
+ WKRetainPtr<WKStringRef> useFlexibleViewportKey = adoptWK(WKStringCreateWithUTF8CString("UseFlexibleViewport"));
+ WKRetainPtr<WKBooleanRef> useFlexibleViewportValue = adoptWK(WKBooleanCreate(options().useFlexibleViewport));
+ WKDictionarySetItem(beginTestMessageBody.get(), useFlexibleViewportKey.get(), useFlexibleViewportValue.get());
+
WKRetainPtr<WKStringRef> dumpPixelsKey = adoptWK(WKStringCreateWithUTF8CString("DumpPixels"));
WKRetainPtr<WKBooleanRef> dumpPixelsValue = adoptWK(WKBooleanCreate(m_dumpPixels));
WKDictionarySetItem(beginTestMessageBody.get(), dumpPixelsKey.get(), dumpPixelsValue.get());
WKRetainPtr<WKStringRef> useWaitToDumpWatchdogTimerKey = adoptWK(WKStringCreateWithUTF8CString("UseWaitToDumpWatchdogTimer"));
- WKRetainPtr<WKBooleanRef> useWaitToDumpWatchdogTimerValue = adoptWK(WKBooleanCreate(TestController::shared().useWaitToDumpWatchdogTimer()));
+ WKRetainPtr<WKBooleanRef> useWaitToDumpWatchdogTimerValue = adoptWK(WKBooleanCreate(TestController::singleton().useWaitToDumpWatchdogTimer()));
WKDictionarySetItem(beginTestMessageBody.get(), useWaitToDumpWatchdogTimerKey.get(), useWaitToDumpWatchdogTimerValue.get());
WKRetainPtr<WKStringRef> timeoutKey = adoptWK(WKStringCreateWithUTF8CString("Timeout"));
WKRetainPtr<WKUInt64Ref> timeoutValue = adoptWK(WKUInt64Create(m_timeout));
WKDictionarySetItem(beginTestMessageBody.get(), timeoutKey.get(), timeoutValue.get());
- WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), beginTestMessageBody.get());
+ WKRetainPtr<WKStringRef> dumpJSConsoleLogInStdErrKey = adoptWK(WKStringCreateWithUTF8CString("DumpJSConsoleLogInStdErr"));
+ WKRetainPtr<WKBooleanRef> dumpJSConsoleLogInStdErrValue = adoptWK(WKBooleanCreate(m_dumpJSConsoleLogInStdErr));
+ WKDictionarySetItem(beginTestMessageBody.get(), dumpJSConsoleLogInStdErrKey.get(), dumpJSConsoleLogInStdErrValue.get());
- TestController::shared().runUntil(m_gotInitialResponse, TestController::ShortTimeout);
+ WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), beginTestMessageBody.get());
+
+ bool shouldOpenExternalURLs = false;
+
+ TestController::singleton().runUntil(m_gotInitialResponse, shortTimeout());
if (!m_gotInitialResponse) {
m_errorMessage = "Timed out waiting for initial response from web process\n";
m_webProcessIsUnresponsive = true;
@@ -228,42 +176,29 @@ void TestInvocation::invoke()
if (m_error)
goto end;
-#if ENABLE(INSPECTOR) && !PLATFORM(IOS)
- if (shouldOpenWebInspector(m_pathOrURL.c_str()))
- WKInspectorShow(WKPageGetInspector(TestController::shared().mainWebView()->page()));
-#endif // ENABLE(INSPECTOR)
-
- WKPageLoadURL(TestController::shared().mainWebView()->page(), m_url.get());
-
- if (TestController::shared().useWaitToDumpWatchdogTimer()) {
- if (m_timeout > 0)
- timeoutToUse = TestController::CustomTimeout;
- } else
- timeoutToUse = TestController::NoTimeout;
- TestController::shared().runUntil(m_gotFinalMessage, timeoutToUse);
+ WKPageLoadURLWithShouldOpenExternalURLsPolicy(TestController::singleton().mainWebView()->page(), m_url.get(), shouldOpenExternalURLs);
- if (!m_gotFinalMessage) {
- m_errorMessage = "Timed out waiting for final message from web process\n";
- m_webProcessIsUnresponsive = true;
- goto end;
- }
+ TestController::singleton().runUntil(m_gotFinalMessage, TestController::noTimeout);
if (m_error)
goto end;
dumpResults();
end:
-#if ENABLE(INSPECTOR) && !PLATFORM(IOS)
+#if !PLATFORM(IOS)
if (m_gotInitialResponse)
- WKInspectorClose(WKPageGetInspector(TestController::shared().mainWebView()->page()));
-#endif // ENABLE(INSPECTOR)
+ WKInspectorClose(WKPageGetInspector(TestController::singleton().mainWebView()->page()));
+#endif // !PLATFORM(IOS)
if (m_webProcessIsUnresponsive)
dumpWebProcessUnresponsiveness();
- else if (!TestController::shared().resetStateToConsistentValues()) {
- m_errorMessage = "Timed out loading about:blank before the next test";
- dumpWebProcessUnresponsiveness();
- }
+ else if (TestController::singleton().resetStateToConsistentValues(m_options))
+ return;
+
+ // The process is unresponsive, so let's start a new one.
+ TestController::singleton().terminateWebContentProcess();
+ // Make sure that we have a process, as invoke() will need one to send bundle messages for the next test.
+ TestController::singleton().reattachPageToWebProcess();
}
void TestInvocation::dumpWebProcessUnresponsiveness()
@@ -273,17 +208,25 @@ void TestInvocation::dumpWebProcessUnresponsiveness()
void TestInvocation::dumpWebProcessUnresponsiveness(const char* errorMessage)
{
- const char* errorMessageToStderr = 0;
-#if PLATFORM(MAC)
- char buffer[64];
- pid_t pid = WKPageGetProcessIdentifier(TestController::shared().mainWebView()->page());
- sprintf(buffer, "#PROCESS UNRESPONSIVE - WebProcess (pid %ld)\n", static_cast<long>(pid));
- errorMessageToStderr = buffer;
+ fprintf(stderr, "%s", errorMessage);
+ char buffer[1024] = { };
+#if PLATFORM(COCOA)
+ pid_t pid = WKPageGetProcessIdentifier(TestController::singleton().mainWebView()->page());
+ snprintf(buffer, sizeof(buffer), "#PROCESS UNRESPONSIVE - %s (pid %ld)\n", TestController::webProcessName(), static_cast<long>(pid));
#else
- errorMessageToStderr = "#PROCESS UNRESPONSIVE - WebProcess";
+ snprintf(buffer, sizeof(buffer), "#PROCESS UNRESPONSIVE - %s\n", TestController::webProcessName());
#endif
- dump(errorMessage, errorMessageToStderr, true);
+ dump(errorMessage, buffer, true);
+
+ if (!TestController::singleton().usingServerMode())
+ return;
+
+ if (isatty(fileno(stdin)) || isatty(fileno(stderr)))
+ fputs("Grab an image of the stack, then hit enter...\n", stderr);
+
+ if (!fgets(buffer, sizeof(buffer), stdin) || strcmp(buffer, "#SAMPLE FINISHED\n"))
+ fprintf(stderr, "Failed receive expected sample response, got:\n\t\"%s\"\nContinuing...\n", buffer);
}
void TestInvocation::dump(const char* textToStdout, const char* textToStderr, bool seenError)
@@ -302,11 +245,17 @@ void TestInvocation::dump(const char* textToStdout, const char* textToStderr, bo
fflush(stderr);
}
-void TestInvocation::forceRepaintDoneCallback(WKErrorRef, void* context)
+void TestInvocation::forceRepaintDoneCallback(WKErrorRef error, void* context)
{
+ // The context may not be valid any more, e.g. if WebKit is invalidating callbacks at process exit.
+ if (error)
+ return;
+
TestInvocation* testInvocation = static_cast<TestInvocation*>(context);
+ RELEASE_ASSERT(TestController::singleton().isCurrentInvocation(testInvocation));
+
testInvocation->m_gotRepaint = true;
- TestController::shared().notifyDone();
+ TestController::singleton().notifyDone();
}
void TestInvocation::dumpResults()
@@ -316,18 +265,22 @@ void TestInvocation::dumpResults()
else
dumpAudio(m_audioResult.get());
- if (m_dumpPixels && m_pixelResult) {
- if (PlatformWebView::windowSnapshotEnabled()) {
+ if (m_dumpPixels) {
+ if (m_pixelResult)
+ dumpPixelsAndCompareWithExpected(m_pixelResult.get(), m_repaintRects.get(), TestInvocation::SnapshotResultType::WebContents);
+ else if (m_pixelResultIsPending) {
m_gotRepaint = false;
- WKPageForceRepaint(TestController::shared().mainWebView()->page(), this, TestInvocation::forceRepaintDoneCallback);
- TestController::shared().runUntil(m_gotRepaint, TestController::ShortTimeout);
+ WKPageForceRepaint(TestController::singleton().mainWebView()->page(), this, TestInvocation::forceRepaintDoneCallback);
+ TestController::singleton().runUntil(m_gotRepaint, shortTimeout());
if (!m_gotRepaint) {
m_errorMessage = "Timed out waiting for pre-pixel dump repaint\n";
m_webProcessIsUnresponsive = true;
return;
}
+
+ WKRetainPtr<WKImageRef> windowSnapshot = TestController::singleton().mainWebView()->windowSnapshotImage();
+ dumpPixelsAndCompareWithExpected(windowSnapshot.get(), m_repaintRects.get(), TestInvocation::SnapshotResultType::WebView);
}
- dumpPixelsAndCompareWithExpected(m_pixelResult.get(), m_repaintRects.get());
}
fputs("#EOF\n", stdout);
@@ -374,7 +327,7 @@ void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName
m_gotFinalMessage = true;
m_error = true;
m_errorMessage = "FAIL\n";
- TestController::shared().notifyDone();
+ TestController::singleton().notifyDone();
return;
}
@@ -383,7 +336,7 @@ void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName
WKStringRef messageBodyString = static_cast<WKStringRef>(messageBody);
if (WKStringIsEqualToUTF8CString(messageBodyString, "BeginTest")) {
m_gotInitialResponse = true;
- TestController::shared().notifyDone();
+ TestController::singleton().notifyDone();
return;
}
@@ -394,9 +347,15 @@ void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName
ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
- WKRetainPtr<WKStringRef> pixelResultKey = adoptWK(WKStringCreateWithUTF8CString("PixelResult"));
- m_pixelResult = static_cast<WKImageRef>(WKDictionaryGetItemForKey(messageBodyDictionary, pixelResultKey.get()));
- ASSERT(!m_pixelResult || m_dumpPixels);
+ WKRetainPtr<WKStringRef> pixelResultIsPendingKey = adoptWK(WKStringCreateWithUTF8CString("PixelResultIsPending"));
+ WKBooleanRef pixelResultIsPending = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, pixelResultIsPendingKey.get()));
+ m_pixelResultIsPending = WKBooleanGetValue(pixelResultIsPending);
+
+ if (!m_pixelResultIsPending) {
+ WKRetainPtr<WKStringRef> pixelResultKey = adoptWK(WKStringCreateWithUTF8CString("PixelResult"));
+ m_pixelResult = static_cast<WKImageRef>(WKDictionaryGetItemForKey(messageBodyDictionary, pixelResultKey.get()));
+ ASSERT(!m_pixelResult || m_dumpPixels);
+ }
WKRetainPtr<WKStringRef> repaintRectsKey = adoptWK(WKStringCreateWithUTF8CString("RepaintRects"));
m_repaintRects = static_cast<WKArrayRef>(WKDictionaryGetItemForKey(messageBodyDictionary, repaintRectsKey.get()));
@@ -405,7 +364,7 @@ void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName
m_audioResult = static_cast<WKDataRef>(WKDictionaryGetItemForKey(messageBodyDictionary, audioResultKey.get()));
m_gotFinalMessage = true;
- TestController::shared().notifyDone();
+ TestController::singleton().notifyDone();
return;
}
@@ -416,55 +375,69 @@ void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName
return;
}
+ if (WKStringIsEqualToUTF8CString(messageName, "DumpToStdErr")) {
+ ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
+ WKStringRef textOutput = static_cast<WKStringRef>(messageBody);
+ fprintf(stderr, "%s", toWTFString(textOutput).utf8().data());
+ return;
+ }
+
if (WKStringIsEqualToUTF8CString(messageName, "BeforeUnloadReturnValue")) {
ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
WKBooleanRef beforeUnloadReturnValue = static_cast<WKBooleanRef>(messageBody);
- TestController::shared().setBeforeUnloadReturnValue(WKBooleanGetValue(beforeUnloadReturnValue));
+ TestController::singleton().setBeforeUnloadReturnValue(WKBooleanGetValue(beforeUnloadReturnValue));
return;
}
if (WKStringIsEqualToUTF8CString(messageName, "AddChromeInputField")) {
- TestController::shared().mainWebView()->addChromeInputField();
+ TestController::singleton().mainWebView()->addChromeInputField();
WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallAddChromeInputFieldCallback"));
- WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0);
+ WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
return;
}
if (WKStringIsEqualToUTF8CString(messageName, "RemoveChromeInputField")) {
- TestController::shared().mainWebView()->removeChromeInputField();
+ TestController::singleton().mainWebView()->removeChromeInputField();
WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallRemoveChromeInputFieldCallback"));
- WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0);
+ WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
return;
}
if (WKStringIsEqualToUTF8CString(messageName, "FocusWebView")) {
- TestController::shared().mainWebView()->makeWebViewFirstResponder();
+ TestController::singleton().mainWebView()->makeWebViewFirstResponder();
WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallFocusWebViewCallback"));
- WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0);
+ WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
return;
}
if (WKStringIsEqualToUTF8CString(messageName, "SetBackingScaleFactor")) {
ASSERT(WKGetTypeID(messageBody) == WKDoubleGetTypeID());
double backingScaleFactor = WKDoubleGetValue(static_cast<WKDoubleRef>(messageBody));
- WKPageSetCustomBackingScaleFactor(TestController::shared().mainWebView()->page(), backingScaleFactor);
+ WKPageSetCustomBackingScaleFactor(TestController::singleton().mainWebView()->page(), backingScaleFactor);
WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallSetBackingScaleFactorCallback"));
- WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0);
+ WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
return;
}
if (WKStringIsEqualToUTF8CString(messageName, "SimulateWebNotificationClick")) {
ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID());
uint64_t notificationID = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody));
- TestController::shared().simulateWebNotificationClick(notificationID);
+ TestController::singleton().simulateWebNotificationClick(notificationID);
+ return;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "SetAddsVisitedLinks")) {
+ ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
+ WKBooleanRef enabledWK = static_cast<WKBooleanRef>(messageBody);
+ WKPageSetAddsVisitedLinks(TestController::singleton().mainWebView()->page(), WKBooleanGetValue(enabledWK));
return;
}
if (WKStringIsEqualToUTF8CString(messageName, "SetGeolocationPermission")) {
ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
WKBooleanRef enabledWK = static_cast<WKBooleanRef>(messageBody);
- TestController::shared().setGeolocationPermission(WKBooleanGetValue(enabledWK));
+ TestController::singleton().setGeolocationPermission(WKBooleanGetValue(enabledWK));
return;
}
@@ -516,14 +489,60 @@ void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName
WKDoubleRef speedWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, speedKeyWK.get()));
double speed = WKDoubleGetValue(speedWK);
- TestController::shared().setMockGeolocationPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed);
+ TestController::singleton().setMockGeolocationPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed);
return;
}
if (WKStringIsEqualToUTF8CString(messageName, "SetMockGeolocationPositionUnavailableError")) {
ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
WKStringRef errorMessage = static_cast<WKStringRef>(messageBody);
- TestController::shared().setMockGeolocationPositionUnavailableError(errorMessage);
+ TestController::singleton().setMockGeolocationPositionUnavailableError(errorMessage);
+ return;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "SetUserMediaPermission")) {
+ ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
+ WKBooleanRef enabledWK = static_cast<WKBooleanRef>(messageBody);
+ TestController::singleton().setUserMediaPermission(WKBooleanGetValue(enabledWK));
+ return;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "SetUserMediaPersistentPermissionForOrigin")) {
+ ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
+ WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
+
+ WKRetainPtr<WKStringRef> permissionKeyWK(AdoptWK, WKStringCreateWithUTF8CString("permission"));
+ WKBooleanRef permissionWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, permissionKeyWK.get()));
+ bool permission = WKBooleanGetValue(permissionWK);
+
+ WKRetainPtr<WKStringRef> originKey(AdoptWK, WKStringCreateWithUTF8CString("origin"));
+ WKStringRef originWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, originKey.get()));
+
+ WKRetainPtr<WKStringRef> parentOriginKey(AdoptWK, WKStringCreateWithUTF8CString("parentOrigin"));
+ WKStringRef parentOriginWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, parentOriginKey.get()));
+
+ TestController::singleton().setUserMediaPersistentPermissionForOrigin(permission, originWK, parentOriginWK);
+ return;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "ResetUserMediaPermissionRequestCountForOrigin")) {
+ ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
+ WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
+
+ WKRetainPtr<WKStringRef> originKey(AdoptWK, WKStringCreateWithUTF8CString("origin"));
+ WKStringRef originWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, originKey.get()));
+
+ WKRetainPtr<WKStringRef> parentOriginKey(AdoptWK, WKStringCreateWithUTF8CString("parentOrigin"));
+ WKStringRef parentOriginWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, parentOriginKey.get()));
+
+ TestController::singleton().resetUserMediaPermissionRequestCountForOrigin(originWK, parentOriginWK);
+ return;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "SetCacheModel")) {
+ ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID());
+ uint64_t model = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody));
+ WKContextSetCacheModel(TestController::singleton().context(), model);
return;
}
@@ -539,30 +558,26 @@ void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName
WKBooleanRef permissiveWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, permissiveKeyWK.get()));
bool permissive = WKBooleanGetValue(permissiveWK);
- TestController::shared().setCustomPolicyDelegate(enabled, permissive);
+ TestController::singleton().setCustomPolicyDelegate(enabled, permissive);
return;
}
- if (WKStringIsEqualToUTF8CString(messageName, "SetVisibilityState")) {
+ if (WKStringIsEqualToUTF8CString(messageName, "SetHidden")) {
ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
- WKRetainPtr<WKStringRef> visibilityStateKeyWK(AdoptWK, WKStringCreateWithUTF8CString("visibilityState"));
- WKUInt64Ref visibilityStateWK = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, visibilityStateKeyWK.get()));
- WKPageVisibilityState visibilityState = static_cast<WKPageVisibilityState>(WKUInt64GetValue(visibilityStateWK));
-
- WKRetainPtr<WKStringRef> isInitialKeyWK(AdoptWK, WKStringCreateWithUTF8CString("isInitialState"));
- WKBooleanRef isInitialWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, isInitialKeyWK.get()));
- bool isInitialState = WKBooleanGetValue(isInitialWK);
+ WKRetainPtr<WKStringRef> isInitialKeyWK(AdoptWK, WKStringCreateWithUTF8CString("hidden"));
+ WKBooleanRef hiddenWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, isInitialKeyWK.get()));
+ bool hidden = WKBooleanGetValue(hiddenWK);
- TestController::shared().setVisibilityState(visibilityState, isInitialState);
+ TestController::singleton().setHidden(hidden);
return;
}
if (WKStringIsEqualToUTF8CString(messageName, "ProcessWorkQueue")) {
- if (TestController::shared().workQueueManager().processWorkQueue()) {
+ if (TestController::singleton().workQueueManager().processWorkQueue()) {
WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("WorkQueueProcessedCallback"));
- WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0);
+ WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
}
return;
}
@@ -570,14 +585,14 @@ void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName
if (WKStringIsEqualToUTF8CString(messageName, "QueueBackNavigation")) {
ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID());
uint64_t stepCount = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody));
- TestController::shared().workQueueManager().queueBackNavigation(stepCount);
+ TestController::singleton().workQueueManager().queueBackNavigation(stepCount);
return;
}
if (WKStringIsEqualToUTF8CString(messageName, "QueueForwardNavigation")) {
ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID());
uint64_t stepCount = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody));
- TestController::shared().workQueueManager().queueForwardNavigation(stepCount);
+ TestController::singleton().workQueueManager().queueForwardNavigation(stepCount);
return;
}
@@ -591,7 +606,10 @@ void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName
WKRetainPtr<WKStringRef> targetKey(AdoptWK, WKStringCreateWithUTF8CString("target"));
WKStringRef targetWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(loadDataDictionary, targetKey.get()));
- TestController::shared().workQueueManager().queueLoad(toWTFString(urlWK), toWTFString(targetWK));
+ WKRetainPtr<WKStringRef> shouldOpenExternalURLsKey(AdoptWK, WKStringCreateWithUTF8CString("shouldOpenExternalURLs"));
+ WKBooleanRef shouldOpenExternalURLsValueWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(loadDataDictionary, shouldOpenExternalURLsKey.get()));
+
+ TestController::singleton().workQueueManager().queueLoad(toWTFString(urlWK), toWTFString(targetWK), WKBooleanGetValue(shouldOpenExternalURLsValueWK));
return;
}
@@ -608,54 +626,110 @@ void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName
WKRetainPtr<WKStringRef> unreachableURLKey(AdoptWK, WKStringCreateWithUTF8CString("unreachableURL"));
WKStringRef unreachableURLWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(loadDataDictionary, unreachableURLKey.get()));
- TestController::shared().workQueueManager().queueLoadHTMLString(toWTFString(contentWK), baseURLWK ? toWTFString(baseURLWK) : String(), unreachableURLWK ? toWTFString(unreachableURLWK) : String());
+ TestController::singleton().workQueueManager().queueLoadHTMLString(toWTFString(contentWK), baseURLWK ? toWTFString(baseURLWK) : String(), unreachableURLWK ? toWTFString(unreachableURLWK) : String());
return;
}
if (WKStringIsEqualToUTF8CString(messageName, "QueueReload")) {
- TestController::shared().workQueueManager().queueReload();
+ TestController::singleton().workQueueManager().queueReload();
return;
}
if (WKStringIsEqualToUTF8CString(messageName, "QueueLoadingScript")) {
ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
WKStringRef script = static_cast<WKStringRef>(messageBody);
- TestController::shared().workQueueManager().queueLoadingScript(toWTFString(script));
+ TestController::singleton().workQueueManager().queueLoadingScript(toWTFString(script));
return;
}
if (WKStringIsEqualToUTF8CString(messageName, "QueueNonLoadingScript")) {
ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
WKStringRef script = static_cast<WKStringRef>(messageBody);
- TestController::shared().workQueueManager().queueNonLoadingScript(toWTFString(script));
+ TestController::singleton().workQueueManager().queueNonLoadingScript(toWTFString(script));
+ return;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "SetRejectsProtectionSpaceAndContinueForAuthenticationChallenges")) {
+ ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
+ WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);
+ TestController::singleton().setRejectsProtectionSpaceAndContinueForAuthenticationChallenges(WKBooleanGetValue(value));
return;
}
- if (WKStringIsEqualToUTF8CString(messageName, "SetHandlesAuthenticationChallenge")) {
+ if (WKStringIsEqualToUTF8CString(messageName, "SetHandlesAuthenticationChallenges")) {
ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);
- TestController::shared().setHandlesAuthenticationChallenges(WKBooleanGetValue(value));
+ TestController::singleton().setHandlesAuthenticationChallenges(WKBooleanGetValue(value));
+ return;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "SetShouldLogCanAuthenticateAgainstProtectionSpace")) {
+ ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
+ WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);
+ TestController::singleton().setShouldLogCanAuthenticateAgainstProtectionSpace(WKBooleanGetValue(value));
return;
}
if (WKStringIsEqualToUTF8CString(messageName, "SetAuthenticationUsername")) {
ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
WKStringRef username = static_cast<WKStringRef>(messageBody);
- TestController::shared().setAuthenticationUsername(toWTFString(username));
+ TestController::singleton().setAuthenticationUsername(toWTFString(username));
return;
}
if (WKStringIsEqualToUTF8CString(messageName, "SetAuthenticationPassword")) {
ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
WKStringRef password = static_cast<WKStringRef>(messageBody);
- TestController::shared().setAuthenticationPassword(toWTFString(password));
+ TestController::singleton().setAuthenticationPassword(toWTFString(password));
return;
}
if (WKStringIsEqualToUTF8CString(messageName, "SetBlockAllPlugins")) {
ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
WKBooleanRef shouldBlock = static_cast<WKBooleanRef>(messageBody);
- TestController::shared().setBlockAllPlugins(WKBooleanGetValue(shouldBlock));
+ TestController::singleton().setBlockAllPlugins(WKBooleanGetValue(shouldBlock));
+ return;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "SetShouldDecideNavigationPolicyAfterDelay")) {
+ ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
+ WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);
+ TestController::singleton().setShouldDecideNavigationPolicyAfterDelay(WKBooleanGetValue(value));
+ return;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "SetNavigationGesturesEnabled")) {
+ ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
+ WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);
+ TestController::singleton().setNavigationGesturesEnabled(WKBooleanGetValue(value));
+ return;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "SetIgnoresViewportScaleLimits")) {
+ ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
+ WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);
+ TestController::singleton().setIgnoresViewportScaleLimits(WKBooleanGetValue(value));
+ return;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "SetShouldDownloadUndisplayableMIMETypes")) {
+ ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
+ WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);
+ TestController::singleton().setShouldDownloadUndisplayableMIMETypes(WKBooleanGetValue(value));
+ return;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "RunUIProcessScript")) {
+ WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
+ WKRetainPtr<WKStringRef> scriptKey(AdoptWK, WKStringCreateWithUTF8CString("Script"));
+ WKRetainPtr<WKStringRef> callbackIDKey(AdoptWK, WKStringCreateWithUTF8CString("CallbackID"));
+
+ UIScriptInvocationData* invocationData = new UIScriptInvocationData();
+ invocationData->testInvocation = this;
+ invocationData->callbackID = (unsigned)WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, callbackIDKey.get())));
+ invocationData->scriptString = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, scriptKey.get()));
+ m_pendingUIScriptInvocationData = invocationData;
+ WKPageCallAfterNextPresentationUpdate(TestController::singleton().mainWebView()->page(), invocationData, runUISideScriptAfterUpdateCallback);
return;
}
@@ -667,12 +741,32 @@ WKRetainPtr<WKTypeRef> TestInvocation::didReceiveSynchronousMessageFromInjectedB
if (WKStringIsEqualToUTF8CString(messageName, "SetWindowIsKey")) {
ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
WKBooleanRef isKeyValue = static_cast<WKBooleanRef>(messageBody);
- TestController::shared().mainWebView()->setWindowIsKey(WKBooleanGetValue(isKeyValue));
- return 0;
+ TestController::singleton().mainWebView()->setWindowIsKey(WKBooleanGetValue(isKeyValue));
+ return nullptr;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "SetViewSize")) {
+ ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
+
+ WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
+ WKRetainPtr<WKStringRef> widthKey(AdoptWK, WKStringCreateWithUTF8CString("width"));
+ WKRetainPtr<WKStringRef> heightKey(AdoptWK, WKStringCreateWithUTF8CString("height"));
+
+ WKDoubleRef widthWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, widthKey.get()));
+ WKDoubleRef heightWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, heightKey.get()));
+
+ TestController::singleton().mainWebView()->resizeTo(WKDoubleGetValue(widthWK), WKDoubleGetValue(heightWK));
+ return nullptr;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "IsGeolocationClientActive")) {
+ bool isActive = TestController::singleton().isGeolocationProviderActive();
+ WKRetainPtr<WKTypeRef> result(AdoptWK, WKBooleanCreate(isActive));
+ return result;
}
if (WKStringIsEqualToUTF8CString(messageName, "IsWorkQueueEmpty")) {
- bool isEmpty = TestController::shared().workQueueManager().isWorkQueueEmpty();
+ bool isEmpty = TestController::singleton().workQueueManager().isWorkQueueEmpty();
WKRetainPtr<WKTypeRef> result(AdoptWK, WKBooleanCreate(isEmpty));
return result;
}
@@ -685,8 +779,234 @@ WKRetainPtr<WKTypeRef> TestInvocation::didReceiveSynchronousMessageFromInjectedB
#endif
return result;
}
+
+ if (WKStringIsEqualToUTF8CString(messageName, "SetAlwaysAcceptCookies")) {
+ WKBooleanRef accept = static_cast<WKBooleanRef>(messageBody);
+ WKHTTPCookieAcceptPolicy policy = WKBooleanGetValue(accept) ? kWKHTTPCookieAcceptPolicyAlways : kWKHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain;
+ // FIXME: This updates the policy in WebProcess and in NetworkProcess asynchronously, which might break some tests' expectations.
+ WKCookieManagerSetHTTPCookieAcceptPolicy(WKContextGetCookieManager(TestController::singleton().context()), policy);
+ return nullptr;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "ImageCountInGeneralPasteboard")) {
+ unsigned count = TestController::singleton().imageCountInGeneralPasteboard();
+ WKRetainPtr<WKUInt64Ref> result(AdoptWK, WKUInt64Create(count));
+ return result;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "DeleteAllIndexedDatabases")) {
+ WKWebsiteDataStoreRemoveAllIndexedDatabases(WKContextGetWebsiteDataStore(TestController::singleton().context()));
+ return nullptr;
+ }
+
+#if PLATFORM(MAC)
+ if (WKStringIsEqualToUTF8CString(messageName, "ConnectMockGamepad")) {
+ ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID());
+
+ uint64_t index = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody));
+ WebCoreTestSupport::connectMockGamepad(index);
+
+ return nullptr;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "DisconnectMockGamepad")) {
+ ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID());
+
+ uint64_t index = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody));
+ WebCoreTestSupport::disconnectMockGamepad(index);
+
+ return nullptr;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "SetMockGamepadDetails")) {
+ ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
+
+ WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
+ WKRetainPtr<WKStringRef> gamepadIndexKey(AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex"));
+ WKRetainPtr<WKStringRef> gamepadIDKey(AdoptWK, WKStringCreateWithUTF8CString("GamepadID"));
+ WKRetainPtr<WKStringRef> axisCountKey(AdoptWK, WKStringCreateWithUTF8CString("AxisCount"));
+ WKRetainPtr<WKStringRef> buttonCountKey(AdoptWK, WKStringCreateWithUTF8CString("ButtonCount"));
+
+ WKUInt64Ref gamepadIndex = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, gamepadIndexKey.get()));
+ WKStringRef gamepadID = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, gamepadIDKey.get()));
+ WKUInt64Ref axisCount = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, axisCountKey.get()));
+ WKUInt64Ref buttonCount = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, buttonCountKey.get()));
+
+ WebCoreTestSupport::setMockGamepadDetails(WKUInt64GetValue(gamepadIndex), toWTFString(gamepadID), WKUInt64GetValue(axisCount), WKUInt64GetValue(buttonCount));
+ return nullptr;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "SetMockGamepadAxisValue")) {
+ ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
+
+ WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
+ WKRetainPtr<WKStringRef> gamepadIndexKey(AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex"));
+ WKRetainPtr<WKStringRef> axisIndexKey(AdoptWK, WKStringCreateWithUTF8CString("AxisIndex"));
+ WKRetainPtr<WKStringRef> valueKey(AdoptWK, WKStringCreateWithUTF8CString("Value"));
+
+ WKUInt64Ref gamepadIndex = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, gamepadIndexKey.get()));
+ WKUInt64Ref axisIndex = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, axisIndexKey.get()));
+ WKDoubleRef value = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, valueKey.get()));
+
+ WebCoreTestSupport::setMockGamepadAxisValue(WKUInt64GetValue(gamepadIndex), WKUInt64GetValue(axisIndex), WKDoubleGetValue(value));
+
+ return nullptr;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "SetMockGamepadButtonValue")) {
+ ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
+
+ WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
+ WKRetainPtr<WKStringRef> gamepadIndexKey(AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex"));
+ WKRetainPtr<WKStringRef> buttonIndexKey(AdoptWK, WKStringCreateWithUTF8CString("ButtonIndex"));
+ WKRetainPtr<WKStringRef> valueKey(AdoptWK, WKStringCreateWithUTF8CString("Value"));
+
+ WKUInt64Ref gamepadIndex = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, gamepadIndexKey.get()));
+ WKUInt64Ref buttonIndex = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, buttonIndexKey.get()));
+ WKDoubleRef value = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, valueKey.get()));
+
+ WebCoreTestSupport::setMockGamepadButtonValue(WKUInt64GetValue(gamepadIndex), WKUInt64GetValue(buttonIndex), WKDoubleGetValue(value));
+
+ return nullptr;
+ }
+#endif // PLATFORM(MAC)
+
+ if (WKStringIsEqualToUTF8CString(messageName, "UserMediaPermissionRequestCountForOrigin")) {
+ ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
+ WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
+
+ WKRetainPtr<WKStringRef> originKey(AdoptWK, WKStringCreateWithUTF8CString("origin"));
+ WKStringRef originWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, originKey.get()));
+
+ WKRetainPtr<WKStringRef> parentOriginKey(AdoptWK, WKStringCreateWithUTF8CString("parentOrigin"));
+ WKStringRef parentOriginWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, parentOriginKey.get()));
+
+ unsigned count = TestController::singleton().userMediaPermissionRequestCountForOrigin(originWK, parentOriginWK);
+ WKRetainPtr<WKUInt64Ref> result(AdoptWK, WKUInt64Create(count));
+ return result;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "SetStatisticsPrevalentResource")) {
+ ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
+
+ WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
+ WKRetainPtr<WKStringRef> hostNameKey(AdoptWK, WKStringCreateWithUTF8CString("HostName"));
+ WKRetainPtr<WKStringRef> valueKey(AdoptWK, WKStringCreateWithUTF8CString("Value"));
+
+ WKStringRef hostName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, hostNameKey.get()));
+ WKBooleanRef value = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, valueKey.get()));
+
+ TestController::singleton().setStatisticsPrevalentResource(hostName, WKBooleanGetValue(value));
+ return nullptr;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "IsStatisticsPrevalentResource")) {
+ ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
+
+ WKStringRef hostName = static_cast<WKStringRef>(messageBody);
+ bool isPrevalent = TestController::singleton().isStatisticsPrevalentResource(hostName);
+ WKRetainPtr<WKTypeRef> result(AdoptWK, WKBooleanCreate(isPrevalent));
+ return result;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "SetStatisticsHasHadUserInteraction")) {
+ ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
+
+ WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
+ WKRetainPtr<WKStringRef> hostNameKey(AdoptWK, WKStringCreateWithUTF8CString("HostName"));
+ WKRetainPtr<WKStringRef> valueKey(AdoptWK, WKStringCreateWithUTF8CString("Value"));
+
+ WKStringRef hostName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, hostNameKey.get()));
+ WKBooleanRef value = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, valueKey.get()));
+
+ TestController::singleton().setStatisticsHasHadUserInteraction(hostName, WKBooleanGetValue(value));
+ return nullptr;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "IsStatisticsHasHadUserInteraction")) {
+ ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
+
+ WKStringRef hostName = static_cast<WKStringRef>(messageBody);
+ bool hasHadUserInteraction = TestController::singleton().isStatisticsHasHadUserInteraction(hostName);
+ WKRetainPtr<WKTypeRef> result(AdoptWK, WKBooleanCreate(hasHadUserInteraction));
+ return result;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "SetStatisticsTimeToLiveUserInteraction")) {
+ ASSERT(WKGetTypeID(messageBody) == WKDoubleGetTypeID());
+ WKDoubleRef seconds = static_cast<WKDoubleRef>(messageBody);
+ TestController::singleton().setStatisticsTimeToLiveUserInteraction(WKDoubleGetValue(seconds));
+ return nullptr;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "StatisticsFireDataModificationHandler")) {
+ TestController::singleton().statisticsFireDataModificationHandler();
+ return nullptr;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "StatisticsNotifyPagesWhenDataRecordsWereScanned")) {
+ ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
+ WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);
+ TestController::singleton().setStatisticsNotifyPagesWhenDataRecordsWereScanned(WKBooleanGetValue(value));
+ return nullptr;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "StatisticsShouldClassifyResourcesBeforeDataRecordsRemoval")) {
+ ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
+ WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);
+ TestController::singleton().setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(WKBooleanGetValue(value));
+ return nullptr;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "SetStatisticsMinimumTimeBetweeenDataRecordsRemoval")) {
+ ASSERT(WKGetTypeID(messageBody) == WKDoubleGetTypeID());
+ WKDoubleRef seconds = static_cast<WKDoubleRef>(messageBody);
+ TestController::singleton().setStatisticsMinimumTimeBetweeenDataRecordsRemoval(WKDoubleGetValue(seconds));
+ return nullptr;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "StatisticsResetToConsistentState")) {
+ TestController::singleton().statisticsResetToConsistentState();
+ return nullptr;
+ }
+
ASSERT_NOT_REACHED();
- return 0;
+ return nullptr;
+}
+
+void TestInvocation::runUISideScriptAfterUpdateCallback(WKErrorRef, void* context)
+{
+ UIScriptInvocationData* data = static_cast<UIScriptInvocationData*>(context);
+ if (TestInvocation* invocation = data->testInvocation) {
+ RELEASE_ASSERT(TestController::singleton().isCurrentInvocation(invocation));
+ invocation->runUISideScript(data->scriptString.get(), data->callbackID);
+ }
+ delete data;
+}
+
+void TestInvocation::runUISideScript(WKStringRef script, unsigned scriptCallbackID)
+{
+ m_pendingUIScriptInvocationData = nullptr;
+
+ if (!m_UIScriptContext)
+ m_UIScriptContext = std::make_unique<UIScriptContext>(*this);
+
+ m_UIScriptContext->runUIScript(toWTFString(script), scriptCallbackID);
+}
+
+void TestInvocation::uiScriptDidComplete(const String& result, unsigned scriptCallbackID)
+{
+ WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallUISideScriptCallback"));
+
+ WKRetainPtr<WKMutableDictionaryRef> messageBody(AdoptWK, WKMutableDictionaryCreate());
+ WKRetainPtr<WKStringRef> resultKey(AdoptWK, WKStringCreateWithUTF8CString("Result"));
+ WKRetainPtr<WKStringRef> callbackIDKey(AdoptWK, WKStringCreateWithUTF8CString("CallbackID"));
+ WKRetainPtr<WKUInt64Ref> callbackIDValue = adoptWK(WKUInt64Create(scriptCallbackID));
+
+ WKDictionarySetItem(messageBody.get(), resultKey.get(), toWK(result).get());
+ WKDictionarySetItem(messageBody.get(), callbackIDKey.get(), callbackIDValue.get());
+
+ WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), messageBody.get());
}
void TestInvocation::outputText(const WTF::String& text)
@@ -694,4 +1014,34 @@ void TestInvocation::outputText(const WTF::String& text)
m_textOutput.append(text);
}
+void TestInvocation::didBeginSwipe()
+{
+ WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallDidBeginSwipeCallback"));
+ WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
+}
+
+void TestInvocation::willEndSwipe()
+{
+ WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallWillEndSwipeCallback"));
+ WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
+}
+
+void TestInvocation::didEndSwipe()
+{
+ WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallDidEndSwipeCallback"));
+ WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
+}
+
+void TestInvocation::didRemoveSwipeSnapshot()
+{
+ WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallDidRemoveSwipeSnapshotCallback"));
+ WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
+}
+
+void TestInvocation::notifyDownloadDone()
+{
+ WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("NotifyDownloadDone"));
+ WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0);
+}
+
} // namespace WTR
diff --git a/Tools/WebKitTestRunner/TestInvocation.h b/Tools/WebKitTestRunner/TestInvocation.h
index a32678135..df5885c7e 100644
--- a/Tools/WebKitTestRunner/TestInvocation.h
+++ b/Tools/WebKitTestRunner/TestInvocation.h
@@ -26,23 +26,35 @@
#ifndef TestInvocation_h
#define TestInvocation_h
+#include "JSWrappable.h"
+#include "TestOptions.h"
+#include "UIScriptContext.h"
+#include <WebKit/WKRetainPtr.h>
#include <string>
-#include <WebKit2/WKRetainPtr.h>
#include <wtf/Noncopyable.h>
-#include <wtf/OwnPtr.h>
#include <wtf/text/StringBuilder.h>
namespace WTR {
-class TestInvocation {
+class TestInvocation : public UIScriptContextDelegate {
WTF_MAKE_NONCOPYABLE(TestInvocation);
public:
- explicit TestInvocation(const std::string& pathOrURL);
+ explicit TestInvocation(WKURLRef, const TestOptions&);
~TestInvocation();
+ WKURLRef url() const;
+ bool urlContains(const char*) const;
+
+ const TestOptions& options() const { return m_options; }
+
void setIsPixelTest(const std::string& expectedPixelHash);
- void setCustomTimeout(int duration);
+ // Milliseconds
+ void setCustomTimeout(int duration) { m_timeout = duration; }
+ void setDumpJSConsoleLogInStdErr(bool value) { m_dumpJSConsoleLogInStdErr = value; }
+
+ // Seconds
+ double shortTimeout() const;
void invoke();
void didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody);
@@ -51,36 +63,66 @@ public:
void dumpWebProcessUnresponsiveness();
static void dumpWebProcessUnresponsiveness(const char* errorMessage);
void outputText(const WTF::String&);
+
+ void didBeginSwipe();
+ void willEndSwipe();
+ void didEndSwipe();
+ void didRemoveSwipeSnapshot();
+
+ void notifyDownloadDone();
+
private:
void dumpResults();
static void dump(const char* textToStdout, const char* textToStderr = 0, bool seenError = false);
- void dumpPixelsAndCompareWithExpected(WKImageRef, WKArrayRef repaintRects);
+ enum class SnapshotResultType { WebView, WebContents };
+ void dumpPixelsAndCompareWithExpected(WKImageRef, WKArrayRef repaintRects, SnapshotResultType);
void dumpAudio(WKDataRef);
bool compareActualHashToExpectedAndDumpResults(const char[33]);
static void forceRepaintDoneCallback(WKErrorRef, void* context);
+
+ struct UIScriptInvocationData {
+ unsigned callbackID;
+ WebKit::WKRetainPtr<WKStringRef> scriptString;
+ TestInvocation* testInvocation;
+ };
+ static void runUISideScriptAfterUpdateCallback(WKErrorRef, void* context);
- WKRetainPtr<WKURLRef> m_url;
- std::string m_pathOrURL;
+ bool shouldLogFrameLoadDelegates() const;
+ bool shouldLogHistoryClientCallbacks() const;
+
+ void runUISideScript(WKStringRef, unsigned callbackID);
+ // UIScriptContextDelegate
+ void uiScriptDidComplete(const String& result, unsigned callbackID) override;
+
+ const TestOptions m_options;
- bool m_dumpPixels;
+ WKRetainPtr<WKURLRef> m_url;
+ WTF::String m_urlString;
+
std::string m_expectedPixelHash;
- int m_timeout;
+ int m_timeout { 0 };
+ bool m_dumpJSConsoleLogInStdErr { false };
// Invocation state
- bool m_gotInitialResponse;
- bool m_gotFinalMessage;
- bool m_gotRepaint;
- bool m_error;
+ bool m_gotInitialResponse { false };
+ bool m_gotFinalMessage { false };
+ bool m_gotRepaint { false };
+ bool m_error { false };
+
+ bool m_dumpPixels { false };
+ bool m_pixelResultIsPending { false };
+ bool m_webProcessIsUnresponsive { false };
StringBuilder m_textOutput;
WKRetainPtr<WKDataRef> m_audioResult;
WKRetainPtr<WKImageRef> m_pixelResult;
WKRetainPtr<WKArrayRef> m_repaintRects;
std::string m_errorMessage;
- bool m_webProcessIsUnresponsive;
-
+
+ std::unique_ptr<UIScriptContext> m_UIScriptContext;
+ UIScriptInvocationData* m_pendingUIScriptInvocationData { nullptr };
};
} // namespace WTR
diff --git a/Tools/WebKitTestRunner/TestOptions.cpp b/Tools/WebKitTestRunner/TestOptions.cpp
new file mode 100644
index 000000000..d6e8ab238
--- /dev/null
+++ b/Tools/WebKitTestRunner/TestOptions.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "TestOptions.h"
+
+#include <string>
+#include <wtf/text/WTFString.h>
+
+namespace WTR {
+
+static bool pathContains(const std::string& pathOrURL, const char* substring)
+{
+ String path(pathOrURL.c_str());
+ return path.contains(substring); // Case-insensitive.
+}
+
+static bool shouldMakeViewportFlexible(const std::string& pathOrURL)
+{
+ return pathContains(pathOrURL, "viewport/") && !pathContains(pathOrURL, "visual-viewport/");
+}
+
+static bool shouldUseFixedLayout(const std::string& pathOrURL)
+{
+#if ENABLE(CSS_DEVICE_ADAPTATION)
+ if (pathContains(pathOrURL, "device-adapt/") || pathContains(pathOrURL, "device-adapt\\"))
+ return true;
+#endif
+ return false;
+}
+
+static bool isSVGTestPath(const std::string& pathOrURL)
+{
+ return pathContains(pathOrURL, "svg/W3C-SVG-1.1") || pathContains(pathOrURL, "svg\\W3C-SVG-1.1");
+}
+
+static float deviceScaleFactorForTest(const std::string& pathOrURL)
+{
+ if (pathContains(pathOrURL, "/hidpi-3x-"))
+ return 3;
+ if (pathContains(pathOrURL, "/hidpi-"))
+ return 2;
+ return 1;
+}
+
+TestOptions::TestOptions(const std::string& pathOrURL)
+ : useFlexibleViewport(shouldMakeViewportFlexible(pathOrURL))
+ , useFixedLayout(shouldUseFixedLayout(pathOrURL))
+ , isSVGTest(isSVGTestPath(pathOrURL))
+ , deviceScaleFactor(deviceScaleFactorForTest(pathOrURL))
+{
+}
+
+}
diff --git a/Tools/WebKitTestRunner/TestOptions.h b/Tools/WebKitTestRunner/TestOptions.h
new file mode 100644
index 000000000..9c665192c
--- /dev/null
+++ b/Tools/WebKitTestRunner/TestOptions.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TestOptions_h
+#define TestOptions_h
+
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace WTR {
+
+struct TestOptions {
+ bool useThreadedScrolling { false };
+ bool useRemoteLayerTree { false };
+ bool shouldShowWebView { false };
+ bool useFlexibleViewport { false };
+ bool useFixedLayout { false };
+ bool isSVGTest { false };
+ bool useDataDetection { false };
+ bool useMockScrollbars { true };
+ bool needsSiteSpecificQuirks { false };
+ bool ignoresViewportScaleLimits { false };
+ bool useCharacterSelectionGranularity { false };
+ bool enableIntersectionObserver { false };
+ bool enableModernMediaControls { true };
+ bool enablePointerLock { false };
+
+ float deviceScaleFactor { 1 };
+ Vector<String> overrideLanguages;
+
+ TestOptions(const std::string& pathOrURL);
+};
+
+}
+
+#endif // TestOptions_h
diff --git a/Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h b/Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h
index dc958c10e..5f989fc54 100644
--- a/Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h
+++ b/Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h
@@ -27,13 +27,8 @@
#import <Foundation/Foundation.h>
#endif
-#if defined(BUILDING_GTK__)
-#include "autotoolsconfig.h"
-#endif /* defined (BUILDING_GTK__) */
-
+#include <WebKit/WebKit2_C.h>
#include <wtf/Platform.h>
-#include <WebKit2/WebKit2_C.h>
-
/* When C++ exceptions are disabled, the C++ library defines |try| and |catch|
* to allow C++ code that expects exceptions to build. These definitions
diff --git a/Tools/WebKitTestRunner/WebNotificationProvider.cpp b/Tools/WebKitTestRunner/WebNotificationProvider.cpp
index 55064249f..b009b36a3 100644
--- a/Tools/WebKitTestRunner/WebNotificationProvider.cpp
+++ b/Tools/WebKitTestRunner/WebNotificationProvider.cpp
@@ -26,10 +26,11 @@
#include "config.h"
#include "WebNotificationProvider.h"
-#include <WebKit2/WKMutableArray.h>
-#include <WebKit2/WKNotification.h>
-#include <WebKit2/WKNumber.h>
-#include <WebKit2/WKSecurityOrigin.h>
+#include <WebKit/WKMutableArray.h>
+#include <WebKit/WKNotification.h>
+#include <WebKit/WKNotificationManager.h>
+#include <WebKit/WKNumber.h>
+#include <WebKit/WKSecurityOriginRef.h>
#include <wtf/Assertions.h>
namespace WTR {
@@ -65,13 +66,14 @@ WebNotificationProvider::WebNotificationProvider()
WebNotificationProvider::~WebNotificationProvider()
{
- WKNotificationManagerSetProvider(m_notificationManager.get(), 0);
+ for (auto& manager : m_ownedNotifications)
+ WKNotificationManagerSetProvider(manager.key.get(), nullptr);
}
WKNotificationProviderV0 WebNotificationProvider::provider()
{
WKNotificationProviderV0 notificationProvider = {
- { kWKNotificationProviderCurrentVersion, this },
+ { 0, this },
WTR::showWebNotification,
WTR::closeWebNotification,
0, // didDestroyNotification
@@ -83,44 +85,73 @@ WKNotificationProviderV0 WebNotificationProvider::provider()
return notificationProvider;
}
-void WebNotificationProvider::showWebNotification(WKPageRef, WKNotificationRef notification)
+void WebNotificationProvider::showWebNotification(WKPageRef page, WKNotificationRef notification)
{
- if (!m_notificationManager)
- return;
-
+ auto context = WKPageGetContext(page);
+ auto notificationManager = WKContextGetNotificationManager(context);
uint64_t id = WKNotificationGetID(notification);
- ASSERT(!m_shownNotifications.contains(id));
- m_shownNotifications.add(id);
- WKNotificationManagerProviderDidShowNotification(m_notificationManager.get(), WKNotificationGetID(notification));
+ ASSERT(m_ownedNotifications.contains(notificationManager));
+ auto addResult = m_ownedNotifications.find(notificationManager)->value.add(id);
+ ASSERT_UNUSED(addResult, addResult.isNewEntry);
+ auto addResult2 = m_owningManager.set(id, notificationManager);
+ ASSERT_UNUSED(addResult2, addResult2.isNewEntry);
+ auto addResult3 = m_localToGlobalNotificationIDMap.add(std::make_pair(page, WKNotificationManagerGetLocalIDForTesting(notificationManager, notification)), id);
+ ASSERT_UNUSED(addResult3, addResult3.isNewEntry);
+
+ WKNotificationManagerProviderDidShowNotification(notificationManager, id);
}
-void WebNotificationProvider::closeWebNotification(WKNotificationRef notification)
+static void removeGlobalIDFromIDMap(HashMap<std::pair<WKPageRef, uint64_t>, uint64_t>& map, uint64_t id)
{
- if (!m_notificationManager)
- return;
+ for (auto iter = map.begin(); iter != map.end(); ++iter) {
+ if (iter->value == id) {
+ map.remove(iter);
+ return;
+ }
+ }
+ ASSERT_NOT_REACHED();
+}
+void WebNotificationProvider::closeWebNotification(WKNotificationRef notification)
+{
uint64_t id = WKNotificationGetID(notification);
+ ASSERT(m_owningManager.contains(id));
+ auto notificationManager = m_owningManager.get(id);
+
+ ASSERT(m_ownedNotifications.contains(notificationManager));
+ bool success = m_ownedNotifications.find(notificationManager)->value.remove(id);
+ ASSERT_UNUSED(success, success);
+ m_owningManager.remove(id);
+
+ removeGlobalIDFromIDMap(m_localToGlobalNotificationIDMap, id);
+
WKRetainPtr<WKUInt64Ref> wkID = WKUInt64Create(id);
WKRetainPtr<WKMutableArrayRef> array(AdoptWK, WKMutableArrayCreate());
WKArrayAppendItem(array.get(), wkID.get());
- m_shownNotifications.remove(id);
- WKNotificationManagerProviderDidCloseNotifications(m_notificationManager.get(), array.get());
+ WKNotificationManagerProviderDidCloseNotifications(notificationManager, array.get());
}
void WebNotificationProvider::addNotificationManager(WKNotificationManagerRef manager)
{
- // We assume there is only one for testing.
- ASSERT(!m_notificationManager);
- m_notificationManager = manager;
+ m_ownedNotifications.add(manager, HashSet<uint64_t>());
}
void WebNotificationProvider::removeNotificationManager(WKNotificationManagerRef manager)
{
- // We assume there is only one for testing.
- ASSERT(m_notificationManager);
- ASSERT(m_notificationManager.get() == manager);
- m_notificationManager = 0;
+ auto iterator = m_ownedNotifications.find(manager);
+ ASSERT(iterator != m_ownedNotifications.end());
+ auto toRemove = iterator->value;
+ WKRetainPtr<WKNotificationManagerRef> guard(manager);
+ m_ownedNotifications.remove(iterator);
+ WKRetainPtr<WKMutableArrayRef> array = adoptWK(WKMutableArrayCreate());
+ for (uint64_t notificationID : toRemove) {
+ bool success = m_owningManager.remove(notificationID);
+ ASSERT_UNUSED(success, success);
+ removeGlobalIDFromIDMap(m_localToGlobalNotificationIDMap, notificationID);
+ WKArrayAppendItem(array.get(), adoptWK(WKUInt64Create(notificationID)).get());
+ }
+ WKNotificationManagerProviderDidCloseNotifications(manager, array.get());
}
WKDictionaryRef WebNotificationProvider::notificationPermissions()
@@ -129,31 +160,28 @@ WKDictionaryRef WebNotificationProvider::notificationPermissions()
return WKMutableDictionaryCreate();
}
-void WebNotificationProvider::simulateWebNotificationClick(uint64_t notificationID)
+void WebNotificationProvider::simulateWebNotificationClick(WKPageRef page, uint64_t notificationID)
{
- if (!m_notificationManager)
- return;
-
- ASSERT(m_shownNotifications.contains(notificationID));
- WKNotificationManagerProviderDidClickNotification(m_notificationManager.get(), notificationID);
+ ASSERT(m_localToGlobalNotificationIDMap.contains(std::make_pair(page, notificationID)));
+ auto globalID = m_localToGlobalNotificationIDMap.get(std::make_pair(page, notificationID));
+ ASSERT(m_owningManager.contains(globalID));
+ WKNotificationManagerProviderDidClickNotification(m_owningManager.get(globalID), globalID);
}
void WebNotificationProvider::reset()
{
- if (!m_notificationManager) {
- m_shownNotifications.clear();
- return;
+ for (auto& notificationPair : m_ownedNotifications) {
+ if (notificationPair.value.isEmpty())
+ continue;
+ WKRetainPtr<WKMutableArrayRef> array = adoptWK(WKMutableArrayCreate());
+ for (uint64_t notificationID : notificationPair.value)
+ WKArrayAppendItem(array.get(), adoptWK(WKUInt64Create(notificationID)).get());
+
+ notificationPair.value.clear();
+ WKNotificationManagerProviderDidCloseNotifications(notificationPair.key.get(), array.get());
}
-
- WKRetainPtr<WKMutableArrayRef> array(AdoptWK, WKMutableArrayCreate());
- HashSet<uint64_t>::const_iterator itEnd = m_shownNotifications.end();
- for (HashSet<uint64_t>::const_iterator it = m_shownNotifications.begin(); it != itEnd; ++it) {
- WKRetainPtr<WKUInt64Ref> wkID = WKUInt64Create(*it);
- WKArrayAppendItem(array.get(), wkID.get());
- }
-
- m_shownNotifications.clear();
- WKNotificationManagerProviderDidCloseNotifications(m_notificationManager.get(), array.get());
+ m_owningManager.clear();
+ m_localToGlobalNotificationIDMap.clear();
}
} // namespace WTR
diff --git a/Tools/WebKitTestRunner/WebNotificationProvider.h b/Tools/WebKitTestRunner/WebNotificationProvider.h
index fba2870fc..ccf8b1bce 100644
--- a/Tools/WebKitTestRunner/WebNotificationProvider.h
+++ b/Tools/WebKitTestRunner/WebNotificationProvider.h
@@ -26,9 +26,10 @@
#ifndef WebNotificationProvider_h
#define WebNotificationProvider_h
-#include <WebKit2/WKNotificationManager.h>
-#include <WebKit2/WKNotificationProvider.h>
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKNotificationManager.h>
+#include <WebKit/WKNotificationProvider.h>
+#include <WebKit/WKRetainPtr.h>
+#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
namespace WTR {
@@ -45,12 +46,15 @@ public:
void removeNotificationManager(WKNotificationManagerRef);
WKDictionaryRef notificationPermissions();
- void simulateWebNotificationClick(uint64_t notificationID);
+ void simulateWebNotificationClick(WKPageRef, uint64_t notificationID);
void reset();
private:
- WKRetainPtr<WKNotificationManagerRef> m_notificationManager;
- HashSet<uint64_t> m_shownNotifications;
+ // Inverses of each other.
+ HashMap<WKRetainPtr<WKNotificationManagerRef>, HashSet<uint64_t>> m_ownedNotifications;
+ HashMap<uint64_t, WKNotificationManagerRef> m_owningManager;
+
+ HashMap<std::pair<WKPageRef, uint64_t>, uint64_t> m_localToGlobalNotificationIDMap;
};
}
diff --git a/Tools/WebKitTestRunner/WorkQueueManager.cpp b/Tools/WebKitTestRunner/WorkQueueManager.cpp
index e74fa3464..63f491b47 100644
--- a/Tools/WebKitTestRunner/WorkQueueManager.cpp
+++ b/Tools/WebKitTestRunner/WorkQueueManager.cpp
@@ -28,17 +28,17 @@
#include "PlatformWebView.h"
#include "TestController.h"
-#include <WebKit2/WKPage.h>
-#include <WebKit2/WKRetainPtr.h>
+#include <WebKit/WKPage.h>
+#include <WebKit/WKPagePrivate.h>
+#include <WebKit/WKRetainPtr.h>
#include <stdio.h>
-#include <wtf/PassOwnPtr.h>
#include <wtf/text/CString.h>
namespace WTR {
static inline WKPageRef mainPage()
{
- return TestController::shared().mainWebView()->page();
+ return TestController::singleton().mainWebView()->page();
}
static inline bool goToItemAtIndex(int index)
@@ -119,20 +119,21 @@ bool WorkQueueManager::processWorkQueue()
{
m_processing = false;
while (!m_processing && !m_workQueue.isEmpty()) {
- OwnPtr<WorkQueueItem> item(m_workQueue.takeFirst());
+ std::unique_ptr<WorkQueueItem> item(m_workQueue.takeFirst());
m_processing = (item->invoke() == WorkQueueItem::Loading);
}
return !m_processing;
}
-void WorkQueueManager::queueLoad(const String& url, const String& target)
+void WorkQueueManager::queueLoad(const String& url, const String& target, bool shouldOpenExternalURLs)
{
class LoadItem : public WorkQueueItem {
public:
- LoadItem(const String& url, const String& target)
+ LoadItem(const String& url, const String& target, bool shouldOpenExternalURLs)
: m_url(AdoptWK, WKURLCreateWithUTF8CString(url.utf8().data()))
, m_target(target)
+ , m_shouldOpenExternalURLs(shouldOpenExternalURLs)
{
}
@@ -143,15 +144,16 @@ void WorkQueueManager::queueLoad(const String& url, const String& target)
fprintf(stderr, "queueLoad for a specific target is not implemented.\n");
return WorkQueueItem::NonLoading;
}
- WKPageLoadURL(mainPage(), m_url.get());
+ WKPageLoadURLWithShouldOpenExternalURLsPolicy(mainPage(), m_url.get(), m_shouldOpenExternalURLs);
return WorkQueueItem::Loading;
}
WKRetainPtr<WKURLRef> m_url;
String m_target;
+ bool m_shouldOpenExternalURLs;
};
- enqueue(new LoadItem(url, target));
+ enqueue(new LoadItem(url, target, shouldOpenExternalURLs));
}
void WorkQueueManager::queueLoadHTMLString(const String& content, const String& baseURL, const String& unreachableURL)
@@ -222,7 +224,7 @@ void WorkQueueManager::enqueue(WorkQueueItem* item)
return;
}
- m_workQueue.append(adoptPtr(item));
+ m_workQueue.append(std::unique_ptr<WorkQueueItem>(item));
}
} // namespace WTR
diff --git a/Tools/WebKitTestRunner/WorkQueueManager.h b/Tools/WebKitTestRunner/WorkQueueManager.h
index 21d5ebb88..273d51191 100644
--- a/Tools/WebKitTestRunner/WorkQueueManager.h
+++ b/Tools/WebKitTestRunner/WorkQueueManager.h
@@ -27,7 +27,6 @@
#define WorkQueueManager_h
#include <wtf/Deque.h>
-#include <wtf/OwnPtr.h>
#include <wtf/text/WTFString.h>
namespace WTR {
@@ -42,7 +41,7 @@ public:
void clearWorkQueue();
bool processWorkQueue(); // Returns 'true' if queue is processed (no new loading is started), returns 'false' otherwise.
- void queueLoad(const String& url, const String& target);
+ void queueLoad(const String& url, const String& target, bool shouldOpenExternalURLs);
void queueLoadHTMLString(const String& content, const String& baseURL, const String& unreachableURL);
void queueBackNavigation(unsigned howFarBackward);
void queueForwardNavigation(unsigned howFarForward);
@@ -51,7 +50,7 @@ public:
void queueNonLoadingScript(const String& script);
private:
- typedef Deque<OwnPtr<class WorkQueueItem> > WorkQueue;
+ typedef Deque<std::unique_ptr<class WorkQueueItem>> WorkQueue;
void enqueue(WorkQueueItem*); // Adopts pointer.
diff --git a/Tools/WebKitTestRunner/cairo/TestInvocationCairo.cpp b/Tools/WebKitTestRunner/cairo/TestInvocationCairo.cpp
index 828e65b1b..376f31986 100644
--- a/Tools/WebKitTestRunner/cairo/TestInvocationCairo.cpp
+++ b/Tools/WebKitTestRunner/cairo/TestInvocationCairo.cpp
@@ -32,7 +32,7 @@
#include "PixelDumpSupport.h"
#include "PlatformWebView.h"
#include "TestController.h"
-#include <WebKit2/WKImageCairo.h>
+#include <WebKit/WKImageCairo.h>
#include <cairo/cairo.h>
#include <cstdio>
#include <wtf/Assertions.h>
@@ -106,14 +106,9 @@ static void paintRepaintRectOverlay(cairo_surface_t* surface, WKArrayRef repaint
cairo_destroy(context);
}
-void TestInvocation::dumpPixelsAndCompareWithExpected(WKImageRef wkImage, WKArrayRef repaintRects)
+void TestInvocation::dumpPixelsAndCompareWithExpected(WKImageRef image, WKArrayRef repaintRects, SnapshotResultType)
{
-#if USE(ACCELERATED_COMPOSITING) && PLATFORM(EFL)
- UNUSED_PARAM(wkImage);
- cairo_surface_t* surface = WKImageCreateCairoSurface(TestController::shared().mainWebView()->windowSnapshotImage().get());
-#else
- cairo_surface_t* surface = WKImageCreateCairoSurface(wkImage);
-#endif
+ cairo_surface_t* surface = WKImageCreateCairoSurface(image);
if (repaintRects)
paintRepaintRectOverlay(surface, repaintRects);
diff --git a/Tools/DumpRenderTree/gtk/EditingCallbacks.h b/Tools/WebKitTestRunner/config.h
index 7a9514917..4042b715b 100644
--- a/Tools/DumpRenderTree/gtk/EditingCallbacks.h
+++ b/Tools/WebKitTestRunner/config.h
@@ -1,35 +1,38 @@
/*
- * Copyright (C) 2010 Igalia S.L.
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
- *
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+
+#ifndef WebKitTestRunner_config_h
+#define WebKitTestRunner_config_h
-#ifndef EditingCallbacks_h
-#define EditingCallbacks_h
+#if defined (BUILDING_WITH_CMAKE)
+#include "cmakeconfig.h"
+#endif
-typedef struct _WebKitWebView WebKitWebView;
-void connectEditingCallbacks(WebKitWebView*);
+#include <WebCore/PlatformExportMacros.h>
+#include <WebKit/WebKit2_C.h>
+#include <wtf/Platform.h>
+#include <wtf/ExportMacros.h>
+#include <runtime/JSExportMacros.h>
#endif
diff --git a/Tools/WebKitTestRunner/gtk/EventSenderProxyGtk.cpp b/Tools/WebKitTestRunner/gtk/EventSenderProxyGtk.cpp
index d25320125..e93caf5aa 100644
--- a/Tools/WebKitTestRunner/gtk/EventSenderProxyGtk.cpp
+++ b/Tools/WebKitTestRunner/gtk/EventSenderProxyGtk.cpp
@@ -14,7 +14,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -39,7 +39,7 @@
#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
#include <wtf/StdLibExtras.h>
-#include <wtf/gobject/GUniquePtr.h>
+#include <wtf/glib/GUniquePtr.h>
#include <wtf/text/WTFString.h>
namespace WTR {
@@ -122,6 +122,8 @@ static guint webkitModifiersToGDKModifiers(WKEventModifiers wkModifiers)
modifiers |= GDK_MOD1_MASK;
if (wkModifiers & kWKEventModifiersMetaKey)
modifiers |= GDK_META_MASK;
+ if (wkModifiers & kWKEventModifiersCapsLockKey)
+ modifiers |= GDK_LOCK_MASK;
return modifiers;
}
@@ -162,8 +164,9 @@ void EventSenderProxy::updateClickCountForButton(int button)
m_clickButton = button;
}
-static void dispatchEvent(GdkEvent* event)
+void EventSenderProxy::dispatchEvent(GdkEvent* event)
{
+ ASSERT(m_testController->mainWebView());
gtk_main_do_event(event);
gdk_event_free(event);
}
@@ -217,6 +220,18 @@ int getGDKKeySymForKeyRef(WKStringRef keyRef, unsigned location, guint* modifier
return GDK_KEY_VoidSymbol;
}
+ if (WKStringIsEqualToUTF8CString(keyRef, "leftControl"))
+ return GDK_KEY_Control_L;
+ if (WKStringIsEqualToUTF8CString(keyRef, "rightControl"))
+ return GDK_KEY_Control_R;
+ if (WKStringIsEqualToUTF8CString(keyRef, "leftShift"))
+ return GDK_KEY_Shift_L;
+ if (WKStringIsEqualToUTF8CString(keyRef, "rightShift"))
+ return GDK_KEY_Shift_R;
+ if (WKStringIsEqualToUTF8CString(keyRef, "leftAlt"))
+ return GDK_KEY_Alt_L;
+ if (WKStringIsEqualToUTF8CString(keyRef, "rightAlt"))
+ return GDK_KEY_Alt_R;
if (WKStringIsEqualToUTF8CString(keyRef, "leftArrow"))
return GDK_KEY_Left;
if (WKStringIsEqualToUTF8CString(keyRef, "rightArrow"))
@@ -277,6 +292,8 @@ int getGDKKeySymForKeyRef(WKStringRef keyRef, unsigned location, guint* modifier
return GDK_KEY_Tab;
if (charCode == '\x8')
return GDK_KEY_BackSpace;
+ if (charCode == 0x001B)
+ return GDK_KEY_Escape;
if (WTF::isASCIIUpper(charCode))
*modifiers |= GDK_SHIFT_MASK;
@@ -416,7 +433,10 @@ void EventSenderProxy::mouseScrollBy(int horizontal, int vertical)
void EventSenderProxy::continuousMouseScrollBy(int horizontal, int vertical, bool paged)
{
// Gtk+ does not support paged scroll events.
- g_return_if_fail(!paged);
+ if (paged) {
+ WTFLogAlways("EventSenderProxy::continuousMouseScrollBy not implemented for paged scroll events");
+ return;
+ }
GdkEvent* event = gdk_event_new(GDK_SCROLL);
event->scroll.x = m_position.x;
@@ -433,6 +453,18 @@ void EventSenderProxy::continuousMouseScrollBy(int horizontal, int vertical, boo
sendOrQueueEvent(event);
}
+void EventSenderProxy::mouseScrollByWithWheelAndMomentumPhases(int x, int y, int /*phase*/, int /*momentum*/)
+{
+ // Gtk+ does not have the concept of wheel gesture phases or momentum. Just relay to
+ // the mouse wheel handler.
+ mouseScrollBy(x, y);
+}
+
+void EventSenderProxy::swipeGestureWithWheelAndMomentumPhases(int, int, int, int)
+{
+ notImplemented();
+}
+
void EventSenderProxy::leapForward(int milliseconds)
{
if (m_eventQueue.isEmpty())
@@ -466,6 +498,7 @@ GUniquePtr<GdkEvent> EventSenderProxy::createTouchEvent(GdkEventType eventType,
return touchEvent;
}
+#if ENABLE(TOUCH_EVENTS)
void EventSenderProxy::addTouchPoint(int x, int y)
{
// Touch ID is array index plus one, so 0 is skipped.
@@ -556,6 +589,6 @@ void EventSenderProxy::setTouchModifier(WKEventModifiers modifier, bool enable)
m_updatedTouchEvents.add(GPOINTER_TO_INT(event->touch.sequence));
}
}
-
+#endif // ENABLE(TOUCH_EVENTS)
} // namespace WTR
diff --git a/Tools/WebKitTestRunner/gtk/PlatformWebViewGtk.cpp b/Tools/WebKitTestRunner/gtk/PlatformWebViewGtk.cpp
index fd6f8466b..eb0a08d74 100644
--- a/Tools/WebKitTestRunner/gtk/PlatformWebViewGtk.cpp
+++ b/Tools/WebKitTestRunner/gtk/PlatformWebViewGtk.cpp
@@ -28,13 +28,17 @@
#include "config.h"
#include "PlatformWebView.h"
-#include <WebKit2/WKViewPrivate.h>
+#include <WebKit/WKImageCairo.h>
+#include <WebKit/WKPageConfigurationRef.h>
+#include <WebKit/WKView.h>
+#include <WebKit/WKViewPrivate.h>
#include <gtk/gtk.h>
+#include <wtf/Assertions.h>
namespace WTR {
-PlatformWebView::PlatformWebView(WKContextRef context, WKPageGroupRef pageGroup, WKPageRef /* relatedPage */, WKDictionaryRef options)
- : m_view(WKViewCreate(context, pageGroup))
+PlatformWebView::PlatformWebView(WKPageConfigurationRef configuration, const TestOptions& options)
+ : m_view(WKViewCreate(configuration))
, m_window(gtk_window_new(GTK_WINDOW_POPUP))
, m_windowIsKey(true)
, m_options(options)
@@ -42,7 +46,7 @@ PlatformWebView::PlatformWebView(WKContextRef context, WKPageGroupRef pageGroup,
gtk_container_add(GTK_CONTAINER(m_window), GTK_WIDGET(m_view));
GtkAllocation size = { 0, 0, 800, 600 };
- gtk_widget_size_allocate(m_window, &size);
+ gtk_widget_size_allocate(GTK_WIDGET(m_view), &size);
gtk_window_resize(GTK_WINDOW(m_window), 800, 600);
gtk_widget_show_all(m_window);
@@ -55,14 +59,17 @@ PlatformWebView::~PlatformWebView()
gtk_widget_destroy(m_window);
}
-void PlatformWebView::resizeTo(unsigned width, unsigned height)
+void PlatformWebView::setWindowIsKey(bool isKey)
{
- GtkAllocation size = { 0, 0, static_cast<int>(width), static_cast<int>(height) };
- gtk_widget_size_allocate(m_window, &size);
- gtk_window_resize(GTK_WINDOW(m_window), width, height);
+ m_windowIsKey = isKey;
+}
- while (gtk_events_pending())
- gtk_main_iteration();
+void PlatformWebView::resizeTo(unsigned width, unsigned height, WebViewSizingMode sizingMode)
+{
+ WKRect frame = windowFrame();
+ frame.size.width = width;
+ frame.size.height = height;
+ setWindowFrame(frame, sizingMode);
}
WKPageRef PlatformWebView::page()
@@ -79,14 +86,8 @@ void PlatformWebView::focus()
WKRect PlatformWebView::windowFrame()
{
GtkAllocation geometry;
-#ifdef GTK_API_VERSION_2
- gint depth;
- gdk_window_get_geometry(gtk_widget_get_window(GTK_WIDGET(m_window)),
- &geometry.x, &geometry.y, &geometry.width, &geometry.height, &depth);
-#else
gdk_window_get_geometry(gtk_widget_get_window(GTK_WIDGET(m_window)),
&geometry.x, &geometry.y, &geometry.width, &geometry.height);
-#endif
WKRect frame;
frame.origin.x = geometry.x;
@@ -96,10 +97,15 @@ WKRect PlatformWebView::windowFrame()
return frame;
}
-void PlatformWebView::setWindowFrame(WKRect frame)
+void PlatformWebView::setWindowFrame(WKRect frame, WebViewSizingMode)
{
- gtk_window_move(GTK_WINDOW(m_window), frame.origin.x, frame.origin.y);
- resizeTo(frame.size.width, frame.size.height);
+ gdk_window_move_resize(gtk_widget_get_window(GTK_WIDGET(m_window)),
+ frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
+ GtkAllocation size = { 0, 0, static_cast<int>(frame.size.width), static_cast<int>(frame.size.height) };
+ gtk_widget_size_allocate(GTK_WIDGET(m_view), &size);
+
+ while (gtk_events_pending())
+ gtk_main_iteration();
}
void PlatformWebView::addChromeInputField()
@@ -110,20 +116,65 @@ void PlatformWebView::removeChromeInputField()
{
}
+void PlatformWebView::addToWindow()
+{
+}
+
+void PlatformWebView::removeFromWindow()
+{
+}
+
void PlatformWebView::makeWebViewFirstResponder()
{
}
+void PlatformWebView::changeWindowScaleIfNeeded(float)
+{
+}
+
WKRetainPtr<WKImageRef> PlatformWebView::windowSnapshotImage()
{
- // FIXME: implement to capture pixels in the UI process,
- // which may be necessary to capture things like 3D transforms.
- return 0;
+ int width = gtk_widget_get_allocated_width(GTK_WIDGET(m_view));
+ int height = gtk_widget_get_allocated_height(GTK_WIDGET(m_view));
+
+ while (gtk_events_pending())
+ gtk_main_iteration();
+
+ cairo_surface_t* imageSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+
+ cairo_t* context = cairo_create(imageSurface);
+ gtk_widget_draw(GTK_WIDGET(m_view), context);
+ cairo_destroy(context);
+
+ WKRetainPtr<WKImageRef> wkImage = adoptWK(WKImageCreateFromCairoSurface(imageSurface, 0 /* options */));
+
+ cairo_surface_destroy(imageSurface);
+ return wkImage;
}
void PlatformWebView::didInitializeClients()
{
}
+bool PlatformWebView::viewSupportsOptions(const TestOptions&) const
+{
+ return true;
+}
+
+void PlatformWebView::dismissAllPopupMenus()
+{
+ // gtk_menu_popdown doesn't modify the GList of attached menus, so it should
+ // be safe to walk this list while calling it.
+ GList* attachedMenusList = gtk_menu_get_for_attach_widget(GTK_WIDGET(m_view));
+ g_list_foreach(attachedMenusList, [] (void* data, void*) {
+ ASSERT(data);
+ gtk_menu_popdown(GTK_MENU(data));
+ }, nullptr);
+}
+
+void PlatformWebView::setNavigationGesturesEnabled(bool)
+{
+}
+
} // namespace WTR
diff --git a/Tools/WebKitTestRunner/gtk/TestControllerGtk.cpp b/Tools/WebKitTestRunner/gtk/TestControllerGtk.cpp
index d8fb9f728..62d031a87 100644
--- a/Tools/WebKitTestRunner/gtk/TestControllerGtk.cpp
+++ b/Tools/WebKitTestRunner/gtk/TestControllerGtk.cpp
@@ -27,52 +27,68 @@
#include "config.h"
#include "TestController.h"
+#include "PlatformWebView.h"
#include <gtk/gtk.h>
#include <wtf/Platform.h>
-#include <wtf/gobject/GUniquePtr.h>
+#include <wtf/RunLoop.h>
+#include <wtf/glib/GRefPtr.h>
+#include <wtf/glib/GUniquePtr.h>
#include <wtf/text/WTFString.h>
namespace WTR {
-static guint gTimeoutSourceId = 0;
-
-static void cancelTimeout()
+static GSource* timeoutSource()
{
- if (!gTimeoutSourceId)
- return;
- g_source_remove(gTimeoutSourceId);
- gTimeoutSourceId = 0;
+ static GRefPtr<GSource> source = nullptr;
+ if (!source) {
+ source = adoptGRef(g_timeout_source_new(0));
+ g_source_set_ready_time(source.get(), -1);
+ g_source_set_name(source.get(), "[WTR] Test timeout source");
+ g_source_set_callback(source.get(), [](gpointer userData) -> gboolean {
+ g_source_set_ready_time(static_cast<GSource*>(userData), -1);
+ fprintf(stderr, "FAIL: TestControllerRunLoop timed out.\n");
+ RunLoop::main().stop();
+ return G_SOURCE_REMOVE;
+ }, source.get(), nullptr);
+ g_source_attach(source.get(), nullptr);
+ }
+ return source.get();
}
void TestController::notifyDone()
{
- gtk_main_quit();
- cancelTimeout();
+ g_source_set_ready_time(timeoutSource(), -1);
+ RunLoop::main().stop();
}
void TestController::platformInitialize()
{
}
-void TestController::platformDestroy()
+WKPreferencesRef TestController::platformPreferences()
{
+ return WKPageGroupGetPreferences(m_pageGroup.get());
}
-static gboolean timeoutCallback(gpointer)
+void TestController::platformDestroy()
{
- fprintf(stderr, "FAIL: TestControllerRunLoop timed out.\n");
- gtk_main_quit();
- return FALSE;
}
void TestController::platformRunUntil(bool&, double timeout)
{
- cancelTimeout();
- if (timeout != m_noTimeout) {
- gTimeoutSourceId = g_timeout_add(timeout * 1000, timeoutCallback, 0);
- g_source_set_name_by_id(gTimeoutSourceId, "[WebKit] timeoutCallback");
- }
- gtk_main();
+ if (timeout > 0) {
+ // FIXME: This conversion is now repeated in several places, it should be moved to a common place in WTF and used everywhere.
+ auto timeoutDuration = std::chrono::duration<double>(timeout);
+ auto safeDuration = std::chrono::microseconds::max();
+ if (timeoutDuration < safeDuration)
+ safeDuration = std::chrono::duration_cast<std::chrono::microseconds>(timeoutDuration);
+ gint64 currentTime = g_get_monotonic_time();
+ gint64 targetTime = currentTime + std::min<gint64>(G_MAXINT64 - currentTime, safeDuration.count());
+ ASSERT(targetTime >= currentTime);
+ g_source_set_ready_time(timeoutSource(), targetTime);
+ } else
+ g_source_set_ready_time(timeoutSource(), -1);
+ RunLoop::main().run();
}
static char* getEnvironmentVariableAsUTF8String(const char* variableName)
@@ -102,9 +118,14 @@ void TestController::platformInitializeContext()
{
}
-void TestController::setHidden(bool)
+void TestController::setHidden(bool hidden)
{
- // FIXME: Need to implement this to test visibilityState.
+ if (!m_mainWebView)
+ return;
+ if (hidden)
+ gtk_widget_unmap(GTK_WIDGET(m_mainWebView->platformView()));
+ else
+ gtk_widget_map(GTK_WIDGET(m_mainWebView->platformView()));
}
void TestController::runModal(PlatformWebView*)
@@ -117,4 +138,20 @@ const char* TestController::platformLibraryPathForTesting()
return 0;
}
+void TestController::platformConfigureViewForTest(const TestInvocation&)
+{
+ WKPageSetApplicationNameForUserAgent(mainWebView()->page(), WKStringCreateWithUTF8CString("WebKitTestRunnerGTK"));
+}
+
+void TestController::platformResetPreferencesToConsistentValues()
+{
+ if (!m_mainWebView)
+ return;
+ m_mainWebView->dismissAllPopupMenus();
+}
+
+void TestController::updatePlatformSpecificTestOptionsForTest(TestOptions&, const std::string&) const
+{
+}
+
} // namespace WTR
diff --git a/Tools/WebKitTestRunner/gtk/fonts/AHEM____.TTF b/Tools/WebKitTestRunner/gtk/fonts/AHEM____.TTF
new file mode 100644
index 000000000..ac81cb031
--- /dev/null
+++ b/Tools/WebKitTestRunner/gtk/fonts/AHEM____.TTF
Binary files differ
diff --git a/Tools/WebKitTestRunner/gtk/fonts/FontWithNoValidEncoding.fon b/Tools/WebKitTestRunner/gtk/fonts/FontWithNoValidEncoding.fon
new file mode 100644
index 000000000..8fff7d9c1
--- /dev/null
+++ b/Tools/WebKitTestRunner/gtk/fonts/FontWithNoValidEncoding.fon
Binary files differ
diff --git a/Tools/WebKitTestRunner/gtk/fonts/fonts.conf b/Tools/WebKitTestRunner/gtk/fonts/fonts.conf
new file mode 100644
index 000000000..2387e9581
--- /dev/null
+++ b/Tools/WebKitTestRunner/gtk/fonts/fonts.conf
@@ -0,0 +1,435 @@
+<?xml version="1.0"?>
+<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
+<fontconfig>
+
+ <!-- Due to patent (http://freetype.sourceforge.net/patents.html)
+ issues hinting gives different results depending on the
+ freetype version of the linux distribution, avoiding hinting
+ gives more consistent results. When all the distributions
+ release freetype the 2.4, which enables by default the
+ hinting method that was patented, we could undo this change
+ and try the hinting again. -->
+ <match target="font">
+ <edit name="hinting" mode="assign">
+ <bool>false</bool>
+ </edit>
+ </match>
+
+ <!-- This system may have turned off selection of bitmap fonts, but
+ we must turn it on again, because we want to be able to test that
+ bitmap fonts with no valid encodings are *never* selected regardless
+ of the Fontconfig settings. So force Fontconfig to select our cruddy
+ bitmap font -->
+ <selectfont>
+ <acceptfont>
+ <pattern>
+ <patelt name="family">
+ <string>FontWithNoValidEncoding</string>
+ </patelt>
+ </pattern>
+ </acceptfont>
+ </selectfont>
+
+ <!-- The sans-serif font should be Liberation Serif -->
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>serif</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Serif</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>Times</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Serif</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>Times New Roman</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Serif</string>
+ </edit>
+ </match>
+
+ <!-- Until we find good fonts to use for cursive and fantasy
+ just use our serif font. -->
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>cursive</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Serif</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>fantasy</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Serif</string>
+ </edit>
+ </match>
+
+ <!-- The sans-serif font should be Liberation Sans -->
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>sans serif</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Sans</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>sans</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Sans</string>
+ </edit>
+ </match>
+ <!-- We need to ensure that layout tests that use "Helvetica" don't
+ fall back to the default serif font -->
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>Helvetica</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Sans</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>Arial</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Sans</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>Lucida Grande</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Sans</string>
+ </edit>
+ </match>
+
+ <!-- The Monospace font should be Liberation Mono -->
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>monospace</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Mono</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>mono</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Mono</string>
+ </edit>
+ </match>
+ <!-- We need to ensure that layout tests that use "Courier", "Courier New",
+ and "Monaco" (all monospace fonts) don't fall back to the default
+ serif font -->
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>Courier</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Mono</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>Courier New</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Mono</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>Monaco</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Mono</string>
+ </edit>
+ </match>
+
+ <!-- The following hinting specializations are adapted from those in the
+ Chromium test_shell. We try to duplicate their incredibly thorough
+ testing here -->
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>NonAntiAliasedSans</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Sans</string>
+ </edit>
+ <edit name="antialias" mode="assign">
+ <bool>false</bool>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>SlightHintedSerif</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Serif</string>
+ </edit>
+ <edit name="hinting" mode="assign">
+ <bool>true</bool>
+ </edit>
+ <edit name="hintstyle" mode="assign">
+ <const>hintslight</const>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>NonHintedSans</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Sans</string>
+ </edit>
+ <!-- These deliberately contradict each other. The 'hinting' preference
+ should take priority -->
+ <edit name="hintstyle" mode="assign">
+ <const>hintfull</const>
+ </edit>
+ <edit name="hinting" mode="assign">
+ <bool>false</bool>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>AutohintedSerif</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Serif</string>
+ </edit>
+ <edit name="hinting" mode="assign">
+ <bool>true</bool>
+ </edit>
+ <edit name="autohint" mode="assign">
+ <bool>true</bool>
+ </edit>
+ <edit name="hintstyle" mode="assign">
+ <const>hintmedium</const>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>HintedSerif</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Serif</string>
+ </edit>
+ <edit name="hinting" mode="assign">
+ <bool>true</bool>
+ </edit>
+ <edit name="autohint" mode="assign">
+ <bool>false</bool>
+ </edit>
+ <edit name="hintstyle" mode="assign">
+ <const>hintmedium</const>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>FullAndAutoHintedSerif</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Serif</string>
+ </edit>
+ <edit name="hinting" mode="assign">
+ <bool>true</bool>
+ </edit>
+ <edit name="autohint" mode="assign">
+ <bool>true</bool>
+ </edit>
+ <edit name="hintstyle" mode="assign">
+ <const>hintfull</const>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>SubpixelEnabledSans</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Sans</string>
+ </edit>
+ <edit name="rgba" mode="assign">
+ <const>rgb</const>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>SubpixelDisabledSans</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Sans</string>
+ </edit>
+ <edit name="rgba" mode="assign">
+ <const>none</const>
+ </edit>
+ </match>
+
+ <!-- We need to enable simulated bold to for DejaVu Serif to ensure that we interpret
+ this property correctly in: platform/gtk/fonts/fontconfig-synthetic-bold.html -->
+ <match target="font">
+ <test qual="any" name="family">
+ <string>DejaVu Serif</string>
+ </test>
+ <test name="weight" compare="less_eq">
+ <const>medium</const>
+ </test>
+ <test target="pattern" name="weight" compare="more">
+ <const>medium</const>
+ </test>
+ <edit name="embolden" mode="assign">
+ <bool>true</bool>
+ </edit>
+ <edit name="weight" mode="assign">
+ <const>bold</const>
+ </edit>
+ </match>
+
+ <!-- We need to enable simulated oblique to for DejaVu Serif to ensure that we interpret
+ this property correctly in: platform/gtk/fonts/fontconfig-synthetic-oblique.html -->
+ <match target="font">
+ <test qual="any" name="family">
+ <string>DejaVu Serif</string>
+ </test>
+ <test name="slant">
+ <const>roman</const>
+ </test>
+ <test target="pattern" name="slant" compare="not_eq">
+ <const>roman</const>
+ </test>
+ <edit name="matrix" mode="assign">
+ <times>
+ <name>matrix</name>
+ <matrix><double>1</double><double>0.2</double>
+ <double>0</double><double>1</double>
+ </matrix>
+ </times>
+ </edit>
+ <edit name="slant" mode="assign">
+ <const>oblique</const>
+ </edit>
+ <edit name="embeddedbitmap" mode="assign">
+ <bool>false</bool>
+ </edit>
+ </match>
+
+ <!-- These fonts should be treated as identical by CSS font fallback. -->
+ <alias binding="same">
+ <family>FamilyStrongAliasedToFreeMono</family>
+ <accept>
+ <family>FreeMono</family>
+ </accept>
+ </alias>
+
+ <!-- These fonts should NOT be treated as identical by CSS font fallback. -->
+ <alias>
+ <family>FamilyWeakAliasedToFreeMono</family>
+ <accept>
+ <family>FreeMono</family>
+ </accept>
+ </alias>
+
+ <!-- If this font doesn't have a family name we are falling back. The fallback
+ font will certainly be one of the DejaVu fonts that we have in our
+ collection since they have a wide range of characters. Fontconfig might
+ choose DejaVu Sans or DejaVu Serif depending on the system, so we force
+ the use of DejaVu Sans in these situations to maintain consistency. -->
+ <match target="pattern">
+ <test qual="all" name="family" compare="eq">
+ <string></string>
+ </test>
+ <edit name="family" mode="append_last">
+ <string>DejaVu Sans</string>
+ </edit>
+ </match>
+
+ <config>
+ <!-- These are the default Unicode chars that are expected to be blank
+ in fonts. All other blank chars are assumed to be broken and won't
+ appear in the resulting charsets -->
+ <blank>
+ <int>0x0020</int> <!-- SPACE -->
+ <int>0x00A0</int> <!-- NO-BREAK SPACE -->
+ <int>0x00AD</int> <!-- SOFT HYPHEN -->
+ <int>0x034F</int> <!-- COMBINING GRAPHEME JOINER -->
+ <int>0x0600</int> <!-- ARABIC NUMBER SIGN -->
+ <int>0x0601</int> <!-- ARABIC SIGN SANAH -->
+ <int>0x0602</int> <!-- ARABIC FOOTNOTE MARKER -->
+ <int>0x0603</int> <!-- ARABIC SIGN SAFHA -->
+ <int>0x06DD</int> <!-- ARABIC END OF AYAH -->
+ <int>0x070F</int> <!-- SYRIAC ABBREVIATION MARK -->
+ <int>0x115F</int> <!-- HANGUL CHOSEONG FILLER -->
+ <int>0x1160</int> <!-- HANGUL JUNGSEONG FILLER -->
+ <int>0x1680</int> <!-- OGHAM SPACE MARK -->
+ <int>0x17B4</int> <!-- KHMER VOWEL INHERENT AQ -->
+ <int>0x17B5</int> <!-- KHMER VOWEL INHERENT AA -->
+ <int>0x180E</int> <!-- MONGOLIAN VOWEL SEPARATOR -->
+ <int>0x2000</int> <!-- EN QUAD -->
+ <int>0x2001</int> <!-- EM QUAD -->
+ <int>0x2002</int> <!-- EN SPACE -->
+ <int>0x2003</int> <!-- EM SPACE -->
+ <int>0x2004</int> <!-- THREE-PER-EM SPACE -->
+ <int>0x2005</int> <!-- FOUR-PER-EM SPACE -->
+ <int>0x2006</int> <!-- SIX-PER-EM SPACE -->
+ <int>0x2007</int> <!-- FIGURE SPACE -->
+ <int>0x2008</int> <!-- PUNCTUATION SPACE -->
+ <int>0x2009</int> <!-- THIN SPACE -->
+ <int>0x200A</int> <!-- HAIR SPACE -->
+ <int>0x200B</int> <!-- ZERO WIDTH SPACE -->
+ <int>0x200C</int> <!-- ZERO WIDTH NON-JOINER -->
+ <int>0x200D</int> <!-- ZERO WIDTH JOINER -->
+ <int>0x200E</int> <!-- LEFT-TO-RIGHT MARK -->
+ <int>0x200F</int> <!-- RIGHT-TO-LEFT MARK -->
+ <int>0x2028</int> <!-- LINE SEPARATOR -->
+ <int>0x2029</int> <!-- PARAGRAPH SEPARATOR -->
+ <int>0x202A</int> <!-- LEFT-TO-RIGHT EMBEDDING -->
+ <int>0x202B</int> <!-- RIGHT-TO-LEFT EMBEDDING -->
+ <int>0x202C</int> <!-- POP DIRECTIONAL FORMATTING -->
+ <int>0x202D</int> <!-- LEFT-TO-RIGHT override -->
+ <int>0x202E</int> <!-- RIGHT-TO-LEFT override -->
+ <int>0x202F</int> <!-- NARROW NO-BREAK SPACE -->
+ <int>0x205F</int> <!-- MEDIUM MATHEMATICAL SPACE -->
+ <int>0x2060</int> <!-- WORD JOINER -->
+ <int>0x2061</int> <!-- FUNCTION APPLICATION -->
+ <int>0x2062</int> <!-- INVISIBLE TIMES -->
+ <int>0x2063</int> <!-- INVISIBLE SEPARATOR -->
+ <int>0x206A</int> <!-- INHIBIT SYMMETRIC SWAPPING -->
+ <int>0x206B</int> <!-- ACTIVATE SYMMETRIC SWAPPING -->
+ <int>0x206C</int> <!-- INHIBIT ARABIC FORM SHAPING -->
+ <int>0x206D</int> <!-- ACTIVATE ARABIC FORM SHAPING -->
+ <int>0x206E</int> <!-- NATIONAL DIGIT SHAPES -->
+ <int>0x206F</int> <!-- NOMINAL DIGIT SHAPES -->
+ <int>0x3000</int> <!-- IDEOGRAPHIC SPACE -->
+ <int>0x3164</int> <!-- HANGUL FILLER -->
+ <int>0xFEFF</int> <!-- ZERO WIDTH NO-BREAK SPACE -->
+ <int>0xFFA0</int> <!-- HALFWIDTH HANGUL FILLER -->
+ <int>0xFFF9</int> <!-- INTERLINEAR ANNOTATION ANCHOR -->
+ <int>0xFFFA</int> <!-- INTERLINEAR ANNOTATION SEPARATOR -->
+ <int>0xFFFB</int> <!-- INTERLINEAR ANNOTATION TERMINATOR -->
+ </blank>
+ </config>
+</fontconfig>
diff --git a/Tools/WebKitTestRunner/gtk/main.cpp b/Tools/WebKitTestRunner/gtk/main.cpp
index d53c6248a..7947ce55c 100644
--- a/Tools/WebKitTestRunner/gtk/main.cpp
+++ b/Tools/WebKitTestRunner/gtk/main.cpp
@@ -26,12 +26,21 @@
#include "config.h"
#include "TestController.h"
+#include <WebKit/WKTextCheckerGtk.h>
#include <gtk/gtk.h>
+#include <wtf/glib/GRefPtr.h>
int main(int argc, char** argv)
{
gtk_init(&argc, &argv);
+
+ GRefPtr<GPtrArray> languages = adoptGRef(g_ptr_array_new());
+ g_ptr_array_add(languages.get(), const_cast<gpointer>(static_cast<const void*>("en_US")));
+ g_ptr_array_add(languages.get(), nullptr);
+ WKTextCheckerSetSpellCheckingLanguages(reinterpret_cast<const char* const*>(languages->pdata));
+
// Prefer the not installed web and plugin processes.
WTR::TestController controller(argc, const_cast<const char**>(argv));
+
return 0;
}
diff --git a/Tools/gtk/GNUmakefile.am b/Tools/gtk/GNUmakefile.am
deleted file mode 100644
index 61cff0134..000000000
--- a/Tools/gtk/GNUmakefile.am
+++ /dev/null
@@ -1,153 +0,0 @@
-EXTRA_DIST += \
- Tools/gtk/check-for-webkitdom-api-breaks \
- Tools/gtk/common.py \
- Tools/gtk/generate-feature-defines-files \
- Tools/gtk/generate-gtkdoc \
- Tools/gtk/generate-inspector-gresource-manifest.py \
- Tools/gtk/gtkdoc.py \
- Tools/gtk/webkitdom.py
-
-docs: docs-build.stamp
-.PHONY : docs
-DISTCLEANFILES += docs-build.stamp
-
-docs_build_dependencies = \
- Source/WebKit/gtk/docs/webkitenvironment.xml
-
-if ENABLE_WEBKIT1
-docs_build_dependencies += \
- libwebkitgtk-@WEBKITGTK_API_MAJOR_VERSION@.@WEBKITGTK_API_MINOR_VERSION@.la \
- Source/WebKit/gtk/docs/webkitgtk-docs.sgml \
- Source/WebKit/gtk/docs/webkitgtk-sections.txt \
- gtkdoc-webkitgtk.cfg
-endif
-
-if ENABLE_WEBKIT2
-docs_build_dependencies += \
- libwebkit2gtk-@WEBKITGTK_API_MAJOR_VERSION@.@WEBKITGTK_API_MINOR_VERSION@.la \
- Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-docs.sgml \
- Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-sections.txt \
- gtkdoc-webkit2gtk.cfg
-endif
-
-docs_build_dependencies += \
- libGObjectDOMBindings.la \
- gtkdoc-webkitdom.cfg
-
-docs-build.stamp: $(docs_build_dependencies)
- CC=$(CC) $(PYTHON) $(srcdir)/Tools/gtk/generate-gtkdoc
- @touch docs-build.stamp
-
-clean-local: doc-clean-local
-doc-clean-local:
- @rm -f Documentation/webkitgtk/*~ Documentation/webkitgtk*.bak
- @rm -f Documentation/webkit2gtk/*~ Documentation/webkit2gtk*.bak
- @rm -f Documentation/webkitdomgtk/*~ Documentation/webkitdomgtk*.bak
-
-distclean-local: doc-distclean-local
-doc-distclean-local:
- @rm -rf Documentation
-maintainer-clean-local: doc-maintainer-clean-local
-doc-maintainer-clean-local: clean
- @rm -rf Documentation/webkitgtk Documentation/webkit2gtk Documentation/webkitdomgtk
- -@rmdir Documentation
-
-install-data-local:
-if ENABLE_WEBKIT1
- @installfiles=`echo ./Documentation/webkitgtk/html/*`; \
- if test "$$installfiles" = './Documentation/webkitgtk/html/*'; \
- then echo 1>&2 'No documentation to install' ; \
- else \
- DOC_MODULE_VERSION=`cat ./Documentation/webkitgtk/version.xml`; \
- if test -n "$(DOC_MODULE_VERSION)"; then \
- installdir="$(DESTDIR)$(HTML_DIR)/webkitgtk-$(DOC_MODULE_VERSION)"; \
- else \
- installdir="$(DESTDIR)$(HTML_DIR)/webkitgtk"; \
- fi; \
- $(mkinstalldirs) $${installdir} ; \
- for i in $$installfiles; do \
- echo ' $(INSTALL_DATA) '$$i ; \
- $(INSTALL_DATA) $$i $${installdir}; \
- done; \
- if test -n "$(DOC_MODULE_VERSION)"; then \
- mv -f $${installdir}/webkitgtk.devhelp2 \
- $${installdir}/webkitgtk-$(DOC_MODULE_VERSION).devhelp2; \
- fi; \
- fi
-endif
-if ENABLE_WEBKIT2
- @installfiles=`echo ./Documentation/webkit2gtk/html/*`; \
- if test "$$installfiles" = './Documentation/webkit2gtk/html/*'; \
- then echo 1>&2 'No documentation to install' ; \
- else \
- DOC_MODULE_VERSION=`cat ./Documentation/webkit2gtk/version.xml`; \
- if test -n "$(DOC_MODULE_VERSION)"; then \
- installdir="$(DESTDIR)$(HTML_DIR)/webkit2gtk-$(DOC_MODULE_VERSION)"; \
- else \
- installdir="$(DESTDIR)$(HTML_DIR)/webkit2gtk"; \
- fi; \
- $(mkinstalldirs) $${installdir} ; \
- for i in $$installfiles; do \
- echo ' $(INSTALL_DATA) '$$i ; \
- $(INSTALL_DATA) $$i $${installdir}; \
- done; \
- if test -n "$(DOC_MODULE_VERSION)"; then \
- mv -f $${installdir}/webkit2gtk.devhelp2 \
- $${installdir}/webkit2gtk-$(DOC_MODULE_VERSION).devhelp2; \
- fi; \
- fi
-endif
- @installfiles=`echo ./Documentation/webkitdomgtk/html/*`; \
- if test "$$installfiles" = './Documentation/webkitdomgtk/html/*'; \
- then echo 1>&2 'No documentation to install' ; \
- else \
- DOC_MODULE_VERSION=`cat ./Documentation/webkitdomgtk/version.xml`; \
- if test -n "$(DOC_MODULE_VERSION)"; then \
- installdir="$(DESTDIR)$(HTML_DIR)/webkitdomgtk-$(DOC_MODULE_VERSION)"; \
- else \
- installdir="$(DESTDIR)$(HTML_DIR)/webkitdomgtk"; \
- fi; \
- $(mkinstalldirs) $${installdir} ; \
- for i in $$installfiles; do \
- echo ' $(INSTALL_DATA) '$$i ; \
- $(INSTALL_DATA) $$i $${installdir}; \
- done; \
- if test -n "$(DOC_MODULE_VERSION)"; then \
- mv -f $${installdir}/webkitdomgtk.devhelp2 \
- $${installdir}/webkitdomgtk-$(DOC_MODULE_VERSION).devhelp2; \
- fi; \
- fi
-if ENABLE_GTK_DOC
- @$(AM_V_GEN) PKG_CONFIG=$(PKG_CONFIG) $(PYTHON) $(srcdir)/Tools/gtk/generate-gtkdoc --rebase --virtual-root=$${DESTDIR}
-endif
-
-uninstall-local:
-if ENABLE_WEBKIT1
- @DOC_MODULE_VERSION=`cat ./Documentation/webkitgtk/version.xml`; \
- if test -n "$(DOC_MODULE_VERSION)"; then \
- installdir="$(DESTDIR)$(HTML_DIR)/webkitgtk-$(DOC_MODULE_VERSION)"; \
- else \
- installdir="$(DESTDIR)$(HTML_DIR)/webkitgtk"; \
- fi; \
- rm -rf $${installdir}
-endif
-if ENABLE_WEBKIT2
- @DOC_MODULE_VERSION=`cat ./Documentation/webkit2gtk/version.xml`; \
- if test -n "$(DOC_MODULE_VERSION)"; then \
- installdir="$(DESTDIR)$(HTML_DIR)/webkit2gtk-$(DOC_MODULE_VERSION)"; \
- else \
- installdir="$(DESTDIR)$(HTML_DIR)/webkit2gtk"; \
- fi; \
- rm -rf $${installdir}
-endif
- @DOC_MODULE_VERSION=`cat ./Documentation/webkitdomgtk/version.xml`; \
- if test -n "$(DOC_MODULE_VERSION)"; then \
- installdir="$(DESTDIR)$(HTML_DIR)/webkitdomgtk-$(DOC_MODULE_VERSION)"; \
- else \
- installdir="$(DESTDIR)$(HTML_DIR)/webkitdomgtk"; \
- fi; \
- rm -rf $${installdir}
-if ENABLE_GTK_DOC
-noinst_DATA += docs-build.stamp
-endif
-
diff --git a/Tools/gtk/check-for-webkitdom-api-breaks b/Tools/gtk/check-for-webkitdom-api-breaks
deleted file mode 100755
index 2f4237b51..000000000
--- a/Tools/gtk/check-for-webkitdom-api-breaks
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/usr/bin/env python
-# Copyright (C) 2013, 2014 Igalia S.L.
-# Copyright (C) 2013 Gustavo Noronha Silva <gns@gnome.org>
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-import argparse
-import common
-import os
-import sys
-import webkitdom
-
-EXPECTED_API_PATH = common.top_level_path('Source', 'WebCore', 'bindings', 'gobject', 'webkitdom.symbols')
-
-def read_built_api():
- apis = set()
- for file_path in webkitdom.get_all_webkitdom_symbol_files():
- with open(file_path) as file_handle:
- apis.update(set(file_handle.readlines()))
- return apis
-
-def read_expected_api():
- with open(EXPECTED_API_PATH) as file_handle:
- return set(file_handle.readlines())
-
-def write_expected_api(new_expected_api):
- with open(EXPECTED_API_PATH, 'w') as file_handle:
- file_handle.writelines(new_expected_api)
-
-def check_api(options, expected_api, built_api):
- missing_api = expected_api.difference(built_api)
- new_api = built_api.difference(expected_api)
-
- if missing_api:
- sys.stderr.write("Missing API (API break!) detected in GObject DOM bindings\n")
- sys.stderr.write(" %s\n" % " ".join(missing_api))
- sys.stderr.flush()
-
- if new_api:
- sys.stdout.write("New API detected in GObject DOM bindings\n")
- sys.stdout.write(" %s\n" % " ".join(new_api))
-
- if missing_api:
- # This test can give false positives because the GObject
- # DOM bindings API varies depending on the compilation options.
- # So this shouldn't be made fatal until we figure out a way to handle it.
- # See https://bugs.webkit.org/show_bug.cgi?id=121481
- sys.stderr.write("Re-add the missing API and rerun the %s.\n" % __file__)
- return 0
-
- if new_api:
- if options.reset_results:
- sys.stdout.write("Resetting expected API\n")
- write_expected_api(built_api)
- else:
- sys.stdout.write("API compatible changes found in GObject DOM bindings.\n")
- sys.stdout.write("To update the symbols file, run %s --reset-results.\n" % __file__)
-
- return 0
-
-if __name__ == '__main__':
- parser = argparse.ArgumentParser(description='Detect API breakage in the WebKitGTK+ GObject DOM bindings.')
- parser.add_argument('--reset-results', action='store_true',
- help='When specified, rest the expected results file with the built results.')
- options = parser.parse_args()
- sys.exit(check_api(options, read_expected_api(), read_built_api()))
diff --git a/Tools/gtk/common.py b/Tools/gtk/common.py
index 02f8b6541..f53cc95aa 100644
--- a/Tools/gtk/common.py
+++ b/Tools/gtk/common.py
@@ -24,8 +24,7 @@ import sys
top_level_dir = None
build_dir = None
library_build_dir = None
-tests_library_build_dir = None
-is_cmake = None
+binary_build_dir = None
build_types = ('Release', 'Debug')
@@ -41,41 +40,18 @@ def set_build_types(new_build_types):
build_types = new_build_types
-def is_cmake_build():
- global is_cmake
- if is_cmake is None:
- is_cmake = os.path.exists(build_path('CMakeCache.txt'))
- return is_cmake
-
-
def library_build_path(*args):
global library_build_dir
if not library_build_dir:
- if is_cmake_build():
- library_build_dir = build_path('lib', *args)
- else:
- library_build_dir = build_path('.libs', *args)
+ library_build_dir = build_path('lib', *args)
return library_build_dir
-def tests_library_build_path(*args):
- if is_cmake_build():
- return library_build_path(*args)
-
- global tests_library_build_dir
- if not tests_library_build_dir:
- tests_library_build_dir = build_path('Libraries', *args)
- return tests_library_build_dir
-
-
def binary_build_path(*args):
- global library_build_dir
- if not library_build_dir:
- if is_cmake_build():
- library_build_dir = build_path('bin', *args)
- else:
- library_build_dir = build_path('Programs', *args)
- return library_build_dir
+ global binary_build_dir
+ if not binary_build_dir:
+ binary_build_dir = build_path('bin', *args)
+ return binary_build_dir
def get_build_path(fatal=True):
@@ -84,11 +60,7 @@ def get_build_path(fatal=True):
return build_dir
def is_valid_build_directory(path):
- return os.path.exists(os.path.join(path, 'GNUmakefile')) or \
- os.path.exists(os.path.join(path, 'Programs', 'GtkLauncher')) or \
- os.path.exists(os.path.join(path, 'Programs', 'MiniBrowser')) or \
- os.path.exists(os.path.join(path, 'CMakeCache.txt')) or \
- os.path.exists(os.path.join(path, 'bin/GtkLauncher')) or \
+ return os.path.exists(os.path.join(path, 'CMakeCache.txt')) or \
os.path.exists(os.path.join(path, 'bin/MiniBrowser'))
if len(sys.argv[1:]) > 1 and os.path.exists(sys.argv[-1]) and is_valid_build_directory(sys.argv[-1]):
@@ -144,16 +116,6 @@ def prefix_of_pkg_config_file(package):
return pkg_config_file_variable(package, 'prefix')
-def gtk_version_of_pkg_config_file(pkg_config_path):
- process = subprocess.Popen(['pkg-config', pkg_config_path, '--print-requires'],
- stdout=subprocess.PIPE)
- stdout = process.communicate()[0].decode("utf-8")
-
- if 'gtk+-3.0' in stdout:
- return 3
- return 2
-
-
def parse_output_lines(fd, parse_line_callback):
output = ''
read_set = [fd]
diff --git a/Tools/gtk/generate-feature-defines-files b/Tools/gtk/generate-feature-defines-files
deleted file mode 100755
index 17d52e65a..000000000
--- a/Tools/gtk/generate-feature-defines-files
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env python
-from __future__ import with_statement
-import os
-import re
-import sys
-
-def read_feature_defines_override(feature_defines):
- feature_defines_overriding_file = 'WebKitFeatureOverrides.txt'
- if not os.path.exists(feature_defines_overriding_file):
- return
-
- print("The following feature defines were overriden:")
- with open(feature_defines_overriding_file) as f:
- match_iter = re.findall(r"((?:ENABLE_)\w+)=(0|1)", f.read())
-
- for match in match_iter:
- feature = match[0]
- value = int(match[1])
-
- if feature in feature_defines and value != feature_defines[feature]:
- print("\t{0}: {1} => {2}".format(feature, feature_defines[feature], value))
- feature_defines[feature] = value
-
-def write_file_if_contents_changed(filename, contents):
- if os.path.exists(filename):
- with open(filename, 'r') as f:
- old_contents = f.read()
- if old_contents == contents:
- return
- with open(filename, 'w') as f:
- f.write(contents)
-
-def write_feature_defines_header(feature_defines):
- contents = ''
- for (feature, value) in feature_defines.items():
- contents += '#define {0} {1}\n'.format(feature, value)
- write_file_if_contents_changed("WebKitFeatures.h", contents)
-
-def write_flattened_feature_defines_file(feature_defines):
- contents = ''
- for (feature, value) in feature_defines.items():
- contents += '{0}={1}\n'.format(feature, value)
- write_file_if_contents_changed("WebKitFeatures.txt", contents)
-
-def generate_feature_defines_files(default_features):
- build_dir = os.getcwd()
- feature_defines = {}
-
- for feature_define in default_features:
- (feature, value) = feature_define.split("=")
- feature_defines[feature] = int(value)
-
- read_feature_defines_override(feature_defines)
- write_feature_defines_header(feature_defines)
- write_flattened_feature_defines_file(feature_defines)
-
-if __name__=='__main__':
- generate_feature_defines_files(sys.argv[1:])
diff --git a/Tools/gtk/generate-gtkdoc b/Tools/gtk/generate-gtkdoc
index 37eeee94c..33b2824f8 100755
--- a/Tools/gtk/generate-gtkdoc
+++ b/Tools/gtk/generate-gtkdoc
@@ -19,13 +19,16 @@ from __future__ import print_function
from ConfigParser import SafeConfigParser
import argparse
+import codecs
import common
import glob
import gtkdoc
import logging
import os.path
import sys
-import webkitdom
+
+sys.stdout = codecs.getwriter("utf-8")(sys.stdout)
+sys.stderr = codecs.getwriter("utf-8")(sys.stderr)
def configure_logging(verbose):
level = logging.DEBUG if verbose else logging.INFO
@@ -39,16 +42,13 @@ def configure_logging(verbose):
else:
handler.setFormatter(logging.Formatter('%(message)s'))
-def get_gtkdoc_module_paths(gtk_version):
+def get_gtkdoc_module_paths(cross_reference_deps):
dependent_packages = {
'glib-2.0' : ['glib', 'gobject', 'gio'],
'libsoup-2.4' : ['libsoup-2.4'],
- 'gdk-pixbuf-2.0': ['gdk-pixbuf']
+ 'gdk-pixbuf-2.0': ['gdk-pixbuf'],
+ 'gtk+-3.0' : ['gtk3', 'gdk3']
}
- if gtk_version == 3:
- dependent_packages.update({'gtk+-3.0' : ['gtk3', 'gdk3']})
- else:
- dependent_packages.update({'gtk+-2.0' : ['gtk', 'gdk']})
paths = []
html_dir = os.path.join('share', 'gtk-doc', 'html')
@@ -58,9 +58,9 @@ def get_gtkdoc_module_paths(gtk_version):
continue
for module in modules:
paths.append(os.path.join(prefix, html_dir, module))
- # This technically is not needed for the GObject DOM bindings documentation itself,
- # but adding it doesn't hurt and allows us to avoid a check here.
- paths.append(common.build_path('Documentation', 'webkitdomgtk', 'html'))
+
+ for local_dep in cross_reference_deps:
+ paths.append(common.build_path('Documentation', local_dep, 'html'))
return paths
def print_missing_api(generator):
@@ -91,13 +91,13 @@ def files_to_ignore(source_dirs, headers_with_gtkdoc):
if os.path.splitext(file)[1] not in ['.h', '.c', '.cpp', '.cc']:
return False # These files are ignored anyway.
if not os.path.isfile(file):
- return False
+ return True
return os.path.abspath(file) not in implementation_files
all_files = sum([[os.path.join(dir, file) for file in os.listdir(dir)] for dir in source_dirs], [])
return filter(file_should_be_ignored, all_files)
-def get_generator_for_config(config_file, virtual_root):
+def get_generator_for_config(config_file, virtual_root, cross_reference_deps = []):
if not os.path.isfile(config_file):
return None
@@ -105,7 +105,6 @@ def get_generator_for_config(config_file, virtual_root):
config.read(config_file)
module_name = config.sections()[0]
pkgconfig_file = config.get(module_name, 'pkgconfig_file')
- gtk_version = common.gtk_version_of_pkg_config_file(pkgconfig_file)
if not os.path.isfile(pkgconfig_file):
return None
@@ -121,37 +120,32 @@ def get_generator_for_config(config_file, virtual_root):
'namespace': config.get(module_name, 'namespace'),
'doc_dir': config.get(module_name, 'doc_dir'),
'output_dir': common.build_path('Documentation', module_name),
+ 'main_sgml_file': config.get(module_name, 'main_sgml_file'),
'source_dirs': source_dirs,
'headers': headers,
'cflags': " ".join(config.get(module_name, 'cflags').split()),
- 'cross_reference_deps': get_gtkdoc_module_paths(gtk_version),
+ 'cross_reference_deps': get_gtkdoc_module_paths(cross_reference_deps),
'ignored_files': files_to_ignore(source_dirs, headers),
})
def generate_doc(generator, skip_html):
- print("\nGenerating {0} documentation...".format(generator.module_name))
generator.generate(not skip_html)
if generator.saw_warnings:
print_missing_api(generator)
return generator.saw_warnings
def rebase_doc(generator):
- print("\nRebasing {0} documentation...".format(generator.module_name))
try:
generator.rebase_installed_docs()
except Exception:
print("Rebase did not happen, likely no documentation is present.")
-def generate_documentation_for_config(config_file):
- generator = get_generator_for_config(config_file, arguments.virtual_root)
- if not generator:
- print("{0} does not exist! Skipping that documentation.".format(os.path.basename(config_file)))
- return
-
+def generate_documentation(generator):
if not arguments.rebase:
return generate_doc(generator, arguments.skip_html)
rebase_doc(generator)
+ return False
def prepare_environment_for_gtkdoc_generation():
# We need to add the JavaScriptCore build directory to the PKG_CONFIG_PATH
@@ -174,10 +168,6 @@ def prepare_environment_for_gtkdoc_generation():
cflags += ' -Wno-cast-align'
os.environ['CFLAGS'] = cflags
- # Clang can be noisy, throwing unnecessary warnings for unused arguments.
- if os.environ.get('CC') == "clang":
- os.environ['CFLAGS'] += ' -Qunused-arguments'
-
# Paths from the GNUmakefile generated configuration files are relative to the build directory.
os.chdir(common.build_path())
@@ -200,10 +190,18 @@ if __name__ == "__main__":
prepare_environment_for_gtkdoc_generation()
- webkitdom.write_doc_files()
- generate_documentation_for_config(common.build_path('gtkdoc-webkitdom.cfg'))
-
- saw_webkit1_warnings = generate_documentation_for_config(common.build_path('gtkdoc-webkitgtk.cfg'))
- saw_webkit2_warnings = generate_documentation_for_config(common.build_path('gtkdoc-webkit2gtk.cfg'))
-
- sys.exit(saw_webkit1_warnings or saw_webkit2_warnings)
+ webkitdom_generator = get_generator_for_config(common.build_path('gtkdoc-webkitdom.cfg'), arguments.virtual_root)
+ if not webkitdom_generator:
+ print("gtkdoc-webkitdom.cfg does not exist! Skipping that documentation")
+ sys.exit(1)
+ saw_warnings = generate_documentation(webkitdom_generator)
+ if saw_warnings:
+ sys.exit(saw_warnings)
+
+ webkit2_generator = get_generator_for_config(common.build_path('gtkdoc-webkit2gtk.cfg'), arguments.virtual_root, [webkitdom_generator.module_name])
+ if not webkit2_generator:
+ print("gtkdoc-webkit2gtk.cfg does not exist! Skipping that documentation")
+ sys.exit(1)
+ saw_warnings = generate_documentation(webkit2_generator)
+
+ sys.exit(saw_warnings)
diff --git a/Tools/gtk/generate-inspector-gresource-manifest.py b/Tools/gtk/generate-inspector-gresource-manifest.py
index d319eba0c..03060cfa2 100755
--- a/Tools/gtk/generate-inspector-gresource-manifest.py
+++ b/Tools/gtk/generate-inspector-gresource-manifest.py
@@ -33,8 +33,8 @@ def get_filenames(args):
base_dir_index = filename.rfind(BASE_DIR)
if base_dir_index != -1:
name = filename[base_dir_index + len(BASE_DIR):]
- # The result should use forward slashes, thus make sure any os-specific
- # separator, added by the glob.glob() call, is properly replaced
+ # The result should use forward slashes, thus make sure any os-specific
+ # separator, added by the glob.glob() call, is properly replaced
if os.sep != '/':
name = name.replace(os.sep, '/')
filenames.append(name)
@@ -55,13 +55,13 @@ if __name__ == "__main__":
args = parser.parse_args(sys.argv[1:])
args.output.write(\
-"""<?xml version=1.0 encoding=UTF-8?>
-<gresources>
- <gresource prefix="/org/webkitgtk/inspector">
+ """<?xml version=1.0 encoding=UTF-8?>
+ <gresources>
+ <gresource prefix="/org/webkitgtk/inspector">
""")
for filename in get_filenames(args.filenames):
- line = ' <file'
+ line = ' <file'
if is_compressible(filename):
line += ' compressed="true"'
if 'Images/gtk/' in filename:
@@ -71,7 +71,7 @@ if __name__ == "__main__":
args.output.write(line)
args.output.write(\
-""" </gresource>
+ """ </gresource>
</gresources>
""")
diff --git a/Tools/gtk/gtkdoc.py b/Tools/gtk/gtkdoc.py
index 5aff6fc9b..48f862a31 100644
--- a/Tools/gtk/gtkdoc.py
+++ b/Tools/gtk/gtkdoc.py
@@ -141,7 +141,6 @@ class GTKDoc(object):
self._write_version_xml()
self._run_gtkdoc_scan()
self._run_gtkdoc_scangobj()
- self._run_gtkdoc_mktmpl()
self._run_gtkdoc_mkdb()
if not html:
@@ -185,7 +184,7 @@ class GTKDoc(object):
def _run_command(self, args, env=None, cwd=None, print_output=True, ignore_warnings=False):
if print_output:
- self.logger.info("Running %s", args[0])
+ self.logger.debug("Running %s", args[0])
self.logger.debug("Full command args: %s", str(args))
process = subprocess.Popen(args, env=env, cwd=cwd,
@@ -195,9 +194,15 @@ class GTKDoc(object):
if print_output:
if stdout:
- sys.stdout.write(stdout.encode("utf-8"))
+ try:
+ sys.stdout.write(stdout.encode("utf-8"))
+ except UnicodeDecodeError:
+ sys.stdout.write(stdout)
if stderr:
- sys.stderr.write(stderr.encode("utf-8"))
+ try:
+ sys.stderr.write(stderr.encode("utf-8"))
+ except UnicodeDecodeError:
+ sys.stderr.write(stderr)
if process.returncode != 0:
raise Exception('%s produced a non-zero return code %i'
@@ -238,14 +243,14 @@ class GTKDoc(object):
copy_file_replacing_existing(os.path.join(src, path),
os.path.join(dest, path))
- self.logger.info('Copying template files to output directory...')
+ self.logger.debug('Copying template files to output directory...')
self._create_directory_if_nonexistent(self.output_dir)
copy_all_files_in_directory(self.doc_dir, self.output_dir)
if not html:
return
- self.logger.info('Copying HTML files to output directory...')
+ self.logger.debug('Copying HTML files to output directory...')
html_src_dir = os.path.join(self.doc_dir, 'html')
html_dest_dir = os.path.join(self.output_dir, 'html')
self._create_directory_if_nonexistent(html_dest_dir)
@@ -307,7 +312,11 @@ class GTKDoc(object):
env = os.environ
ldflags = self.ldflags
if self.library_path:
- ldflags = ' "-L%s" ' % self.library_path + ldflags
+ additional_ldflags = ''
+ for arg in env.get('LDFLAGS', '').split(' '):
+ if arg.startswith('-L'):
+ additional_ldflags = '%s %s' % (additional_ldflags, arg)
+ ldflags = ' "-L%s" %s ' % (self.library_path, additional_ldflags) + ldflags
current_ld_library_path = env.get('LD_LIBRARY_PATH')
if current_ld_library_path:
env['RUN'] = 'LD_LIBRARY_PATH="%s:%s" ' % (self.library_path, current_ld_library_path)
@@ -328,10 +337,6 @@ class GTKDoc(object):
self._run_command(['gtkdoc-scangobj', '--module=%s' % self.module_name],
env=env, cwd=self.output_dir)
- def _run_gtkdoc_mktmpl(self):
- args = ['gtkdoc-mktmpl', '--module=%s' % self.module_name]
- self._run_command(args, cwd=self.output_dir)
-
def _run_gtkdoc_mkdb(self):
sgml_file = os.path.join(self.output_dir, self.main_sgml_file)
self._raise_exception_if_file_inaccessible(sgml_file)
@@ -373,6 +378,7 @@ class GTKDoc(object):
def _run_gtkdoc_fixxref(self):
args = ['gtkdoc-fixxref',
+ '--module=%s' % self.module_name,
'--module-dir=html',
'--html-dir=html']
args.extend(['--extra-dir=%s' % extra_dir for extra_dir in self.cross_reference_deps])
diff --git a/Tools/gtk/install-dependencies b/Tools/gtk/install-dependencies
new file mode 100755
index 000000000..71582b729
--- /dev/null
+++ b/Tools/gtk/install-dependencies
@@ -0,0 +1,479 @@
+#!/bin/bash
+
+# This script needs to be run with root rights.
+if [ $UID -ne 0 ]; then
+ sudo $0
+ exit 0
+fi
+
+function printNotSupportedMessageAndExit() {
+ echo
+ echo "Currently this script only works for distributions supporting apt-get and yum."
+ echo "Please add support for your distribution: http://webkit.org/b/110693"
+ echo
+ exit 1
+}
+
+function checkInstaller {
+ # apt-get - Debian based distributions
+ apt-get --version &> /dev/null
+ if [ $? -eq 0 ]; then
+ installDependenciesWithApt
+ exit 0
+ fi
+
+ # dnf - Fedora
+ dnf --version &> /dev/null
+ if [ $? -eq 0 ]; then
+ installDependenciesWithDnf
+ exit 0
+ fi
+
+ # pacman - Arch Linux
+ # pacman --version and pacman --help both return non-0
+ pacman -Ss &> /dev/null
+ if [ $? -eq 0 ]; then
+ installDependenciesWithPacman
+ exit 0
+ fi
+
+ if [ `uname` -eq "Darwin" ]; then
+ installDependenciesWithBrew
+ exit 0
+ fi
+
+ printNotSupportedMessageAndExit
+}
+
+function installDependenciesWithBrew {
+ brew &> /dev/null
+ if [ $? -gt 1 ]; then
+ echo "Please install HomeBrew. Instructions on http://brew.sh"
+ exit 1
+ fi
+
+ brew install autoconf \
+ automake \
+ bison \
+ cmake \
+ enchant \
+ flex \
+ gettext \
+ gobject-introspection \
+ intltool \
+ itstool \
+ libcroco \
+ libgcrypt \
+ libgpg-error \
+ libtiff \
+ libtool \
+ ninja \
+ pango \
+ pkg-config \
+ sqlite \
+ webp \
+ xz
+}
+
+# If the package $1 is available, prints it. Otherwise prints $2.
+# Useful for handling when a package is renamed on new versions of Debian/Ubuntu.
+function aptIfElse {
+ if apt-cache show $1 &>/dev/null; then
+ echo $1
+ else
+ echo $2
+ fi
+}
+
+function installDependenciesWithApt {
+ # These are dependencies necessary for building WebKitGTK+.
+ packages=" \
+ autoconf \
+ automake \
+ autopoint \
+ autotools-dev \
+ bison \
+ cmake \
+ flex \
+ gawk \
+ geoclue-2.0 \
+ gnome-common \
+ gperf \
+ gtk-doc-tools \
+ intltool \
+ itstool \
+ libatk1.0-dev \
+ libedit-dev \
+ libenchant-dev \
+ libfaad-dev \
+ $(aptIfElse libgcrypt20-dev libgcrypt11-dev) \
+ $(aptIfElse libgeoclue-2-dev libgeoclue-dev) \
+ libgirepository1.0-dev \
+ libgl1-mesa-dev \
+ libgl1-mesa-glx \
+ libgtk2.0-dev \
+ libgtk-3-dev \
+ libgstreamer1.0-dev \
+ libgstreamer-plugins-base1.0-dev \
+ libgudev-1.0-dev \
+ libhyphen-dev \
+ libjpeg-dev \
+ libmpg123-dev \
+ libnotify-dev \
+ libopus-dev \
+ libpango1.0-dev \
+ $(aptIfElse libpng-dev libpng12-dev) \
+ libpulse-dev \
+ librsvg2-dev \
+ libsecret-1-dev \
+ libsoup2.4-dev \
+ libsqlite3-dev \
+ libtheora-dev \
+ libtool \
+ libvorbis-dev \
+ libwebp-dev \
+ libxcomposite-dev \
+ libxt-dev \
+ libxtst-dev \
+ libxslt1-dev \
+ libwayland-dev \
+ ninja-build \
+ patch \
+ ruby \
+ xfonts-utils"
+
+ # These are dependencies necessary for running tests.
+ packages="$packages \
+ apache2 \
+ curl \
+ dbus-x11 \
+ gdb \
+ libapache2-mod-bw \
+ $(aptIfElse libapache2-mod-php7.0 libapache2-mod-php5) \
+ libgpg-error-dev \
+ psmisc \
+ pulseaudio-utils \
+ python-gi \
+ python-psutil \
+ ruby \
+ ruby-json \
+ ruby-highline \
+ weston \
+ xvfb"
+
+ # These are dependencies necessary for building the jhbuild.
+ packages="$packages \
+ git \
+ gobject-introspection \
+ gsettings-desktop-schemas-dev \
+ icon-naming-utils \
+ libcroco3-dev \
+ libdrm-dev \
+ libegl1-mesa-dev \
+ libepoxy-dev \
+ libevdev-dev \
+ libexpat1-dev \
+ libgbm-dev \
+ libgles2-mesa-dev \
+ libgnutls28-dev \
+ libgpg-error-dev \
+ libjson-glib-dev \
+ libinput-dev \
+ libmtdev-dev \
+ libp11-kit-dev \
+ libpciaccess-dev \
+ libproxy-dev \
+ libssl-dev \
+ libtiff5-dev \
+ libv4l-dev \
+ libxcb-composite0-dev \
+ libxcb-xfixes0-dev \
+ $(aptIfElse libxfont1-dev libxfont-dev) \
+ libxkbfile-dev \
+ libtool-bin \
+ libudev-dev \
+ python-dev \
+ ragel \
+ x11proto-bigreqs-dev \
+ x11proto-composite-dev \
+ x11proto-gl-dev \
+ x11proto-input-dev \
+ x11proto-randr-dev \
+ x11proto-resource-dev \
+ x11proto-scrnsaver-dev \
+ x11proto-video-dev \
+ x11proto-xcmisc-dev \
+ x11proto-xf86dri-dev \
+ xfonts-utils \
+ xtrans-dev \
+ xutils-dev \
+ yasm"
+
+ # These are dependencies necessary for using webkit-patch
+ packages="$packages \
+ git-svn \
+ subversion"
+
+ apt-get install $packages
+}
+
+function installDependenciesWithPacman {
+ # These are dependencies necessary for building WebKitGTK+.
+ packages=" \
+ autoconf \
+ automake \
+ bison \
+ cmake \
+ libedit \
+ file \
+ findutils \
+ flex \
+ gawk \
+ gcc \
+ gettext \
+ gnome-common \
+ gperf \
+ grep \
+ groff \
+ gstreamer \
+ gst-plugins-base-libs \
+ gzip \
+ hyphen \
+ libtool \
+ m4 \
+ make \
+ patch \
+ pkg-config \
+ sed \
+ texinfo \
+ util-linux \
+ which \
+ gtk-doc \
+ intltool \
+ itstool \
+ atk \
+ enchant \
+ faad2 \
+ geoclue \
+ gobject-introspection \
+ mesa \
+ mesa-libgl \
+ gtk2 \
+ gtk3 \
+ libsystemd \
+ libjpeg-turbo \
+ mpg123 \
+ opus \
+ pango \
+ libgcrypt \
+ libnotify \
+ libpng \
+ libpulse \
+ librsvg \
+ libsecret \
+ libsoup \
+ sqlite \
+ libtheora \
+ libtool \
+ libvorbis \
+ libwebp \
+ libxcomposite \
+ libxt \
+ libxslt \
+ libxtst \
+ ninja \
+ ruby \
+ xorg-font-utils \
+ wayland"
+
+ # These are dependencies necessary for running tests.
+ # Note: apache-mod_bw is available in the AUR, but the main repos
+ # could not find ruby-json
+ packages="$packages \
+ apache \
+ curl \
+ gdb \
+ hunspell \
+ hunspell-en \
+ php-apache \
+ libgpg-error \
+ psmisc \
+ pulseaudio \
+ python-gobject \
+ python2-psutil \
+ ruby \
+ ruby-highline \
+ weston \
+ xorg-server-xvfb"
+
+ # These are dependencies necessary for building the jhbuild.
+ # Note: Could not find libegl-mesa
+ packages="$packages \
+ expat \
+ git \
+ gnutls \
+ gobject-introspection \
+ gsettings-desktop-schemas \
+ icon-naming-utils \
+ libcroco \
+ libdrm \
+ libepoxy \
+ libevdev \
+ libgpg-error \
+ libinput \
+ p11-kit \
+ libpciaccess \
+ libproxy \
+ libtiff \
+ libxfixes \
+ libxfont \
+ libxcb \
+ libxkbfile \
+ mtdev \
+ python2 \
+ python2-lxml \
+ ragel \
+ bigreqsproto \
+ compositeproto \
+ glproto \
+ inputproto \
+ randrproto \
+ resourceproto \
+ scrnsaverproto \
+ videoproto \
+ xcmiscproto \
+ xf86driproto \
+ xorg-font-utils \
+ xorg-util-macros \
+ xtrans \
+ xorg-utils \
+ yasm"
+
+ # These are dependencies necessary for using webkit-patch
+ packages="$packages \
+ svn"
+ pacman -S --needed $packages
+
+ echo "You will also need to follow the instructions on the Arch Wiki to make"
+ echo "'python' call python2 in the webkit folder"
+ echo "https://wiki.archlinux.org/index.php/Python#Dealing_with_version_problem_in_build_scripts"
+}
+
+function installDependenciesWithDnf {
+ # These are dependencies necessary for building WebKitGTK+.
+ packages=" \
+ atk-devel \
+ autoconf \
+ automake \
+ bison \
+ cairo-devel \
+ cmake \
+ enchant-devel \
+ flex \
+ gcc-c++ \
+ geoclue2-devel \
+ gettext-devel \
+ gobject-introspection-devel \
+ gperf \
+ gstreamer1-devel \
+ gstreamer1-plugins-base-devel \
+ gtk-doc \
+ gtk2-devel \
+ gtk3-devel \
+ hyphen-devel \
+ intltool \
+ json-glib-devel \
+ libXt-devel \
+ libXtst-devel \
+ libxslt-devel \
+ libedit-devel \
+ libgcrypt-devel \
+ libgudev1-devel \
+ libjpeg-turbo-devel \
+ libnotify-devel \
+ libpng-devel \
+ libsecret-devel \
+ libsoup-devel \
+ libv4l-devel \
+ libwebp-devel \
+ libwayland-client-devel \
+ libwayland-server-devel \
+ mesa-libGL-devel \
+ ninja-build \
+ openssl-devel \
+ patch \
+ pcre-devel \
+ perl-Switch \
+ perl-version \
+ pulseaudio-libs-devel \
+ python-devel \
+ redhat-rpm-config \
+ ruby \
+ sqlite-devel"
+
+ # These are dependencies necessary for running tests.
+ packages="$packages \
+ curl \
+ dbus-x11 \
+ gdb \
+ hunspell-en \
+ httpd \
+ libgpg-error-devel \
+ mod_bw \
+ mod_ssl \
+ perl-CGI \
+ php \
+ psmisc \
+ pulseaudio-utils \
+ pygobject3-base \
+ python2-psutil \
+ ruby \
+ rubygem-json \
+ rubygem-highline \
+ weston-devel \
+ xorg-x11-server-Xvfb"
+
+ # These are dependencies necessary for building the jhbuild.
+ packages="$packages \
+ expat-devel \
+ docbook-utils \
+ docbook-utils-pdf \
+ git \
+ gobject-introspection \
+ gnutls-devel \
+ gsettings-desktop-schemas-devel \
+ icon-naming-utils \
+ itstool \
+ libXfont-devel \
+ libcroco-devel \
+ libdrm-devel \
+ libepoxy-devel \
+ libevdev-devel
+ libgpg-error-devel \
+ libinput-devel \
+ libp11-devel \
+ libpciaccess-devel \
+ libproxy-devel \
+ libtiff-devel \
+ libxcb-devel \
+ libxkbfile-devel \
+ mesa-libEGL-devel \
+ mtdev-devel \
+ ragel \
+ systemd-devel \
+ xorg-x11-font-utils \
+ xorg-x11-proto-devel \
+ xorg-x11-util-macros \
+ xorg-x11-xtrans-devel \
+ yasm"
+
+ # These are dependencies necessary for using webkit-patch
+ packages="$packages
+ git-svn \
+ subversion"
+
+ dnf install $packages
+}
+
+checkInstaller
+
diff --git a/Tools/gtk/jhbuild.modules b/Tools/gtk/jhbuild.modules
new file mode 100644
index 000000000..e7762fac8
--- /dev/null
+++ b/Tools/gtk/jhbuild.modules
@@ -0,0 +1,628 @@
+<?xml version="1.0"?>
+<!DOCTYPE moduleset SYSTEM "moduleset.dtd">
+<?xml-stylesheet type="text/xsl" href="moduleset.xsl"?>
+<moduleset>
+
+ <metamodule id="webkitgtk-testing-dependencies">
+ <dependencies>
+ <dep package="cairo"/>
+ <dep package="fonts"/>
+ <dep package="dicts"/>
+ <dep package="fontconfig"/>
+ <dep package="freetype6"/>
+ <dep package="harfbuzz"/>
+ <dep package="libxml2"/>
+ <dep package="libxslt"/>
+ <dep package="gdk-pixbuf"/>
+ <dep package="gtk+"/>
+ <dep package="glib"/>
+ <dep package="glib-networking"/>
+ <dep package="gnome-icon-theme"/>
+ <dep package="gnome-icon-theme-symbolic"/>
+ <dep package="gnome-themes-standard"/>
+ <dep package="gtk-doc"/>
+ <dep package="icu"/>
+ <dep package="libsoup"/>
+ <dep package="atk"/>
+ <dep package="gstreamer"/>
+ <dep package="gst-plugins-base"/>
+ <dep package="gst-plugins-good"/>
+ <dep package="gst-plugins-bad"/>
+ <dep package="gst-libav"/>
+ <dep package="openwebrtc"/>
+ <dep package="llvm"/>
+ <dep package="shared-mime-info"/>
+ <if condition-set="linux">
+ <dep package="xserver"/>
+ <dep package="mesa"/>
+ <dep package="at-spi2-core"/>
+ <dep package="at-spi2-atk"/>
+ <dep package="weston"/>
+ </if>
+ <if condition-set="macos">
+ <dep package="gsettings-desktop-schemas"/>
+ </if>
+ </dependencies>
+ </metamodule>
+
+ <!-- Please use http/https to access repositories to be friendly to users stuck behind firewalls. -->
+ <repository type="git" name="github.com"
+ href="https://github.com"/>
+ <repository type="tarball" name="github-tarball"
+ href="https://github.com/"/>
+ <repository type="tarball" name="sourceware.org-mirror"
+ href="http://mirrors.kernel.org/sources.redhat.com/"/>
+ <repository type="tarball" name="ftp.gnome.org"
+ href="http://ftp.gnome.org"/>
+ <repository type="git" name="git.gnome.org"
+ href="https://git.gnome.org/browse/"/>
+ <repository type="tarball" name="cairographics.org"
+ href="http://cairographics.org"/>
+ <repository type="tarball" name="freedesktop.org"
+ href="http://www.freedesktop.org"/>
+ <repository type="tarball" name="xorg"
+ href="http://xorg.freedesktop.org"/>
+ <repository type="tarball" name="xmlsoft.org"
+ href="http://xmlsoft.org"/>
+ <repository type="tarball" name="gstreamer"
+ href="http://gstreamer.freedesktop.org/src/"/>
+ <repository type="tarball" name="savannah.gnu.org"
+ href="http://download.savannah.gnu.org/releases/"/>
+ <repository type="git" name="freedesktop-git"
+ href="http://anongit.freedesktop.org/git"/>
+ <repository type="tarball" name="dri.freedesktop.org"
+ href="http://dri.freedesktop.org"/>
+ <repository type="tarball" name="people.freedesktop.org"
+ href="http://people.freedesktop.org"/>
+ <repository type="tarball" name="wayland.freedesktop.org"
+ href="http://wayland.freedesktop.org"/>
+ <repository type="tarball" name="llvm.org"
+ href="http://llvm.org"/>
+ <repository type="tarball" name="webkitgtk-jhbuild-mirror"
+ href="http://webkitgtk.org/jhbuild_mirror/"/>
+
+ <autotools id="cairo">
+ <if condition-set="linux">
+ <autogenargs value="--enable-gl=yes --enable-egl=yes --enable-glx=yes"/>
+ </if>
+ <if condition-set="macos">
+ <autogenargs value="ac_cv_func_rsvg_pixbuf_from_file=no --disable-lto"/>
+ </if>
+ <dependencies>
+ <dep package="fontconfig"/>
+ <dep package="pixman"/>
+ <dep package="glib"/>
+ </dependencies>
+ <branch module="releases/cairo-1.14.2.tar.xz" version="1.14.2"
+ repo="cairographics.org"
+ hash="sha1:c8da68aa66ca0855b5d0ff552766d3e8679e1d24"/>
+ </autotools>
+
+ <!-- FIXME: Pixman 0.32.6 isn't buildable with Clang, but disable-mmx option fixes
+ the build. This workaround can be removed once the original bug is fixed.
+ Details can be found here: https://bugs.webkit.org/show_bug.cgi?id=151441 -->
+ <!-- FIXME: Pixman 0.32.6 ARM iwMMXt fast path isn't buildable with GCC 4.9 and
+ ARM traditional instruction set. It causes a build failure on Raspbian.
+ This workaround can be removed once we raise the minimum GCC version
+ for WebKitGTK+ above 4.9 -->
+ <autotools id="pixman" autogen-sh="configure"
+ autogenargs="--enable-gtk=no --disable-mmx --disable-arm-iwmmxt">
+ <branch module="releases/pixman-0.32.6.tar.gz" version="0.32.6"
+ repo="cairographics.org"
+ hash="sha256:3dfed13b8060eadabf0a4945c7045b7793cc7e3e910e748a8bb0f0dc3e794904"
+ md5sum="3a30859719a41bd0f5cccffbfefdd4c2">
+ </branch>
+ </autotools>
+
+ <autotools id="fonts" supports-non-srcdir-builds="no"
+ skip-autogen="true">
+ <branch repo="github.com" module="mrobinson/webkitgtk-test-fonts.git" checkoutdir="webkitgtk-test-fonts" tag="0.0.5"/>
+ </autotools>
+
+ <autotools id="dicts" supports-non-srcdir-builds="no"
+ skip-autogen="true">
+ <branch repo="github.com" module="mrobinson/webkitgtk-test-dicts.git" checkoutdir="webkitgtk-test-dicts" tag="0.0.1"/>
+ </autotools>
+
+ <autotools id="freetype6" autogen-sh="configure">
+ <branch module="freetype/freetype-2.4.11.tar.bz2" version="2.4.11"
+ repo="savannah.gnu.org"
+ hash="sha256:ef9d0bcb64647d9e5125dc7534d7ca371c98310fec87677c410f397f71ffbe3f"
+ md5sum="b93435488942486c8d0ca22e8f768034">
+ <patch file="freetype6-2.4.11-truetype-font-height-fix.patch" strip="1"/>
+ </branch>
+ </autotools>
+
+ <autotools id="harfbuzz" autogen-sh="configure">
+ <dependencies>
+ <dep package="icu"/>
+ </dependencies>
+ <branch module="software/harfbuzz/release/harfbuzz-1.3.3.tar.bz2"
+ version="1.3.3"
+ checkoutdir="harfbuzz-1.3.3"
+ repo="freedesktop.org"
+ hash="sha256:2620987115a4122b47321610dccbcc18f7f121115fd7b88dc8a695c8b66cb3c9"
+ md5sum="97ae15a72a93f1f27324a2b8d9bd3b1d">
+ </branch>
+ </autotools>
+
+ <autotools id="libffi" autogen-sh="configure">
+ <branch module="libffi/libffi-3.1.tar.gz" version="3.1"
+ repo="sourceware.org-mirror"
+ hash="sha256:97feeeadca5e21870fa4433bc953d1b3af3f698d5df8a428f68b73cd60aef6eb"
+ md5sum="f5898b29bbfd70502831a212d9249d10"/>
+ </autotools>
+
+ <autotools id="gdk-pixbuf" autogen-sh="configure"
+ autogenargs="--disable-introspection">
+ <dependencies>
+ <dep package="glib"/>
+ </dependencies>
+ <branch module="/pub/GNOME/sources/gdk-pixbuf/2.30/gdk-pixbuf-2.30.8.tar.xz" version="2.30.8"
+ repo="ftp.gnome.org"
+ hash="sha256:4853830616113db4435837992c0aebd94cbb993c44dc55063cee7f72a7bef8be"/>
+ </autotools>
+
+ <autotools id="librsvg" autogen-sh="configure"
+ autogenargs="--disable-introspection --enable-pixbuf-loader --disable-gtk-theme">
+ <if condition-set="macos">
+ <autogenargs value="--disable-Bsymbolic"/>
+ </if>
+ <dependencies>
+ <dep package="gdk-pixbuf"/>
+ <dep package="glib"/>
+ <dep package="cairo"/>
+ </dependencies>
+ <branch module="/pub/GNOME/sources/librsvg/2.36/librsvg-2.36.1.tar.xz" version="2.36.1"
+ repo="ftp.gnome.org"
+ hash="sha256:786b95e1a091375c5ef2997a21c69ff24d7077afeff18197355f54d9dcbcd8c5"
+ md5sum="89d483f30a7c77245b7ee02faaea5a5a">
+ <patch file="librsvg-2.36.1-bump-up-config.guess-to-support-aarch64.patch" strip="1"/>
+ </branch>
+ </autotools>
+
+ <autotools id="gtk+" autogen-sh="configure"
+ autogenargs="--disable-introspection">
+ <if condition-set="macos">
+ <autogenargs value="--enable-x11-backend=no --enable-quartz-backend" />
+ <makeargs value="-j1" />
+ </if>
+ <dependencies>
+ <dep package="glib"/>
+ <dep package="cairo"/>
+ <dep package="atk"/>
+ <if condition-set="linux">
+ <dep package="at-spi2-atk"/>
+ <dep package="wayland"/>
+ </if>
+ <dep package="gdk-pixbuf"/>
+ <dep package="pango"/>
+ </dependencies>
+ <branch module="/pub/GNOME/sources/gtk+/3.16/gtk+-3.16.4.tar.xz" version="3.16.4"
+ repo="ftp.gnome.org"
+ hash="sha256:1ee5dbd7a4cb81a91eaa1b7ae64ba5a3eab6a3c0a764155583ab96524590fc8e">
+ <patch file="gtk+-configure-fix-detecting-CUPS-2.x.patch" strip="1"/>
+ </branch>
+ </autotools>
+
+ <autotools id="glib"
+ autogen-sh="configure"
+ autogenargs="--disable-dtrace">
+ <dependencies>
+ <dep package="libffi"/>
+ </dependencies>
+ <branch module="/pub/GNOME/sources/glib/2.44/glib-2.44.1.tar.xz" version="2.44.1"
+ repo="ftp.gnome.org"
+ hash="sha256:8811deacaf8a503d0a9b701777ea079ca6a4277be10e3d730d2112735d5eca07">
+ <patch file="glib-warning-fix.patch" strip="1"/>
+ <patch file="gdate-suppress-string-format-literal-warning.patch" strip="1"/>
+ </branch>
+ </autotools>
+
+ <autotools id="glib-networking">
+ <if condition-set="macos">
+ <autogenargs value="--with-ca-certificates='/usr/local/etc/openssl/cert.pem' --without-pkcs11"/>
+ </if>
+ <dependencies>
+ <dep package="glib"/>
+ </dependencies>
+ <branch module="/pub/GNOME/sources/glib-networking/2.41/glib-networking-2.41.4.tar.xz" version="2.41.4"
+ repo="ftp.gnome.org"
+ hash="sha256:930ad618865dcf81765d0f48cb6f13e22d76203efa59d30604aed0384ce80fd7"
+ md5sum="f88e163322c0834f9781d6224771ab2e"/>
+ </autotools>
+
+ <autotools id="libsoup"
+ autogenargs="--without-gnome --disable-introspection">
+ <if condition-set="macos">
+ <autogenargs value="--disable-tls-check"/>
+ </if>
+ <dependencies>
+ <dep package="glib-networking"/>
+ </dependencies>
+ <branch module="/pub/GNOME/sources/libsoup/2.57/libsoup-2.57.1.tar.xz" version="2.57.1"
+ repo="ftp.gnome.org"
+ hash="sha256:ca1ca037e89e8bc7b782559f3ec5d89c9d0b836f505b2f95e008ed517fd6658f">
+ <patch file="libsoup-auth-Fix-async-authentication-when-flag-SOUP_MESSAGE.patch" strip="1"/>
+ <patch file="libsoup-auth-do-not-use-cached-credentials-in-lookup-method-.patch" strip="1"/>
+ </branch>
+ </autotools>
+
+ <autotools id="fontconfig"
+ autogen-sh="configure"
+ autogenargs="--enable-libxml2">
+ <if condition-set="macos">
+ <autogenargs value="--with-add-fonts=/System/Library/Fonts,/Library/Fonts,~/Library/Fonts"/>
+ </if>
+ <dependencies>
+ <dep package="freetype6"/>
+ <dep package="libxml2"/>
+ </dependencies>
+ <branch module="software/fontconfig/release/fontconfig-2.11.1.tar.gz" version="2.11.1"
+ repo="freedesktop.org"
+ hash="sha256:b6b066c7dce3f436fdc0dfbae9d36122b38094f4f53bd8dffd45e195b0540d8d"
+ md5sum="e75e303b4f7756c2b16203a57ac87eba">
+ <patch file="fontconfig-fix-osx-cache.diff" strip="1"/>
+ </branch>
+ </autotools>
+
+ <autotools id="gnome-icon-theme" autogen-sh="configure">
+ <dependencies>
+ <dep package="gtk+"/>
+ </dependencies>
+ <branch module="pub/GNOME/sources/gnome-icon-theme/3.2/gnome-icon-theme-3.2.1.tar.xz" version="3.2.1"
+ repo="ftp.gnome.org"
+ hash="sha256:a7f0a8b17e91ac338fdbc01ac59a8738e9c1e201de492c070d43aacf291a8959"
+ md5sum="40be1e5a6eae11181311a6fc432cf892">
+ </branch>
+ </autotools>
+
+ <autotools id="gnome-icon-theme-symbolic" supports-non-srcdir-builds="no" autogen-sh="configure">
+ <dependencies>
+ <dep package="gtk+"/>
+ </dependencies>
+ <branch module="pub/GNOME/sources/gnome-icon-theme-symbolic/3.2/gnome-icon-theme-symbolic-3.2.1.tar.xz" version="3.2.1"
+ repo="ftp.gnome.org"
+ hash="sha256:a558af2f87f761f00421f49c1addd2149b70228158e09327fa861219ac1a63cb"
+ md5sum="94137d3c256f2cc80298a9bef15d68c4">
+ </branch>
+ </autotools>
+
+ <autotools id="gnome-themes-standard" autogen-sh="configure">
+ <dependencies>
+ <dep package="gtk+"/>
+ <dep package="librsvg"/>
+ </dependencies>
+ <branch module="pub/GNOME/sources/gnome-themes-standard/3.6/gnome-themes-standard-3.6.0.tar.xz" version="3.6.0"
+ repo="ftp.gnome.org"
+ hash="sha256:d832fd38f7659f470df5ddc52131a59f989c75f3a70f8b3a514f89d90d4f43ec">
+ </branch>
+ </autotools>
+
+ <autotools id="atk"
+ autogen-sh="configure"
+ autogenargs="--disable-introspection">
+ <branch module="pub/GNOME/sources/atk/2.15/atk-2.15.4.tar.xz" version="2.15.4"
+ repo="ftp.gnome.org"
+ hash="sha256:0dddfa73a02178ca21a8de172c86d699aa887b4efeec736b4c8721eee4ac349c"/>
+ </autotools>
+
+ <autotools id="at-spi2-core"
+ autogenargs="--disable-introspection">
+ <branch module="pub/GNOME/sources/at-spi2-core/2.15/at-spi2-core-2.15.4.tar.xz" version="2.15.4"
+ repo="ftp.gnome.org"
+ hash="sha256:0e3b01af6ba06d98faf7b85891ece394897fe145b0760b7846e810b57f1b809f">
+ </branch>
+ <dependencies>
+ <dep package="glib"/>
+ </dependencies>
+ </autotools>
+
+ <autotools id="at-spi2-atk">
+ <branch module="pub/GNOME/sources/at-spi2-atk/2.15/at-spi2-atk-2.15.4.tar.xz" version="2.15.4"
+ repo="ftp.gnome.org"
+ hash="sha256:3283aa5207b81e4c77d24c4e8b1c0abe6c850b11a2e62cd873cc07af0b403501">
+ </branch>
+ <dependencies>
+ <dep package="glib"/>
+ <dep package="atk"/>
+ <dep package="at-spi2-core"/>
+ </dependencies>
+ </autotools>
+
+ <autotools id="libxml2" supports-non-srcdir-builds="no"
+ autogen-sh="./autogen.sh; ./configure --with-python=no">
+ <branch module="/sources/libxml2-2.9.1.tar.gz" version="2.9.1"
+ repo="xmlsoft.org"
+ hash="sha256:fd3c64cb66f2c4ea27e934d275904d92cec494a8e8405613780cbc8a71680fdb"
+ md5sum="9c0cfef285d5c4a5c80d00904ddab380"/>
+ </autotools>
+
+ <autotools id="libxslt">
+ <branch module="/sources/libxslt-${version}.tar.gz" version="1.1.29"
+ repo="xmlsoft.org"
+ hash="sha256:b5976e3857837e7617b29f2249ebb5eeac34e249208d31f1fbf7a6ba7a4090ce"/>
+ <dependencies>
+ <dep package="libxml2"/>
+ </dependencies>
+ </autotools>
+
+ <autotools id="orc" autogenargs="--disable-gtk-doc" autogen-sh="configure">
+ <branch module="orc/orc-0.4.17.tar.gz" version="0.4.17"
+ repo="gstreamer"
+ hash="sha256:4fc7cca48c59fff23afee78fb642cdbde001f56401c8f47b95a16578d1d5d7e8"
+ md5sum="af1bf3dab9e69f3c36f389285e2a12a1"/>
+ </autotools>
+
+ <autotools id="gstreamer" autogen-sh="configure" autogenargs="--disable-gtk-doc">
+ <if condition-set="macos">
+ <autogenargs value="--disable-introspection"/>
+ </if>
+ <dependencies>
+ <dep package="orc"/>
+ </dependencies>
+ <branch module="gstreamer/gstreamer-${version}.tar.xz" version="1.8.0"
+ repo="gstreamer"
+ hash="sha256:947a314a212b5d94985d89b43440dbe66b696e12bbdf9a2f78967b98d74abedc"
+ md5sum="6846d7289ec323c38c49b818171e955a">
+ <patch file="gstreamer-0001-protection-added-function-to-filter-system-ids.patch" strip="1"/>
+ </branch>
+ </autotools>
+
+ <autotools id="gst-plugins-base"
+ autogen-sh="configure"
+ autogenargs="--disable-examples --disable-gtk-doc">
+ <if condition-set="macos">
+ <autogenargs value="--disable-introspection"/>
+ </if>
+ <dependencies>
+ <dep package="gstreamer"/>
+ </dependencies>
+ <branch module="gst-plugins-base/gst-plugins-base-${version}.tar.xz" version="1.8.0"
+ repo="gstreamer"
+ hash="sha256:abc0acc1d15b4b9c97c65cd9689bd6400081853b9980ea428d3c8572dd791522"
+ md5sum="20cc8231609318310f2a55f64c86cbb4"/>
+ </autotools>
+
+ <autotools id="gst-plugins-good" autogen-sh="configure" autogenargs="--disable-examples --disable-soup --disable-gtk-doc">
+ <if condition-set="macos">
+ <autogenargs value="--disable-introspection"/>
+ </if>
+ <dependencies>
+ <dep package="gst-plugins-base"/>
+ <dep package="libvpx"/>
+ </dependencies>
+
+ <branch module="gst-plugins-good/gst-plugins-good-${version}.tar.xz" version="1.8.0"
+ repo="gstreamer"
+ hash="sha256:c20c134d47dbc238d921707a3b66da709c2b4dd89f9d267cec13d1ddf16e9f4d"
+ md5sum="91ed4649c7c2e43a61f731d144f6f6d0">
+ <patch file="gst-plugins-good-use-the-tfdt-decode-time.patch" strip="1"/>
+ <patch file="gst-plugins-good-Revert-qtdemux-expose-streams-with-first-moof-for-fr.patch" strip="1"/>
+ <patch file="gst-plugins-good-0001-rtpbin-pipeline-gets-an-EOS-when-any-rtpsources-byes.patch" strip="1"/>
+ <patch file="gst-plugins-good-0002-rtpbin-avoid-generating-errors-when-rtcp-messages-ar.patch" strip="1"/>
+ <patch file="gst-plugins-good-0003-rtpbin-receive-bundle-support.patch" strip="1"/>
+ <patch file="gst-plugins-good-0004-qtdemux-add-context-for-a-preferred-protection.patch" strip="1"/>
+ </branch>
+ </autotools>
+
+ <autotools id="gst-plugins-bad" autogen-sh="configure" autogenargs="--disable-examples --disable-gtk-doc">
+ <if condition-set="macos">
+ <autogenargs value="--disable-introspection"/>
+ </if>
+ <dependencies>
+ <dep package="gst-plugins-base"/>
+ <dep package="openh264"/>
+ </dependencies>
+ <branch module="gst-plugins-bad/gst-plugins-bad-${version}.tar.xz" version="1.8.0"
+ repo="gstreamer"
+ hash="sha256:116376dd1085082422e0b21b0ecd3d1cb345c469c58e32463167d4675f4ca90e"
+ md5sum="1c2d797bb96a81e9ef570c7a0a37203e">
+ <patch file="gst-plugins-bad-0001-dtls-port-to-OpenSSL-1.1.0.patch" strip="1"/>
+ <patch file="gst-plugins-bad-0002-dtlscertificate-Fix-error-checking-in-RSA_generate_k.patch" strip="1"/>
+ </branch>
+ </autotools>
+
+ <autotools id="gst-libav" autogen-sh="configure" autogenargs="--with-libav-extra-configure='--disable-yasm' --disable-gtk-doc">
+ <dependencies>
+ <dep package="gst-plugins-base"/>
+ </dependencies>
+ <branch module="gst-libav/gst-libav-${version}.tar.xz" version="1.8.0"
+ repo="gstreamer"
+ hash="sha256:5a1ce28876aee93cb4f3d090f0e807915a5d9bc1325e3480dd302b85aeb4291c"
+ md5sum="361638fa45466c5050bcde6bfe10fa46"/>
+ </autotools>
+
+ <autotools id="xserver" autogenargs="--disable-xinerama --enable-glx --enable-composite --disable-xorg --disable-dmx --disable-xnest --disable-xquartz --disable-xwin --disable-xephyr --disable-xfake --disable-xfbdev --disable-install-setuid --disable-unit-tests --disable-present --enable-unix-transport --enable-tcp-transport --disable-local-transport --with-xkb-path=/usr/share/X11/xkb --with-xkb-output=/var/lib/xkb --with-xkb-bin-directory=/usr/bin --without-dtrace">
+ <dependencies>
+ <dep package="pixman"/>
+ </dependencies>
+ <branch module="/releases/individual/xserver/xorg-server-1.16.4.tar.bz2" version="1.16.4"
+ repo="xorg"
+ hash="sha256:abb6e1cc9213a9915a121f48576ff6739a0b8cdb3d32796f9a7743c9a6efc871"
+ md5sum="80d140f631d862b76dc67ae983151c77">
+ <patch file="xserver-remove-bogus-dependencies.patch" strip="1"/>
+ <patch file="xserver-search-for-DRI-drivers-at-LIBGL_DRIVERS_PATH-environ.patch" strip="1"/>
+ </branch>
+ </autotools>
+
+ <autotools id="wayland" autogenargs="--disable-documentation">
+ <pkg-config>wayland-server.pc</pkg-config>
+ <dependencies>
+ <dep package="libffi"/>
+ </dependencies>
+ <branch module="releases/wayland-1.8.1.tar.xz"
+ version="1.8.1"
+ repo="wayland.freedesktop.org"
+ hash="sha256:f17c938d1c24fd0a10f650a623a2775d329db3168b5732e498b08388ec776fc8"
+ md5sum="6e877877c3e04cfb865cfcd0733c9ab1">
+ </branch>
+ </autotools>
+
+ <autotools id="weston" autogenargs="--enable-x11-compositor --disable-rpi-compositor --disable-fbdev-compositor --disable-setuid-install --disable-ivi-shell --disable-weston-launch --with-cairo=gl">
+ <pkg-config>weston.pc</pkg-config>
+ <dependencies>
+ <dep package="wayland"/>
+ <dep package="libdrm"/>
+ <dep package="xserver"/>
+ <dep package="cairo"/>
+ <dep package="libinput"/>
+ </dependencies>
+ <branch module="releases/weston-1.8.0.tar.xz"
+ version="1.8.0"
+ repo="wayland.freedesktop.org"
+ hash="sha256:8963e69f328e815cec42c58046c4af721476c7541bb7d9edc71740fada5ad312"
+ md5sum="24cb8a7ed0535b4fc3642643988dab36">
+ </branch>
+ </autotools>
+
+ <autotools id="gtk-doc" autogen-sh="configure">
+ <if condition-set="macos">
+ <autogenargs value="--with-xml-catalog=/usr/local/etc/xml/catalog"/>
+ </if>
+ <dependencies>
+ <dep package="glib"/>
+ </dependencies>
+ <branch module="/pub/GNOME/sources/gtk-doc/${version}/gtk-doc-${version}.tar.xz" version="1.25"
+ repo="ftp.gnome.org"
+ hash="sha256:1ea46ed400e6501f975acaafea31479cea8f32f911dca4dff036f59e6464fd42"/>
+ </autotools>
+
+ <autotools id="libdrm" autogen-sh="configure">
+ <pkg-config>libdrm.pc</pkg-config>
+ <branch module="/libdrm/libdrm-2.4.65.tar.bz2" version="2.4.65"
+ repo="dri.freedesktop.org"
+ hash="sha256:71960ac8bde7d710992b1bc8879935e8300a870c36bd06f22412d0447e3d96c4"/>
+ </autotools>
+
+ <autotools id="mesa"
+ autogen-template="%(srcdir)s/%(autogen-sh)s --prefix %(prefix)s/softGL %(autogenargs)s"
+ autogenargs="--disable-dri3 --enable-dri --enable-glx --enable-egl --with-egl-platforms=x11,wayland --with-dri-drivers=swrast --with-gallium-drivers=swrast">
+ <!--- WARNING: At jhbuildrc, when we define the path to the Gallium llvmpipe software rasterizer (needed by XvfbDriver),
+ we assume that the directory is named "Mesa". So, don't change the checkoutdir name even if you update the version. -->
+ <branch module="/~brianp/mesa/older-versions/11.x/11.0.6/mesa-11.0.6.tar.xz" version="11.0.6"
+ checkoutdir="Mesa"
+ repo="people.freedesktop.org"
+ hash="sha256:8340e64cdc91999840404c211496f3de38e7b4cb38db34e2f72f1642c5134760">
+ </branch>
+ <dependencies>
+ <dep package="llvm"/>
+ <dep package="libdrm"/>
+ <dep package="wayland"/>
+ </dependencies>
+ </autotools>
+
+ <autotools id="libusrsctp" supports-non-srcdir-builds="no" autogen-sh="./bootstrap; ./configure --disable-warnings-as-errors">
+ <branch repo="github.com" module="sctplab/usrsctp.git" checkoutdir="usrsctp" tag="078ff3252f73327e0ac11d6fd5eff62011f6646e"/>
+ </autotools>
+
+ <autotools id="openh264" supports-non-srcdir-builds="no" autogen-sh="pseudo-configure">
+ <branch module="cisco/openh264/archive/v${version}.tar.gz" version="1.5.0"
+ checkoutdir="openh264-${version}" repo="github-tarball">
+ <patch file="openh264-configure.patch" strip="0"/>
+ </branch>
+ </autotools>
+
+ <autotools id="libvpx"
+ autogen-template="%(srcdir)s/configure --prefix=%(prefix)s --enable-pic --as=yasm --disable-unit-tests --size-limit=16384x16384 --enable-postproc --enable-multi-res-encoding --enable-temporal-denoising --enable-vp9-temporal-denoising --enable-vp9-postproc --enable-shared">
+ <branch repo="github.com" module="webmproject/libvpx.git" version="1.6.0" checkoutdir="libvpx-1.6.0">
+ </branch>
+ </autotools>
+
+ <autotools id="gst-plugins-openwebrtc" supports-parallel-builds="no" supports-non-srcdir-builds="no" autogen-sh="./autogen.sh; ./configure">
+ <dependencies>
+ <dep package="gst-plugins-base"/>
+ <dep package="libusrsctp"/>
+ </dependencies>
+ <branch repo="github.com" module="Igalia/openwebrtc-gst-plugins.git" checkoutdir="gst-plugins-openwebrtc" tag="9b2199ea970369dbf1d9ca2f8e61c95f21db2b6e"/>
+ </autotools>
+
+ <autotools id="libnice" supports-non-srcdir-builds="no">
+ <dependencies>
+ <dep package="gstreamer"/>
+ </dependencies>
+ <branch module="libnice/libnice/archive/${version}.tar.gz" version="2803a0b4b70af9684e05ef5ed3f0c2fbca4b6c93"
+ checkoutdir="libnice-${version}" repo="github-tarball">
+ <patch file="libnice-0001-nicesrc-spin-the-agent-mainloop-in-a-separate-thread.patch" strip="1"/>
+ <patch file="libnice-0001-TURN-allow-REALM-to-be-empty.patch" strip="1"/>
+ </branch>
+ </autotools>
+
+ <autotools id="openwebrtc" autogenargs="--enable-bridge=no --enable-owr-gst=yes">
+ <dependencies>
+ <dep package="gst-plugins-openwebrtc"/>
+ <dep package="gst-plugins-bad"/>
+ <dep package="libnice"/>
+ </dependencies>
+ <branch repo="github.com" module="Igalia/openwebrtc.git" checkoutdir="openwebrtc" tag="7f3d23e034818893db198f4b56e41609abd8847b"/>
+ </autotools>
+
+ <autotools id="llvm"
+ autogenargs="--enable-optimized --disable-terminfo --disable-zlib --enable-targets=host --disable-backtraces --disable-crash-overrides --disable-expensive-checks --disable-debug-runtime --disable-assertions --enable-shared --enable-bindings=none">
+ <branch repo="llvm.org"
+ module="/releases/3.7.0/llvm-3.7.0.src.tar.xz" version="3.7.0" checkoutdir="llvm-3.7.0"
+ hash="sha256:ab45895f9dcdad1e140a3a79fd709f64b05ad7364e308c0e582c5b02e9cc3153"/>
+ </autotools>
+
+ <autotools id="gsettings-desktop-schemas" autogen-sh="configure">
+ <dependencies>
+ <dep package="glib"/>
+ </dependencies>
+ <branch module="/pub/GNOME/sources/gsettings-desktop-schemas/3.16/gsettings-desktop-schemas-3.16.1.tar.xz" version="3.16.1"
+ repo="ftp.gnome.org"
+ hash="sha256:74fe9fdad510c8a6666febeceb7ebafc581ef990b3afcc8c1e8b5d90b24b3461">
+ </branch>
+ </autotools>
+
+ <autotools id="shared-mime-info"
+ autogenargs="--disable-default-make-check">
+ <dependencies>
+ <dep package="libxml2"/>
+ <dep package="glib"/>
+ </dependencies>
+ <branch module="/~hadess/shared-mime-info-${version}.tar.xz" version="1.5"
+ repo="freedesktop.org"
+ hash="sha256:d6412840eb265bf36e61fd7b6fc6bea21b0f58cb22bed16f2ccccdd54bea4180">
+ <patch file="shared-mime-info-xht-glob.patch" strip="1"/>
+ <patch file="shared-mime-info-xhtml-magic.patch" strip="1"/>
+ </branch>
+ </autotools>
+
+ <autotools id="icu"
+ autogen-sh="./source/configure"
+ autogenargs="--disable-samples --enable-weak-threads">
+ <branch module="icu4c-55_1-src.tgz" version="55.1" checkoutdir="icu"
+ repo="webkitgtk-jhbuild-mirror"
+ hash="sha256:e16b22cbefdd354bec114541f7849a12f8fc2015320ca5282ee4fd787571457b">
+ <patch file="icudata-stdlibs.patch" strip="1"/>
+ </branch>
+ </autotools>
+
+ <!-- Dependencies listed below this point are not thought to affect test results, and are only
+ included because they themselves depend on other dependencies built by jhbuild. -->
+
+ <autotools id="pango" autogen-sh="configure"
+ autogenargs="--enable-cairo">
+ <dependencies>
+ <dep package="cairo"/>
+ <dep package="fontconfig"/>
+ </dependencies>
+ <branch module="/pub/GNOME/sources/pango/1.36/pango-1.36.8.tar.xz" version="1.36.8"
+ repo="ftp.gnome.org"
+ hash="sha256:18dbb51b8ae12bae0ab7a958e7cf3317c9acfc8a1e1103ec2f147164a0fc2d07">
+ </branch>
+ </autotools>
+
+ <!-- libinput is only included because the version of libinput shipped with Debian Jessie
+ os too old for building Weston 1.8. This may be removed after Debian Strech is released -->
+ <autotools id="libinput" autogen-sh="configure" autogenargs="--disable-libwacom --disable-tests --disable-documentation">
+ <pkg-config>libinput.pc</pkg-config>
+ <branch module="software/libinput/libinput-1.2.4.tar.xz"
+ version="1.2.4"
+ repo="freedesktop.org"
+ hash="sha256:aee3650ad2a864ab9a10e7e63df543cc2b475f6bf3974751037a2df325dabbb1"
+ md5sum="1cbaa34f04a336f2703906d564e0a37a">
+ </branch>
+ </autotools>
+
+</moduleset>
diff --git a/Tools/gtk/jhbuildrc b/Tools/gtk/jhbuildrc
new file mode 100644
index 000000000..3ed2c9da7
--- /dev/null
+++ b/Tools/gtk/jhbuildrc
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+# Copyright (C) 2011-2014 Igalia S.L.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+import sys
+import os
+
+sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../jhbuild") )
+import jhbuildrc_common
+jhbuildrc_common.init(globals(), "gtk")
+
+__gtk_tools_directory = os.path.abspath(os.path.dirname(__file__))
+sys.path = [__gtk_tools_directory] + sys.path
+import common
+
+# LLVM requires that builddir != srcdir, and it's not possible to do that in jhbuild only
+# for a module, so we do it here globally since it's a good idea for all other modules as well.
+buildroot = os.path.join(os.path.dirname(checkoutroot), "Build")
+
+# For the layout tests: path where llvmpipe/software-only mesa libraries are installed.
+os.environ['LLVMPIPE_LIBGL_PATH'] = os.path.abspath(os.path.join(prefix, 'softGL', 'lib'))
+
+# We only want to export this when bulding the JHBuild, but not when building WebKit.
+# When the build-webkit script is used, we end executing 'jhbuild [...] run cmake [...]'.
+# But when the JHBuild gets built, we end executing 'jhbuild [...] build'.
+# So we can know if we are building the JHBuild by checking that 'run' is not an argument.
+if 'run' not in sys.argv:
+ os.environ['CFLAGS'] = '-Wno-error -O2 -g1'
+ os.environ['CXXFLAGS'] = '-Wno-error -O2 -g1'
+ # For building gstreamer plugins on the Mac.
+ os.environ['OBJCFLAGS'] = '-Wno-error -O2 -g1'
diff --git a/Tools/gtk/make-dist.py b/Tools/gtk/make-dist.py
new file mode 100755
index 000000000..4f0c4d589
--- /dev/null
+++ b/Tools/gtk/make-dist.py
@@ -0,0 +1,333 @@
+#!/usr/bin/env python
+# Copyright (C) 2014 Igalia S.L.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+from __future__ import print_function
+from contextlib import closing
+
+import argparse
+import errno
+import multiprocessing
+import os
+import re
+import shutil
+import subprocess
+import tarfile
+
+
+def enum(**enums):
+ return type('Enum', (), enums)
+
+
+class Rule(object):
+ Result = enum(INCLUDE=1, EXCLUDE=2, NO_MATCH=3)
+
+ def __init__(self, type, pattern):
+ self.type = type
+ self.original_pattern = pattern
+ self.pattern = re.compile(pattern)
+
+ def test(self, file):
+ if not(self.pattern.search(file)):
+ return Rule.Result.NO_MATCH
+ return self.type
+
+
+class Ruleset(object):
+ _global_rules = None
+
+ def __init__(self):
+ # By default, accept all files.
+ self.rules = [Rule(Rule.Result.INCLUDE, '.*')]
+
+ @classmethod
+ def global_rules(cls):
+ if not cls._global_rules:
+ cls._global_rules = Ruleset()
+ return cls._global_rules
+
+ @classmethod
+ def add_global_rule(cls, rule):
+ cls.global_rules().add_rule(rule)
+
+ def add_rule(self, rule):
+ self.rules.append(rule)
+
+ def passes(self, file):
+ allowed = False
+ for rule in self.rules:
+ result = rule.test(file)
+ if result == Rule.Result.NO_MATCH:
+ continue
+ allowed = Rule.Result.INCLUDE == result
+ return allowed
+
+
+class File(object):
+ def __init__(self, source_root, tarball_root):
+ self.source_root = source_root
+ self.tarball_root = tarball_root
+
+ def should_skip_file(self, path):
+ # Do not skip files explicitly added from the manifest.
+ return False
+
+ def get_files(self):
+ yield (self.source_root, self.tarball_root)
+
+
+class Directory(object):
+ def __init__(self, source_root, tarball_root):
+ self.source_root = source_root
+ self.tarball_root = tarball_root
+ self.rules = Ruleset()
+
+ self.files_in_version_control = self.list_files_in_version_control()
+
+ def add_rule(self, rule):
+ self.rules.add_rule(rule)
+
+ def get_tarball_path(self, filename):
+ return filename.replace(self.source_root, self.tarball_root, 1)
+
+ def list_files_in_version_control(self):
+ # FIXME: Only git is supported for now.
+ p = subprocess.Popen(['git', 'ls-tree', '-r', '--name-only', 'HEAD', self.source_root], stdout=subprocess.PIPE)
+ out = p.communicate()[0]
+ if not out:
+ return []
+ return out.rstrip('\n').split('\n')
+
+ def should_skip_file(self, path):
+ return path not in self.files_in_version_control
+
+ def get_files(self):
+ for root, dirs, files in os.walk(self.source_root):
+
+ def passes_all_rules(entry):
+ return Ruleset.global_rules().passes(entry) and self.rules.passes(entry)
+
+ to_keep = filter(passes_all_rules, dirs)
+ del dirs[:]
+ dirs.extend(to_keep)
+
+ for file in files:
+ file = os.path.join(root, file)
+ if not passes_all_rules(file):
+ continue
+ yield (file, self.get_tarball_path(file))
+
+
+class Manifest(object):
+ def __init__(self, manifest_filename, source_root, build_root, tarball_root='/'):
+ self.current_directory = None
+ self.directories = []
+ self.tarball_root = tarball_root
+ self.source_root = source_root
+ self.build_root = build_root
+
+ # Normalize the tarball root so that it starts and ends with a slash.
+ if not self.tarball_root.endswith('/'):
+ self.tarball_root = self.tarball_root + '/'
+ if not self.tarball_root.startswith('/'):
+ self.tarball_root = '/' + self.tarball_root
+
+ with open(manifest_filename, 'r') as file:
+ for line in file.readlines():
+ self.process_line(line)
+
+ def add_rule(self, rule):
+ if self.current_directory is not None:
+ self.current_directory.add_rule(rule)
+ else:
+ Ruleset.add_global_rule(rule)
+
+ def add_directory(self, directory):
+ self.current_directory = directory
+ self.directories.append(directory)
+
+ def get_full_source_path(self, source_path):
+ if not os.path.exists(source_path):
+ source_path = os.path.join(self.source_root, source_path)
+ if not os.path.exists(source_path):
+ raise Exception('Could not find directory %s' % source_path)
+ return source_path
+
+ def get_full_tarball_path(self, path):
+ return self.tarball_root + path
+
+ def get_source_and_tarball_paths_from_parts(self, parts):
+ full_source_path = self.get_full_source_path(parts[1])
+ if len(parts) > 2:
+ full_tarball_path = self.get_full_tarball_path(parts[2])
+ else:
+ full_tarball_path = self.get_full_tarball_path(parts[1])
+ return (full_source_path, full_tarball_path)
+
+ def process_line(self, line):
+ parts = line.split()
+ if not parts:
+ return
+ if parts[0].startswith("#"):
+ return
+
+ if parts[0] == "directory" and len(parts) > 1:
+ self.add_directory(Directory(*self.get_source_and_tarball_paths_from_parts(parts)))
+ elif parts[0] == "file" and len(parts) > 1:
+ self.add_directory(File(*self.get_source_and_tarball_paths_from_parts(parts)))
+ elif parts[0] == "exclude" and len(parts) > 1:
+ self.add_rule(Rule(Rule.Result.EXCLUDE, parts[1]))
+ elif parts[0] == "include" and len(parts) > 1:
+ self.add_rule(Rule(Rule.Result.INCLUDE, parts[1]))
+ else:
+ raise Exception('Line does not begin with a correct rule:\n\t' + line)
+
+ def should_skip_file(self, directory, filename):
+ # Only allow files that are not in version control when they are explicitly included in the manifest from the build dir.
+ if filename.startswith(self.build_root):
+ return False
+
+ return directory.should_skip_file(filename)
+
+ def get_files(self):
+ for directory in self.directories:
+ for file_tuple in directory.get_files():
+ if self.should_skip_file(directory, file_tuple[0]):
+ continue
+ yield file_tuple
+
+ def create_tarfile(self, output):
+ count = 0
+ for file_tuple in self.get_files():
+ count = count + 1
+
+ with closing(tarfile.open(output, 'w')) as tarball:
+ for i, (file_path, tarball_path) in enumerate(self.get_files(), start=1):
+ print('Tarring file {0} of {1}'.format(i, count).ljust(40), end='\r')
+ tarball.add(file_path, tarball_path)
+ print("Wrote {0}".format(output).ljust(40))
+
+
+class Distcheck(object):
+ BUILD_DIRECTORY_NAME = "_build"
+ INSTALL_DIRECTORY_NAME = "_install"
+
+ def __init__(self, source_root, build_root):
+ self.source_root = source_root
+ self.build_root = build_root
+
+ def extract_tarball(self, tarball_path):
+ with closing(tarfile.open(tarball_path, 'r')) as tarball:
+ tarball.extractall(self.build_root)
+
+ def configure(self, dist_dir, build_dir, install_dir, port):
+ def create_dir(directory, directory_type):
+ try:
+ os.mkdir(directory)
+ except OSError, e:
+ if e.errno != errno.EEXIST or not os.path.isdir(directory):
+ raise Exception("Could not create %s dir at %s: %s" % (directory_type, directory, str(e)))
+
+ create_dir(build_dir, "build")
+ create_dir(install_dir, "install")
+
+ command = ['cmake', '-DPORT=%s' % port, '-DCMAKE_INSTALL_PREFIX=%s' % install_dir, '-DCMAKE_BUILD_TYPE=Release', dist_dir]
+ subprocess.check_call(command, cwd=build_dir)
+
+ def build(self, build_dir):
+ command = ['make']
+ make_args = os.getenv('MAKE_ARGS')
+ if make_args:
+ command.extend(make_args.split(' '))
+ else:
+ command.append('-j%d' % multiprocessing.cpu_count())
+ subprocess.check_call(command, cwd=build_dir)
+
+ def install(self, build_dir):
+ subprocess.check_call(['make', 'install'], cwd=build_dir)
+
+ def clean(self, dist_dir):
+ shutil.rmtree(dist_dir)
+
+ def check(self, tarball, port):
+ tarball_name, ext = os.path.splitext(os.path.basename(tarball))
+ dist_dir = os.path.join(self.build_root, tarball_name)
+ build_dir = os.path.join(dist_dir, self.BUILD_DIRECTORY_NAME)
+ install_dir = os.path.join(dist_dir, self.INSTALL_DIRECTORY_NAME)
+
+ self.extract_tarball(tarball)
+ self.configure(dist_dir, build_dir, install_dir, port)
+ self.build(build_dir)
+ self.install(build_dir)
+ self.clean(dist_dir)
+
+if __name__ == "__main__":
+ class FilePathAction(argparse.Action):
+ def __call__(self, parser, namespace, values, option_string=None):
+ setattr(namespace, self.dest, os.path.abspath(values))
+
+ def ensure_version_if_possible(arguments):
+ if arguments.version is not None:
+ return
+
+ pkgconfig_file = os.path.join(arguments.build_dir, "Source/WebKit2/webkit2gtk-4.0.pc")
+ if os.path.isfile(pkgconfig_file):
+ p = subprocess.Popen(['pkg-config', '--modversion', pkgconfig_file], stdout=subprocess.PIPE)
+ version = p.communicate()[0]
+ if version:
+ arguments.version = version.rstrip('\n')
+
+
+ def get_tarball_root_and_output_filename_from_arguments(arguments):
+ tarball_root = arguments.tarball_name
+ if arguments.version is not None:
+ tarball_root += '-' + arguments.version
+
+ output_filename = os.path.join(arguments.build_dir, tarball_root + ".tar")
+ return tarball_root, output_filename
+
+ parser = argparse.ArgumentParser(description='Build a distribution bundle.')
+ parser.add_argument('-c', '--check', action='store_true',
+ help='Check the tarball')
+ parser.add_argument('-s', '--source-dir', type=str, action=FilePathAction, default=os.getcwd(),
+ help='The top-level directory of the source distribution. ' + \
+ 'Directory for relative paths. Defaults to current directory.')
+ parser.add_argument('--version', type=str, default=None,
+ help='The version of the tarball to generate')
+ parser.add_argument('-b', '--build-dir', type=str, action=FilePathAction, default=os.getcwd(),
+ help='The top-level path of directory of the build root. ' + \
+ 'By default is the current directory.')
+ parser.add_argument('-t', '--tarball-name', type=str, default='webkitgtk',
+ help='Base name of tarball. Defaults to "webkitgtk".')
+ parser.add_argument('-p', '--port', type=str, default='GTK',
+ help='Port to be built in tarball check. Defaults to "GTK".')
+ parser.add_argument('manifest_filename', metavar="manifest", type=str, action=FilePathAction, help='The path to the manifest file.')
+
+ arguments = parser.parse_args()
+
+ # Paths in the manifest are relative to the source directory, and this script assumes that
+ # current working directory is the source directory, so change the current working directory
+ # to be the source directory.
+ os.chdir(arguments.source_dir)
+
+ ensure_version_if_possible(arguments)
+ tarball_root, output_filename = get_tarball_root_and_output_filename_from_arguments(arguments)
+
+ manifest = Manifest(arguments.manifest_filename, arguments.source_dir, arguments.build_dir, tarball_root)
+ manifest.create_tarfile(output_filename)
+
+ if arguments.check:
+ Distcheck(arguments.source_dir, arguments.build_dir).check(output_filename, arguments.port)
diff --git a/Tools/gtk/manifest.txt.in b/Tools/gtk/manifest.txt.in
new file mode 100644
index 000000000..09531e39e
--- /dev/null
+++ b/Tools/gtk/manifest.txt.in
@@ -0,0 +1,106 @@
+# Global rules
+exclude #$
+exclude ChangeLog
+exclude CMakeLists.txt.user
+exclude Makefile
+exclude PlatformAppleWin.cmake
+exclude PlatformEfl.cmake
+exclude PlatformMac.cmake
+exclude PlatformWin.cmake
+exclude PlatformWinCairo.cmake
+exclude tags$
+exclude ~$
+exclude \.#$
+exclude \.bak$
+exclude \.cproject$
+exclude \.git$
+exclude \.gitattributes$
+exclude \.gitignore$
+exclude \.icns$
+exclude \.lproj$
+exclude \.m$
+exclude \.mm$
+exclude \.nib$
+exclude \.o$
+exclude \.order$
+exclude \.orig$
+exclude \.pdf$
+exclude \.plist$
+exclude \.project$
+exclude \.props$
+exclude \.pyc$
+exclude \.pyo$
+exclude \.rej$
+exclude \.rtf$
+exclude \.sb$
+exclude \.sb\.in$
+exclude \.settings$
+exclude \.svn$
+exclude \.sw[a-p]$
+exclude \.vcxproj$
+exclude \.xib$
+exclude \.xcconfig$
+exclude \.xcodeproj$
+
+# Exclude directories from other ports
+exclude .*\/(Configurations|mac|ios|cf|cg|cocoa|Cocoa|objc|avfoundation|ca|curl|efl|win)\/.*$
+
+directory Source
+exclude Source/JavaScriptCore/tests
+exclude Source/ThirdParty/libwebrtc
+exclude Source/ThirdParty/qunit
+exclude Source/WebCore/platform/audio/resources
+exclude Source/WebCore/bindings/scripts/test
+exclude Source/WebCore/platform/efl/DefaultTheme
+exclude Source/WebCore/Resources
+exclude Source/WebKit/.*
+exclude Source/cmake/EFLHelpers.cmake$
+exclude Source/cmake/OptionsWinCairo.cmake$
+exclude Source/cmake/OptionsWindows.cmake$
+exclude Source/cmake/OptionsAppleWin.cmake$
+exclude Source/cmake/OptionsEfl.cmake$
+exclude Source/cmake/eflsymbols.filter$
+exclude Source/WebInspectorUI/Tools
+exclude Source/WebInspectorUI/UserInterface/Images
+
+exclude Source/WebKit2/Resources
+exclude Source/WebKit2/gtk/NEWS$
+
+# We do want to include the NEWS, but we want it to be in the root of the archive.
+file Source/WebKit2/gtk/NEWS NEWS
+
+directory Source/WebInspectorUI/UserInterface/Images/gtk
+file Source/WebCore/English.lproj/mediaControlsLocalizedStrings.js Source/WebCore/English.lproj/mediaControlsLocalizedStrings.js
+file Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
+
+# Include only the resources we actually build
+file Source/WebCore/Resources/missingImage.png
+file Source/WebCore/Resources/missingImage@2x.png
+file Source/WebCore/Resources/panIcon.png
+file Source/WebCore/Resources/plugIns.js
+file Source/WebCore/Resources/textAreaResizeCorner.png
+file Source/WebCore/Resources/textAreaResizeCorner@2x.png
+file Source/WebCore/Resources/urlIcon.png
+file Source/WebCore/platform/audio/resources/Composite.wav
+
+directory Tools/gtk
+directory Tools/ImageDiff
+directory Tools/MiniBrowser
+directory Tools/TestWebKitAPI
+
+directory Tools/DumpRenderTree
+exclude Tools/DumpRenderTree/fonts
+
+directory Tools/WebKitTestRunner
+exclude Tools/WebKitTestRunner/fonts/
+
+file CMakeLists.txt
+file Tools/CMakeLists.txt
+file Tools/Scripts/VCSUtils.pm
+file Tools/Scripts/run-gtk-tests
+file Tools/Scripts/webkit-build-directory
+file Tools/Scripts/webkitdirs.pm
+file Tools/jhbuild/jhbuildutils.py
+
+directory ${CMAKE_BINARY_DIR}/Documentation/webkit2gtk-${WEBKITGTK_API_VERSION}/html Documentation/webkit2gtk-${WEBKITGTK_API_VERSION}/html
+directory ${CMAKE_BINARY_DIR}/Documentation/webkitdomgtk-${WEBKITGTK_API_VERSION}/html Documentation/webkitdomgtk-${WEBKITGTK_API_VERSION}/html
diff --git a/Tools/gtk/patches/fontconfig-C-11-requires-a-space-between-literal-and-identifier.patch b/Tools/gtk/patches/fontconfig-C-11-requires-a-space-between-literal-and-identifier.patch
new file mode 100644
index 000000000..b4e0a541d
--- /dev/null
+++ b/Tools/gtk/patches/fontconfig-C-11-requires-a-space-between-literal-and-identifier.patch
@@ -0,0 +1,30 @@
+From 7069d717e982adcf8e1d300cbd10eec6322a65c9 Mon Sep 17 00:00:00 2001
+From: Akira TAGOH <akira@tagoh.org>
+Date: Sun, 22 Apr 2012 21:40:44 +0900
+Subject: [PATCH] C++11 requires a space between literal and identifier
+
+Reported by Buganini
+---
+ fontconfig/fontconfig.h | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/fontconfig/fontconfig.h b/fontconfig/fontconfig.h
+index 0e2ca50..b27ccb5 100644
+--- a/fontconfig/fontconfig.h
++++ b/fontconfig/fontconfig.h
+@@ -112,9 +112,9 @@ typedef int FcBool;
+ #define FC_DECORATIVE "decorative" /* Bool - true if style is a decorative variant */
+ #define FC_LCD_FILTER "lcdfilter" /* Int */
+
+-#define FC_CACHE_SUFFIX ".cache-"FC_CACHE_VERSION
+-#define FC_DIR_CACHE_FILE "fonts.cache-"FC_CACHE_VERSION
+-#define FC_USER_CACHE_FILE ".fonts.cache-"FC_CACHE_VERSION
++#define FC_CACHE_SUFFIX ".cache-" FC_CACHE_VERSION
++#define FC_DIR_CACHE_FILE "fonts.cache-" FC_CACHE_VERSION
++#define FC_USER_CACHE_FILE ".fonts.cache-" FC_CACHE_VERSION
+
+ /* Adjust outline rasterizer */
+ #define FC_CHAR_WIDTH "charwidth" /* Int */
+--
+1.8.3.2
+
diff --git a/Tools/gtk/patches/fontconfig-fix-osx-cache.diff b/Tools/gtk/patches/fontconfig-fix-osx-cache.diff
new file mode 100644
index 000000000..2c71bc83a
--- /dev/null
+++ b/Tools/gtk/patches/fontconfig-fix-osx-cache.diff
@@ -0,0 +1,207 @@
+diff --git a/fc-cache/fc-cache.c b/fc-cache/fc-cache.c
+index 99e0e9f..bf3b6b4 100644
+--- a/fc-cache/fc-cache.c
++++ b/fc-cache/fc-cache.c
+@@ -187,13 +187,8 @@ scanDirs (FcStrList *list, FcConfig *config, FcBool force, FcBool really_force,
+
+ if (!cache)
+ {
+- if (!recursive)
+- cache = FcDirCacheRescan (dir, config);
+- else
+- {
+- (*changed)++;
+- cache = FcDirCacheRead (dir, FcTrue, config);
+- }
++ (*changed)++;
++ cache = FcDirCacheRead (dir, FcTrue, config);
+ if (!cache)
+ {
+ fprintf (stderr, "%s: error scanning\n", dir);
+@@ -391,7 +386,6 @@ main (int argc, char **argv)
+ ret += scanDirs (list, config, FcTrue, really_force, verbose, FcFalse, &changed, NULL);
+ FcStrListDone (list);
+ }
+- FcStrSetDestroy (updateDirs);
+
+ /*
+ * Try to create CACHEDIR.TAG anyway.
+diff --git a/fontconfig/fontconfig.h b/fontconfig/fontconfig.h
+index 2258251..d0b4e9e 100644
+--- a/fontconfig/fontconfig.h
++++ b/fontconfig/fontconfig.h
+@@ -541,9 +541,6 @@ FcDirSave (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir);
+
+ FcPublic FcCache *
+ FcDirCacheLoad (const FcChar8 *dir, FcConfig *config, FcChar8 **cache_file);
+-
+-FcPublic FcCache *
+-FcDirCacheRescan (const FcChar8 *dir, FcConfig *config);
+
+ FcPublic FcCache *
+ FcDirCacheRead (const FcChar8 *dir, FcBool force, FcConfig *config);
+diff --git a/src/fccache.c b/src/fccache.c
+index 5173e0b..10eacff 100644
+--- a/src/fccache.c
++++ b/src/fccache.c
+@@ -828,19 +828,6 @@ bail1:
+ return NULL;
+ }
+
+-FcCache *
+-FcDirCacheRebuild (FcCache *cache, struct stat *dir_stat, FcStrSet *dirs)
+-{
+- FcCache *new;
+- FcFontSet *set = FcFontSetDeserialize (FcCacheSet (cache));
+- const FcChar8 *dir = FcCacheDir (cache);
+-
+- new = FcDirCacheBuild (set, dir, dir_stat, dirs);
+- FcFontSetDestroy (set);
+-
+- return new;
+-}
+-
+ /* write serialized state to the cache file */
+ FcBool
+ FcDirCacheWrite (FcCache *cache, FcConfig *config)
+diff --git a/src/fcdir.c b/src/fcdir.c
+index 3bcd0b8..b040a28 100644
+--- a/src/fcdir.c
++++ b/src/fcdir.c
+@@ -130,12 +130,7 @@ FcFileScanConfig (FcFontSet *set,
+ if (FcFileIsDir (file))
+ return FcStrSetAdd (dirs, file);
+ else
+- {
+- if (set)
+- return FcFileScanFontConfig (set, blanks, file, config);
+- else
+- return FcTrue;
+- }
++ return FcFileScanFontConfig (set, blanks, file, config);
+ }
+
+ FcBool
+@@ -311,45 +306,6 @@ FcDirCacheScan (const FcChar8 *dir, FcConfig *config)
+ return cache;
+ }
+
+-FcCache *
+-FcDirCacheRescan (const FcChar8 *dir, FcConfig *config)
+-{
+- FcCache *cache = FcDirCacheLoad (dir, config, NULL);
+- FcCache *new = NULL;
+- struct stat dir_stat;
+- FcStrSet *dirs;
+-
+- if (!cache)
+- return NULL;
+- if (FcStatChecksum (dir, &dir_stat) < 0)
+- goto bail;
+- dirs = FcStrSetCreate ();
+- if (!dirs)
+- goto bail;
+-
+- /*
+- * Scan the dir
+- */
+- if (!FcDirScanConfig (NULL, dirs, NULL, dir, FcTrue, config))
+- goto bail1;
+- /*
+- * Rebuild the cache object
+- */
+- new = FcDirCacheRebuild (cache, &dir_stat, dirs);
+- if (!new)
+- goto bail1;
+- FcDirCacheUnload (cache);
+- /*
+- * Write out the cache file, ignoring any troubles
+- */
+- FcDirCacheWrite (new, config);
+-
+-bail1:
+- FcStrSetDestroy (dirs);
+-bail:
+- return new;
+-}
+-
+ /*
+ * Read (or construct) the cache for a directory
+ */
+diff --git a/src/fcfs.c b/src/fcfs.c
+index 21c6c7c..941abba 100644
+--- a/src/fcfs.c
++++ b/src/fcfs.c
+@@ -122,28 +122,6 @@ FcFontSetSerialize (FcSerialize *serialize, const FcFontSet * s)
+
+ return s_serialize;
+ }
+-
+-FcFontSet *
+-FcFontSetDeserialize (const FcFontSet *set)
+-{
+- int i;
+- FcFontSet *new = FcFontSetCreate ();
+-
+- if (!new)
+- return NULL;
+- for (i = 0; i < set->nfont; i++)
+- {
+- if (!FcFontSetAdd (new, FcPatternDuplicate (FcFontSetFont (set, i))))
+- goto bail;
+- }
+-
+- return new;
+-bail:
+- FcFontSetDestroy (new);
+-
+- return NULL;
+-}
+-
+ #define __fcfs__
+ #include "fcaliastail.h"
+ #undef __fcfs__
+diff --git a/src/fcint.h b/src/fcint.h
+index cdf2dab..362ea6f 100644
+--- a/src/fcint.h
++++ b/src/fcint.h
+@@ -567,9 +567,6 @@ FcDirCacheScan (const FcChar8 *dir, FcConfig *config);
+ FcPrivate FcCache *
+ FcDirCacheBuild (FcFontSet *set, const FcChar8 *dir, struct stat *dir_stat, FcStrSet *dirs);
+
+-FcPrivate FcCache *
+-FcDirCacheRebuild (FcCache *cache, struct stat *dir_stat, FcStrSet *dirs);
+-
+ FcPrivate FcBool
+ FcDirCacheWrite (FcCache *cache, FcConfig *config);
+
+@@ -841,9 +838,6 @@ FcFontSetSerializeAlloc (FcSerialize *serialize, const FcFontSet *s);
+ FcPrivate FcFontSet *
+ FcFontSetSerialize (FcSerialize *serialize, const FcFontSet * s);
+
+-FcPrivate FcFontSet *
+-FcFontSetDeserialize (const FcFontSet *set);
+-
+ /* fchash.c */
+ FcPrivate FcChar8 *
+ FcHashGetSHA256Digest (const FcChar8 *input_strings,
+diff --git a/src/fcpat.c b/src/fcpat.c
+index 986cca3..0614ac2 100644
+--- a/src/fcpat.c
++++ b/src/fcpat.c
+@@ -33,7 +33,6 @@ FcPatternCreate (void)
+ p = (FcPattern *) malloc (sizeof (FcPattern));
+ if (!p)
+ return 0;
+- memset (p, 0, sizeof (FcPattern));
+ p->num = 0;
+ p->size = 0;
+ p->elts_offset = FcPtrToOffset (p, NULL);
+@@ -1311,7 +1310,6 @@ FcValueListSerialize (FcSerialize *serialize, const FcValueList *vl)
+ }
+ return head_serialized;
+ }
+-
+ #define __fcpat__
+ #include "fcaliastail.h"
+ #include "fcftaliastail.h" \ No newline at end of file
diff --git a/Tools/gtk/patches/freetype6-2.4.11-truetype-font-height-fix.patch b/Tools/gtk/patches/freetype6-2.4.11-truetype-font-height-fix.patch
new file mode 100644
index 000000000..0ffe76b4e
--- /dev/null
+++ b/Tools/gtk/patches/freetype6-2.4.11-truetype-font-height-fix.patch
@@ -0,0 +1,39 @@
+From e0469372be3870a5ad60b2c4586e9c281357bd28 Mon Sep 17 00:00:00 2001
+From: Werner Lemberg <wl@gnu.org>
+Date: Tue, 22 Jan 2013 10:07:07 +0000
+Subject: [truetype] Fix font height.
+
+* src/truetype/ttobjs.c (tt_size_reset): The Windows rendering
+engine uses rounded values of the ascender and descender to compute
+the TrueType font height.
+---
+diff --git a/src/truetype/ttobjs.c b/src/truetype/ttobjs.c
+index c61b218..590b66c 100644
+--- a/src/truetype/ttobjs.c
++++ b/src/truetype/ttobjs.c
+@@ -4,7 +4,7 @@
+ /* */
+ /* Objects manager (body). */
+ /* */
+-/* Copyright 1996-2012 */
++/* Copyright 1996-2013 */
+ /* David Turner, Robert Wilhelm, and Werner Lemberg. */
+ /* */
+ /* This file is part of the FreeType project, and may only be used, */
+@@ -1177,11 +1177,12 @@
+ FT_PIX_ROUND( FT_MulFix( face->root.ascender, metrics->y_scale ) );
+ metrics->descender =
+ FT_PIX_ROUND( FT_MulFix( face->root.descender, metrics->y_scale ) );
+- metrics->height =
+- FT_PIX_ROUND( FT_MulFix( face->root.height, metrics->y_scale ) );
+ metrics->max_advance =
+ FT_PIX_ROUND( FT_MulFix( face->root.max_advance_width,
+ metrics->x_scale ) );
++
++ /* the height is derived from rounded values */
++ metrics->height = metrics->ascender - metrics->descender;
+ }
+
+ /* compute new transformation */
+--
+cgit v0.9.0.2
diff --git a/Tools/gtk/patches/gdate-suppress-string-format-literal-warning.patch b/Tools/gtk/patches/gdate-suppress-string-format-literal-warning.patch
new file mode 100644
index 000000000..90cb951a1
--- /dev/null
+++ b/Tools/gtk/patches/gdate-suppress-string-format-literal-warning.patch
@@ -0,0 +1,29 @@
+From 3a7efd598d39366c2c9de0def2fdfb35e5e9f2a1 Mon Sep 17 00:00:00 2001
+From: coypu <coypu@sdf.org>
+Date: Mon, 8 Feb 2016 00:06:06 +0200
+Subject: [PATCH 1/1] gdate: Suppress string format literal warning
+
+Newer versions of GCC emit an error here, but we know it's safe.
+https://bugzilla.gnome.org/761550
+---
+ glib/gdate.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/glib/gdate.c b/glib/gdate.c
+index 4aece02..cdc735c 100644
+--- a/glib/gdate.c
++++ b/glib/gdate.c
+@@ -2494,7 +2494,10 @@ g_date_strftime (gchar *s,
+ * recognize whether strftime actually failed or just returned "".
+ */
+ tmpbuf[0] = '\1';
++ #pragma GCC diagnostic push
++ #pragma GCC diagnostic ignored "-Wformat-nonliteral"
+ tmplen = strftime (tmpbuf, tmpbufsize, locale_format, &tm);
++ #pragma GCC diagnostic pop
+
+ if (tmplen == 0 && tmpbuf[0] != '\0')
+ {
+--
+2.7.0
+
diff --git a/Tools/gtk/patches/glib-warning-fix.patch b/Tools/gtk/patches/glib-warning-fix.patch
new file mode 100644
index 000000000..8faf4d11f
--- /dev/null
+++ b/Tools/gtk/patches/glib-warning-fix.patch
@@ -0,0 +1,34 @@
+From 9f90ee5eeccd47f39c7a03dcd786b125a19c195d Mon Sep 17 00:00:00 2001
+From: Michael Catanzaro <mcatanzaro@gnome.org>
+Date: Sat, 13 Jun 2015 22:52:33 -0500
+Subject: [PATCH] genmarshal: silence register storage class warnings
+
+Using the register keyword triggers warnings on noteworthy compilers
+(clang), since it's deprecated in C++ and at danger of being removed
+from the language. There is no reason to use it since it isn't 1980
+anymore.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=750918
+---
+ gobject/glib-genmarshal.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/gobject/glib-genmarshal.c b/gobject/glib-genmarshal.c
+index be4151a..ca78a6f 100644
+--- a/gobject/glib-genmarshal.c
++++ b/gobject/glib-genmarshal.c
+@@ -412,9 +412,9 @@ generate_marshal (const gchar *signame,
+ g_fprintf (fout, "%s%s data2);\n", indent (ind), pad ("gpointer"));
+
+ /* cfile marshal variables */
+- g_fprintf (fout, " register GMarshalFunc_%s callback;\n", signame);
+- g_fprintf (fout, " register GCClosure *cc = (GCClosure*) closure;\n");
+- g_fprintf (fout, " register gpointer data1, data2;\n");
++ g_fprintf (fout, " GMarshalFunc_%s callback;\n", signame);
++ g_fprintf (fout, " GCClosure *cc = (GCClosure*) closure;\n");
++ g_fprintf (fout, " gpointer data1, data2;\n");
+ if (sig->rarg->setter)
+ g_fprintf (fout, " %s v_return;\n", sig->rarg->ctype);
+
+--
+2.4.2 \ No newline at end of file
diff --git a/Tools/gtk/patches/gst-plugins-bad-0001-dtls-port-to-OpenSSL-1.1.0.patch b/Tools/gtk/patches/gst-plugins-bad-0001-dtls-port-to-OpenSSL-1.1.0.patch
new file mode 100644
index 000000000..5d1064ed5
--- /dev/null
+++ b/Tools/gtk/patches/gst-plugins-bad-0001-dtls-port-to-OpenSSL-1.1.0.patch
@@ -0,0 +1,236 @@
+From e938933167c494cdca443334f658b02a03c4486b Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <dueno@redhat.com>
+Date: Wed, 26 Oct 2016 14:51:01 +0200
+Subject: [PATCH] dtls: port to OpenSSL 1.1.0
+
+Changes are:
+
+- Use the wrapper functions to access opaque data types. To preserve
+ backward compatibility, define fallback definitions
+
+- Remove the use of idiom "pqueue_size(ssl->d1->sent_messages)", since
+ there is no replacement
+
+- Use RSA_generate_key_ex instead of the deprecated RSA_generate_key
+
+https://bugzilla.gnome.org/show_bug.cgi?id=773540
+---
+ ext/dtls/gstdtlscertificate.c | 15 ++++++++
+ ext/dtls/gstdtlsconnection.c | 87 ++++++++++++++++++++++++++++++++++++++-----
+ 2 files changed, 93 insertions(+), 9 deletions(-)
+
+diff --git a/ext/dtls/gstdtlscertificate.c b/ext/dtls/gstdtlscertificate.c
+index 95fbb83..c1c9602 100644
+--- a/ext/dtls/gstdtlscertificate.c
++++ b/ext/dtls/gstdtlscertificate.c
+@@ -199,7 +199,22 @@ init_generated (GstDtlsCertificate * self)
+ priv->private_key = NULL;
+ return;
+ }
++
++ /* XXX: RSA_generate_key is actually deprecated in 0.9.8 */
++#if OPENSSL_VERSION_NUMBER < 0x10100001L
+ rsa = RSA_generate_key (2048, RSA_F4, NULL, NULL);
++#else
++ rsa = RSA_new ();
++ if (rsa != NULL) {
++ BIGNUM *e = BN_new ();
++ if (e != NULL && BN_set_word (e, RSA_F4)
++ && RSA_generate_key_ex (rsa, 2048, e, NULL)) {
++ RSA_free (rsa);
++ rsa = NULL;
++ }
++ BN_free (e);
++ }
++#endif
+
+ if (!rsa) {
+ GST_WARNING_OBJECT (self, "failed to generate RSA");
+diff --git a/ext/dtls/gstdtlsconnection.c b/ext/dtls/gstdtlsconnection.c
+index 36f6d63..728f5a7 100644
+--- a/ext/dtls/gstdtlsconnection.c
++++ b/ext/dtls/gstdtlsconnection.c
+@@ -42,6 +42,8 @@
+ #include <openssl/err.h>
+ #include <openssl/ssl.h>
+
++#include <string.h>
++
+ GST_DEBUG_CATEGORY_STATIC (gst_dtls_connection_debug);
+ #define GST_CAT_DEFAULT gst_dtls_connection_debug
+ G_DEFINE_TYPE_WITH_CODE (GstDtlsConnection, gst_dtls_connection, G_TYPE_OBJECT,
+@@ -216,6 +218,38 @@ gst_dtls_connection_finalize (GObject * gobject)
+ G_OBJECT_CLASS (gst_dtls_connection_parent_class)->finalize (gobject);
+ }
+
++#if OPENSSL_VERSION_NUMBER < 0x10100001L
++static void
++BIO_set_data (BIO * bio, void *ptr)
++{
++ bio->ptr = ptr;
++}
++
++static void *
++BIO_get_data (BIO * bio)
++{
++ return bio->ptr;
++}
++
++static void
++BIO_set_shutdown (BIO * bio, int shutdown)
++{
++ bio->shutdown = shutdown;
++}
++
++static void
++BIO_set_init (BIO * bio, int init)
++{
++ bio->init = init;
++}
++
++static X509 *
++X509_STORE_CTX_get0_cert (X509_STORE_CTX * ctx)
++{
++ return ctx->cert;
++}
++#endif
++
+ static void
+ gst_dtls_connection_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+@@ -239,7 +273,7 @@ gst_dtls_connection_set_property (GObject * object, guint prop_id,
+ priv->bio = BIO_new (BIO_s_gst_dtls_connection ());
+ g_return_if_fail (priv->bio);
+
+- priv->bio->ptr = self;
++ BIO_set_data (priv->bio, self);
+ SSL_set_bio (priv->ssl, priv->bio, priv->bio);
+
+ SSL_set_verify (priv->ssl,
+@@ -573,6 +607,7 @@ log_state (GstDtlsConnection * self, const gchar * str)
+ states |= (! !SSL_want_write (priv->ssl) << 20);
+ states |= (! !SSL_want_read (priv->ssl) << 24);
+
++#if OPENSSL_VERSION_NUMBER < 0x10100001L
+ GST_LOG_OBJECT (self, "%s: role=%s buf=(%d,%p:%d/%d) %x|%x %s",
+ str,
+ priv->is_client ? "client" : "server",
+@@ -581,6 +616,15 @@ log_state (GstDtlsConnection * self, const gchar * str)
+ priv->bio_buffer_offset,
+ priv->bio_buffer_len,
+ states, SSL_get_state (priv->ssl), SSL_state_string_long (priv->ssl));
++#else
++ GST_LOG_OBJECT (self, "%s: role=%s buf=(%p:%d/%d) %x|%x %s",
++ str,
++ priv->is_client ? "client" : "server",
++ priv->bio_buffer,
++ priv->bio_buffer_offset,
++ priv->bio_buffer_len,
++ states, SSL_get_state (priv->ssl), SSL_state_string_long (priv->ssl));
++#endif
+ }
+
+ static void
+@@ -737,7 +781,7 @@ openssl_verify_callback (int preverify_ok, X509_STORE_CTX * x509_ctx)
+ self = SSL_get_ex_data (ssl, connection_ex_index);
+ g_return_val_if_fail (GST_IS_DTLS_CONNECTION (self), FALSE);
+
+- pem = _gst_dtls_x509_to_pem (x509_ctx->cert);
++ pem = _gst_dtls_x509_to_pem (X509_STORE_CTX_get0_cert (x509_ctx));
+
+ if (!pem) {
+ GST_WARNING_OBJECT (self,
+@@ -749,7 +793,8 @@ openssl_verify_callback (int preverify_ok, X509_STORE_CTX * x509_ctx)
+ gint len;
+
+ len =
+- X509_NAME_print_ex (bio, X509_get_subject_name (x509_ctx->cert), 1,
++ X509_NAME_print_ex (bio,
++ X509_get_subject_name (X509_STORE_CTX_get0_cert (x509_ctx)), 1,
+ XN_FLAG_MULTILINE);
+ BIO_read (bio, buffer, len);
+ buffer[len] = '\0';
+@@ -777,6 +822,7 @@ openssl_verify_callback (int preverify_ok, X509_STORE_CTX * x509_ctx)
+ ######## #### #######
+ */
+
++#if OPENSSL_VERSION_NUMBER < 0x10100001L
+ static BIO_METHOD custom_bio_methods = {
+ BIO_TYPE_BIO,
+ "stream",
+@@ -795,11 +841,34 @@ BIO_s_gst_dtls_connection (void)
+ {
+ return &custom_bio_methods;
+ }
++#else
++static BIO_METHOD *custom_bio_methods;
++
++static BIO_METHOD *
++BIO_s_gst_dtls_connection (void)
++{
++ if (custom_bio_methods != NULL)
++ return custom_bio_methods;
++
++ custom_bio_methods = BIO_meth_new (BIO_TYPE_BIO, "stream");
++ if (custom_bio_methods == NULL
++ || !BIO_meth_set_write (custom_bio_methods, bio_method_write)
++ || !BIO_meth_set_read (custom_bio_methods, bio_method_read)
++ || !BIO_meth_set_ctrl (custom_bio_methods, bio_method_ctrl)
++ || !BIO_meth_set_create (custom_bio_methods, bio_method_new)
++ || !BIO_meth_set_destroy (custom_bio_methods, bio_method_free)) {
++ BIO_meth_free (custom_bio_methods);
++ return NULL;
++ }
++
++ return custom_bio_methods;
++}
++#endif
+
+ static int
+ bio_method_write (BIO * bio, const char *data, int size)
+ {
+- GstDtlsConnection *self = GST_DTLS_CONNECTION (bio->ptr);
++ GstDtlsConnection *self = GST_DTLS_CONNECTION (BIO_get_data (bio));
+
+ GST_LOG_OBJECT (self, "BIO: writing %d", size);
+
+@@ -824,7 +893,7 @@ bio_method_write (BIO * bio, const char *data, int size)
+ static int
+ bio_method_read (BIO * bio, char *out_buffer, int size)
+ {
+- GstDtlsConnection *self = GST_DTLS_CONNECTION (bio->ptr);
++ GstDtlsConnection *self = GST_DTLS_CONNECTION (BIO_get_data (bio));
+ GstDtlsConnectionPrivate *priv = self->priv;
+ guint internal_size;
+ gint copy_size;
+@@ -868,7 +937,7 @@ bio_method_read (BIO * bio, char *out_buffer, int size)
+ static long
+ bio_method_ctrl (BIO * bio, int cmd, long arg1, void *arg2)
+ {
+- GstDtlsConnection *self = GST_DTLS_CONNECTION (bio->ptr);
++ GstDtlsConnection *self = GST_DTLS_CONNECTION (BIO_get_data (bio));
+ GstDtlsConnectionPrivate *priv = self->priv;
+
+ switch (cmd) {
+@@ -916,8 +985,8 @@ bio_method_new (BIO * bio)
+ {
+ GST_LOG_OBJECT (NULL, "BIO: new");
+
+- bio->shutdown = 0;
+- bio->init = 1;
++ BIO_set_shutdown (bio, 0);
++ BIO_set_init (bio, 1);
+
+ return 1;
+ }
+@@ -930,6 +999,6 @@ bio_method_free (BIO * bio)
+ return 0;
+ }
+
+- GST_LOG_OBJECT (GST_DTLS_CONNECTION (bio->ptr), "BIO free");
++ GST_LOG_OBJECT (GST_DTLS_CONNECTION (BIO_get_data (bio)), "BIO free");
+ return 0;
+ }
+--
+2.10.2
+
diff --git a/Tools/gtk/patches/gst-plugins-bad-0002-dtlscertificate-Fix-error-checking-in-RSA_generate_k.patch b/Tools/gtk/patches/gst-plugins-bad-0002-dtlscertificate-Fix-error-checking-in-RSA_generate_k.patch
new file mode 100644
index 000000000..c66877370
--- /dev/null
+++ b/Tools/gtk/patches/gst-plugins-bad-0002-dtlscertificate-Fix-error-checking-in-RSA_generate_k.patch
@@ -0,0 +1,37 @@
+From 3a069193e25364ebdacac86f4b03022c151ea29c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= <sebastian@centricular.com>
+Date: Mon, 14 Nov 2016 11:32:17 +0200
+Subject: [PATCH] dtlscertificate: Fix error checking in RSA_generate_key_ex()
+ usage
+
+Was broken during the port for OpenSSL 1.1.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=774328
+---
+ ext/dtls/gstdtlscertificate.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/ext/dtls/gstdtlscertificate.c b/ext/dtls/gstdtlscertificate.c
+index c1c9602..c2d9bb2 100644
+--- a/ext/dtls/gstdtlscertificate.c
++++ b/ext/dtls/gstdtlscertificate.c
+@@ -207,12 +207,13 @@ init_generated (GstDtlsCertificate * self)
+ rsa = RSA_new ();
+ if (rsa != NULL) {
+ BIGNUM *e = BN_new ();
+- if (e != NULL && BN_set_word (e, RSA_F4)
+- && RSA_generate_key_ex (rsa, 2048, e, NULL)) {
++ if (e == NULL || !BN_set_word (e, RSA_F4)
++ || !RSA_generate_key_ex (rsa, 2048, e, NULL)) {
+ RSA_free (rsa);
+ rsa = NULL;
+ }
+- BN_free (e);
++ if (e)
++ BN_free (e);
+ }
+ #endif
+
+--
+2.10.2
+
diff --git a/Tools/gtk/patches/gst-plugins-good-0001-rtpbin-pipeline-gets-an-EOS-when-any-rtpsources-byes.patch b/Tools/gtk/patches/gst-plugins-good-0001-rtpbin-pipeline-gets-an-EOS-when-any-rtpsources-byes.patch
new file mode 100644
index 000000000..f0f90d104
--- /dev/null
+++ b/Tools/gtk/patches/gst-plugins-good-0001-rtpbin-pipeline-gets-an-EOS-when-any-rtpsources-byes.patch
@@ -0,0 +1,156 @@
+From eeea2a7fe88a17b15318d5b6ae6e190b2f777030 Mon Sep 17 00:00:00 2001
+From: "Alejandro G. Castro" <alex@igalia.com>
+Date: Wed, 26 Oct 2016 13:21:29 +0200
+Subject: [PATCH] rtpbin: pipeline gets an EOS when any rtpsources byes
+
+Instead of sending EOS when a source byes we have to wait for
+all the sources to be gone, which means they already sent BYE and
+were removed from the session. We now handle the EOS in the rtcp
+loop checking the amount of sources in the session.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=773218
+---
+ gst/rtpmanager/gstrtpsession.c | 29 +++++++++++++++++++----------
+ gst/rtpmanager/rtpsession.c | 6 +-----
+ gst/rtpmanager/rtpsession.h | 3 +--
+ 3 files changed, 21 insertions(+), 17 deletions(-)
+
+diff --git a/gst/rtpmanager/gstrtpsession.c b/gst/rtpmanager/gstrtpsession.c
+index 3688e85..fd1f2b1 100644
+--- a/gst/rtpmanager/gstrtpsession.c
++++ b/gst/rtpmanager/gstrtpsession.c
+@@ -293,7 +293,7 @@ static GstFlowReturn gst_rtp_session_process_rtp (RTPSession * sess,
+ static GstFlowReturn gst_rtp_session_send_rtp (RTPSession * sess,
+ RTPSource * src, gpointer data, gpointer user_data);
+ static GstFlowReturn gst_rtp_session_send_rtcp (RTPSession * sess,
+- RTPSource * src, GstBuffer * buffer, gboolean eos, gpointer user_data);
++ RTPSource * src, GstBuffer * buffer, gpointer user_data);
+ static GstFlowReturn gst_rtp_session_sync_rtcp (RTPSession * sess,
+ GstBuffer * buffer, gpointer user_data);
+ static gint gst_rtp_session_clock_rate (RTPSession * sess, guint8 payload,
+@@ -1156,6 +1156,22 @@ rtcp_thread (GstRtpSession * rtpsession)
+ GST_RTP_SESSION_UNLOCK (rtpsession);
+ rtp_session_on_timeout (session, current_time, ntpnstime, running_time);
+ GST_RTP_SESSION_LOCK (rtpsession);
++
++ if (!rtp_session_get_num_sources (session)) {
++ /* when no sources left in the session, all of the them have went
++ * BYE at some point and removed, we can send EOS to the
++ * pipeline. */
++ GstPad *rtcp_src = rtpsession->send_rtcp_src;
++
++ if (rtcp_src) {
++ gst_object_ref (rtcp_src);
++ GST_LOG_OBJECT (rtpsession, "sending EOS");
++ GST_RTP_SESSION_UNLOCK (rtpsession);
++ gst_pad_push_event (rtpsession->send_rtcp_src, gst_event_new_eos ());
++ GST_RTP_SESSION_LOCK (rtpsession);
++ gst_object_unref (rtcp_src);
++ }
++ }
+ }
+ /* mark the thread as stopped now */
+ rtpsession->priv->thread_stopped = TRUE;
+@@ -1413,11 +1429,10 @@ do_rtcp_events (GstRtpSession * rtpsession, GstPad * srcpad)
+ }
+
+ /* called when the session manager has an RTCP packet ready for further
+- * sending. The eos flag is set when an EOS event should be sent downstream as
+- * well. */
++ * sending. */
+ static GstFlowReturn
+ gst_rtp_session_send_rtcp (RTPSession * sess, RTPSource * src,
+- GstBuffer * buffer, gboolean eos, gpointer user_data)
++ GstBuffer * buffer, gpointer user_data)
+ {
+ GstFlowReturn result;
+ GstRtpSession *rtpsession;
+@@ -1440,11 +1455,6 @@ gst_rtp_session_send_rtcp (RTPSession * sess, RTPSource * src,
+ GST_LOG_OBJECT (rtpsession, "sending RTCP");
+ result = gst_pad_push (rtcp_src, buffer);
+
+- /* we have to send EOS after this packet */
+- if (eos) {
+- GST_LOG_OBJECT (rtpsession, "sending EOS");
+- gst_pad_push_event (rtcp_src, gst_event_new_eos ());
+- }
+ gst_object_unref (rtcp_src);
+ } else {
+ GST_RTP_SESSION_UNLOCK (rtpsession);
+@@ -2056,7 +2066,6 @@ gst_rtp_session_event_send_rtcp_src (GstPad * pad, GstObject * parent,
+ return ret;
+ }
+
+-
+ static gboolean
+ gst_rtp_session_event_send_rtp_sink (GstPad * pad, GstObject * parent,
+ GstEvent * event)
+diff --git a/gst/rtpmanager/rtpsession.c b/gst/rtpmanager/rtpsession.c
+index 8b33b6b..aa8b40b 100644
+--- a/gst/rtpmanager/rtpsession.c
++++ b/gst/rtpmanager/rtpsession.c
+@@ -3263,7 +3263,6 @@ early_exit:
+ typedef struct
+ {
+ RTPSource *source;
+- gboolean is_bye;
+ GstBuffer *buffer;
+ } ReportOutput;
+
+@@ -3874,7 +3873,6 @@ static void
+ generate_rtcp (const gchar * key, RTPSource * source, ReportData * data)
+ {
+ RTPSession *sess = data->sess;
+- gboolean is_bye = FALSE;
+ ReportOutput *output;
+
+ /* only generate RTCP for active internal sources */
+@@ -3893,7 +3891,6 @@ generate_rtcp (const gchar * key, RTPSource * source, ReportData * data)
+ if (source->marked_bye) {
+ /* send BYE */
+ make_source_bye (sess, source, data);
+- is_bye = TRUE;
+ } else if (!data->is_early) {
+ /* loop over all known sources and add report blocks. If we are early, we
+ * just make a minimal RTCP packet and skip this step */
+@@ -3918,7 +3915,6 @@ generate_rtcp (const gchar * key, RTPSource * source, ReportData * data)
+
+ output = g_slice_new (ReportOutput);
+ output->source = g_object_ref (source);
+- output->is_bye = is_bye;
+ output->buffer = data->rtcp;
+ /* queue the RTCP packet to push later */
+ g_queue_push_tail (&data->output, output);
+@@ -4098,7 +4094,7 @@ done:
+ GST_DEBUG ("%p, sending RTCP packet, avg size %u, %u", &sess->stats,
+ sess->stats.avg_rtcp_packet_size, packet_size);
+ result =
+- sess->callbacks.send_rtcp (sess, source, buffer, output->is_bye,
++ sess->callbacks.send_rtcp (sess, source, buffer,
+ sess->send_rtcp_user_data);
+
+ RTP_SESSION_LOCK (sess);
+diff --git a/gst/rtpmanager/rtpsession.h b/gst/rtpmanager/rtpsession.h
+index 9fa9327..c25981a 100644
+--- a/gst/rtpmanager/rtpsession.h
++++ b/gst/rtpmanager/rtpsession.h
+@@ -71,7 +71,6 @@ typedef GstFlowReturn (*RTPSessionSendRTP) (RTPSession *sess, RTPSource *src, gp
+ * @sess: an #RTPSession
+ * @src: the #RTPSource
+ * @buffer: the RTCP buffer ready for sending
+- * @eos: if an EOS event should be pushed
+ * @user_data: user data specified when registering
+ *
+ * This callback will be called when @sess has @buffer ready for sending to
+@@ -80,7 +79,7 @@ typedef GstFlowReturn (*RTPSessionSendRTP) (RTPSession *sess, RTPSource *src, gp
+ * Returns: a #GstFlowReturn.
+ */
+ typedef GstFlowReturn (*RTPSessionSendRTCP) (RTPSession *sess, RTPSource *src, GstBuffer *buffer,
+- gboolean eos, gpointer user_data);
++ gpointer user_data);
+
+ /**
+ * RTPSessionSyncRTCP:
+--
+2.10.2
+
diff --git a/Tools/gtk/patches/gst-plugins-good-0002-rtpbin-avoid-generating-errors-when-rtcp-messages-ar.patch b/Tools/gtk/patches/gst-plugins-good-0002-rtpbin-avoid-generating-errors-when-rtcp-messages-ar.patch
new file mode 100644
index 000000000..aad048300
--- /dev/null
+++ b/Tools/gtk/patches/gst-plugins-good-0002-rtpbin-avoid-generating-errors-when-rtcp-messages-ar.patch
@@ -0,0 +1,61 @@
+From dab6c473c3e1b2b400ee18afc70140c2f842debf Mon Sep 17 00:00:00 2001
+From: "Alejandro G. Castro" <alex@igalia.com>
+Date: Thu, 20 Oct 2016 13:14:13 +0200
+Subject: [PATCH] rtpbin: avoid generating errors when rtcp messages are empty
+ and check the queue is not empty
+
+Add a check to verify all the output buffers were empty for the
+session in a timout and log an error.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=773269
+---
+ gst/rtpmanager/rtpsession.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/gst/rtpmanager/rtpsession.c b/gst/rtpmanager/rtpsession.c
+index 75908c0..f1d9210 100644
+--- a/gst/rtpmanager/rtpsession.c
++++ b/gst/rtpmanager/rtpsession.c
+@@ -3923,6 +3923,7 @@ rtp_session_on_timeout (RTPSession * sess, GstClockTime current_time,
+ ReportData data = { GST_RTCP_BUFFER_INIT };
+ GHashTable *table_copy;
+ ReportOutput *output;
++ gboolean all_empty = FALSE;
+
+ g_return_val_if_fail (RTP_IS_SESSION (sess), GST_FLOW_ERROR);
+
+@@ -3989,6 +3990,9 @@ rtp_session_on_timeout (RTPSession * sess, GstClockTime current_time,
+ if (!is_rtcp_time (sess, current_time, &data))
+ goto done;
+
++ /* check if all the buffers are empty afer generation */
++ all_empty = TRUE;
++
+ GST_DEBUG
+ ("doing RTCP generation %u for %u sources, early %d, may suppress %d",
+ sess->generation, data.num_to_report, data.is_early, data.may_suppress);
+@@ -4036,8 +4040,8 @@ done:
+
+ empty_buffer = gst_buffer_get_size (buffer) == 0;
+
+- if (empty_buffer)
+- g_warning ("rtpsession: Trying to send an empty RTCP packet");
++ if (!empty_buffer)
++ all_empty = FALSE;
+
+ if (sess->callbacks.send_rtcp &&
+ !empty_buffer && (do_not_suppress || !data.may_suppress)) {
+@@ -4068,6 +4072,10 @@ done:
+ g_object_unref (source);
+ g_slice_free (ReportOutput, output);
+ }
++
++ if (all_empty)
++ GST_ERROR ("generated empty RTCP messages for all the sources");
++
+ return result;
+ }
+
+--
+2.10.2
+
diff --git a/Tools/gtk/patches/gst-plugins-good-0003-rtpbin-receive-bundle-support.patch b/Tools/gtk/patches/gst-plugins-good-0003-rtpbin-receive-bundle-support.patch
new file mode 100644
index 000000000..ff89c8199
--- /dev/null
+++ b/Tools/gtk/patches/gst-plugins-good-0003-rtpbin-receive-bundle-support.patch
@@ -0,0 +1,1018 @@
+From dcd3ce9751cdef0b5ab1fa118355f92bdfe82cb3 Mon Sep 17 00:00:00 2001
+From: Philippe Normand <philn@igalia.com>
+Date: Wed, 16 Nov 2016 08:56:34 +0100
+Subject: [PATCH] rtpbin: receive bundle support
+
+A new signal named on-bundled-ssrc is provided and can be
+used by the application to redirect a stream to a different
+GstRtpSession or to keep the RTX stream grouped within the
+GstRtpSession of the same media type.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=772740
+---
+ docs/plugins/gst-plugins-good-plugins.signals | 8 +
+ gst/rtpmanager/gstrtpbin.c | 562 ++++++++++++++++++--------
+ gst/rtpmanager/gstrtpbin.h | 2 +
+ tests/check/Makefile.am | 4 +
+ tests/check/elements/.gitignore | 1 +
+ tests/check/elements/rtpbundle.c | 390 ++++++++++++++++++
+ tests/check/meson.build | 1 +
+ tests/examples/rtp/.gitignore | 2 +
+ tests/examples/rtp/Makefile.am | 10 +-
+ tests/examples/rtp/client-rtpbundle.c | 266 ++++++++++++
+ tests/examples/rtp/server-rtpbundle.c | 179 ++++++++
+ 11 files changed, 1265 insertions(+), 160 deletions(-)
+ create mode 100644 tests/check/elements/rtpbundle.c
+ create mode 100644 tests/examples/rtp/client-rtpbundle.c
+ create mode 100644 tests/examples/rtp/server-rtpbundle.c
+
+diff --git a/docs/plugins/gst-plugins-good-plugins.signals b/docs/plugins/gst-plugins-good-plugins.signals
+index 3db17e9..44bbdda 100644
+--- a/docs/plugins/gst-plugins-good-plugins.signals
++++ b/docs/plugins/gst-plugins-good-plugins.signals
+@@ -375,6 +375,14 @@ guint arg1
+ </SIGNAL>
+
+ <SIGNAL>
++<NAME>GstRtpBin::on-bundled-ssrc</NAME>
++<RETURNS>guint</RETURNS>
++<FLAGS>l</FLAGS>
++GstRtpBin *gstrtpbin
++guint arg1
++</SIGNAL>
++
++<SIGNAL>
+ <NAME>GstRtpJitterBuffer::clear-pt-map</NAME>
+ <RETURNS>void</RETURNS>
+ <FLAGS>la</FLAGS>
+diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c
+index 648adb9..f58de01 100644
+--- a/gst/rtpmanager/gstrtpbin.c
++++ b/gst/rtpmanager/gstrtpbin.c
+@@ -53,6 +53,13 @@
+ * SSRC in the RTP packets to its own SSRC and wil forward the packets on the
+ * send_rtp_src_\%u pad after updating its internal state.
+ *
++ * #GstRtpBin can also demultiplex incoming bundled streams. The first
++ * #GstRtpSession will have a #GstRtpSsrcDemux element splitting the streams
++ * based on their SSRC and potentially dispatched to a different #GstRtpSession.
++ * Because retransmission SSRCs need to be merged with the corresponding media
++ * stream the #GstRtpBin::on-bundled-ssrc signal is emitted so that the
++ * application can find out to which session the SSRC belongs.
++ *
+ * The session manager needs the clock-rate of the payload types it is handling
+ * and will signal the #GstRtpSession::request-pt-map signal when it needs such a
+ * mapping. One can clear the cached values with the #GstRtpSession::clear-pt-map
+@@ -276,6 +283,8 @@ enum
+ SIGNAL_ON_NEW_SENDER_SSRC,
+ SIGNAL_ON_SENDER_SSRC_ACTIVE,
+
++ SIGNAL_ON_BUNDLED_SSRC,
++
+ LAST_SIGNAL
+ };
+
+@@ -362,6 +371,14 @@ static void remove_send_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session);
+ static void remove_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session);
+ static void free_client (GstRtpBinClient * client, GstRtpBin * bin);
+ static void free_stream (GstRtpBinStream * stream, GstRtpBin * bin);
++static GstRtpBinSession *create_session (GstRtpBin * rtpbin, gint id);
++static GstPad *complete_session_sink (GstRtpBin * rtpbin,
++ GstRtpBinSession * session, gboolean bundle_demuxer_needed);
++static void
++complete_session_receiver (GstRtpBin * rtpbin, GstRtpBinSession * session,
++ guint sessid);
++static GstPad *complete_session_rtcp (GstRtpBin * rtpbin,
++ GstRtpBinSession * session, guint sessid, gboolean bundle_demuxer_needed);
+
+ /* Manages the RTP stream for one SSRC.
+ *
+@@ -428,6 +445,12 @@ struct _GstRtpBinSession
+ gulong demux_newpad_sig;
+ gulong demux_padremoved_sig;
+
++ /* Bundling support */
++ GstElement *rtp_funnel;
++ GstElement *rtcp_funnel;
++ GstElement *bundle_demux;
++ gulong bundle_demux_newpad_sig;
++
+ GMutex lock;
+
+ /* list of GstRtpBinStream */
+@@ -629,6 +652,96 @@ ssrc_demux_pad_removed (GstElement * element, guint ssrc, GstPad * pad,
+ GST_RTP_BIN_UNLOCK (rtpbin);
+ }
+
++static void
++new_bundled_ssrc_pad_found (GstElement * element, guint ssrc, GstPad * pad,
++ GstRtpBinSession * session)
++{
++ GValue result = G_VALUE_INIT;
++ GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT };
++ guint session_id = 0;
++ GstRtpBinSession *target_session = NULL;
++ GstRtpBin *rtpbin = session->bin;
++ gchar *name;
++ GstPad *src_pad;
++ GstPad *recv_rtp_sink = NULL;
++ GstPad *recv_rtcp_sink = NULL;
++ GstPadLinkReturn ret;
++
++ GST_RTP_BIN_DYN_LOCK (rtpbin);
++ GST_DEBUG_OBJECT (rtpbin, "new bundled SSRC pad %08x, %s:%s", ssrc,
++ GST_DEBUG_PAD_NAME (pad));
++
++ g_value_init (&result, G_TYPE_UINT);
++ g_value_init (&params[0], GST_TYPE_ELEMENT);
++ g_value_set_object (&params[0], rtpbin);
++ g_value_init (&params[1], G_TYPE_UINT);
++ g_value_set_uint (&params[1], ssrc);
++
++ g_signal_emitv (params,
++ gst_rtp_bin_signals[SIGNAL_ON_BUNDLED_SSRC], 0, &result);
++ g_value_unset (&params[0]);
++
++ session_id = g_value_get_uint (&result);
++ if (session_id == 0) {
++ target_session = session;
++ } else {
++ target_session = find_session_by_id (rtpbin, (gint) session_id);
++ if (!target_session) {
++ target_session = create_session (rtpbin, session_id);
++ }
++ if (!target_session->recv_rtp_sink) {
++ recv_rtp_sink = complete_session_sink (rtpbin, target_session, FALSE);
++ }
++
++ if (!target_session->recv_rtp_src)
++ complete_session_receiver (rtpbin, target_session, session_id);
++
++ if (!target_session->recv_rtcp_sink) {
++ recv_rtcp_sink =
++ complete_session_rtcp (rtpbin, target_session, session_id, FALSE);
++ }
++ }
++
++ GST_DEBUG_OBJECT (rtpbin, "Assigning bundled ssrc %u to session %u", ssrc,
++ session_id);
++
++ if (!recv_rtp_sink) {
++ recv_rtp_sink =
++ gst_element_get_request_pad (target_session->rtp_funnel, "sink_%u");
++ }
++
++ if (!recv_rtcp_sink) {
++ recv_rtcp_sink =
++ gst_element_get_request_pad (target_session->rtcp_funnel, "sink_%u");
++ }
++
++ name = g_strdup_printf ("src_%u", ssrc);
++ src_pad = gst_element_get_static_pad (element, name);
++ ret = gst_pad_link (src_pad, recv_rtp_sink);
++ g_free (name);
++ gst_object_unref (src_pad);
++ gst_object_unref (recv_rtp_sink);
++ if (ret != GST_PAD_LINK_OK) {
++ g_warning
++ ("rtpbin: failed to link bundle demuxer to receive rtp funnel for session %u",
++ session_id);
++ }
++
++ name = g_strdup_printf ("rtcp_src_%u", ssrc);
++ src_pad = gst_element_get_static_pad (element, name);
++ gst_pad_link (src_pad, recv_rtcp_sink);
++ g_free (name);
++ gst_object_unref (src_pad);
++ gst_object_unref (recv_rtcp_sink);
++ if (ret != GST_PAD_LINK_OK) {
++ g_warning
++ ("rtpbin: failed to link bundle demuxer to receive rtcp sink pad for session %u",
++ session_id);
++ }
++
++ GST_RTP_BIN_DYN_UNLOCK (rtpbin);
++}
++
+ /* create a session with the given id. Must be called with RTP_BIN_LOCK */
+ static GstRtpBinSession *
+ create_session (GstRtpBin * rtpbin, gint id)
+@@ -649,6 +762,10 @@ create_session (GstRtpBin * rtpbin, gint id)
+ sess->bin = rtpbin;
+ sess->session = session;
+ sess->demux = demux;
++
++ sess->rtp_funnel = gst_element_factory_make ("funnel", NULL);
++ sess->rtcp_funnel = gst_element_factory_make ("funnel", NULL);
++
+ sess->ptmap = g_hash_table_new_full (NULL, NULL, NULL,
+ (GDestroyNotify) gst_caps_unref);
+ rtpbin->sessions = g_slist_prepend (rtpbin->sessions, sess);
+@@ -696,6 +813,8 @@ create_session (GstRtpBin * rtpbin, gint id)
+
+ gst_bin_add (GST_BIN_CAST (rtpbin), session);
+ gst_bin_add (GST_BIN_CAST (rtpbin), demux);
++ gst_bin_add (GST_BIN_CAST (rtpbin), sess->rtp_funnel);
++ gst_bin_add (GST_BIN_CAST (rtpbin), sess->rtcp_funnel);
+
+ GST_OBJECT_LOCK (rtpbin);
+ target = GST_STATE_TARGET (rtpbin);
+@@ -704,6 +823,8 @@ create_session (GstRtpBin * rtpbin, gint id)
+ /* change state only to what's needed */
+ gst_element_set_state (demux, target);
+ gst_element_set_state (session, target);
++ gst_element_set_state (sess->rtp_funnel, target);
++ gst_element_set_state (sess->rtcp_funnel, target);
+
+ return sess;
+
+@@ -807,7 +928,7 @@ get_pt_map (GstRtpBinSession * session, guint pt)
+ GValue ret = { 0 };
+ GValue args[3] = { {0}, {0}, {0} };
+
+- GST_DEBUG ("searching pt %d in cache", pt);
++ GST_DEBUG ("searching pt %u in cache", pt);
+
+ GST_RTP_SESSION_LOCK (session);
+
+@@ -820,7 +941,7 @@ get_pt_map (GstRtpBinSession * session, guint pt)
+
+ bin = session->bin;
+
+- GST_DEBUG ("emiting signal for pt %d in session %d", pt, session->id);
++ GST_DEBUG ("emiting signal for pt %u in session %u", pt, session->id);
+
+ /* not in cache, send signal to request caps */
+ g_value_init (&args[0], GST_TYPE_ELEMENT);
+@@ -856,7 +977,7 @@ get_pt_map (GstRtpBinSession * session, guint pt)
+ if (!caps)
+ goto no_caps;
+
+- GST_DEBUG ("caching pt %d as %" GST_PTR_FORMAT, pt, caps);
++ GST_DEBUG ("caching pt %u as %" GST_PTR_FORMAT, pt, caps);
+
+ /* store in cache, take additional ref */
+ g_hash_table_insert (session->ptmap, GINT_TO_POINTER (pt),
+@@ -947,7 +1068,7 @@ gst_rtp_bin_get_session (GstRtpBin * bin, guint session_id)
+ GstElement *ret = NULL;
+
+ GST_RTP_BIN_LOCK (bin);
+- GST_DEBUG_OBJECT (bin, "retrieving GstRtpSession, index: %d", session_id);
++ GST_DEBUG_OBJECT (bin, "retrieving GstRtpSession, index: %u", session_id);
+ session = find_session_by_id (bin, (gint) session_id);
+ if (session) {
+ ret = gst_object_ref (session->session);
+@@ -964,7 +1085,7 @@ gst_rtp_bin_get_internal_session (GstRtpBin * bin, guint session_id)
+ GstRtpBinSession *session;
+
+ GST_RTP_BIN_LOCK (bin);
+- GST_DEBUG_OBJECT (bin, "retrieving internal RTPSession object, index: %d",
++ GST_DEBUG_OBJECT (bin, "retrieving internal RTPSession object, index: %u",
+ session_id);
+ session = find_session_by_id (bin, (gint) session_id);
+ if (session) {
+@@ -2194,6 +2315,29 @@ gst_rtp_bin_class_init (GstRtpBinClass * klass)
+ on_sender_ssrc_active), NULL, NULL, g_cclosure_marshal_generic,
+ G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
+
++
++ /**
++ * GstRtpBin::on-bundled-ssrc:
++ * @rtpbin: the object which received the signal
++ * @ssrc: the bundled SSRC
++ *
++ * Notify of a new incoming bundled SSRC. If no handler is connected to the
++ * signal then the #GstRtpSession created for the recv_rtp_sink_\%u
++ * request pad will be managing this new SSRC. However if there is a handler
++ * connected then the application can decided to dispatch this new stream to
++ * another session by providing its ID as return value of the handler. This
++ * can be particularly useful to keep retransmission SSRCs grouped with the
++ * session for which they handle retransmission.
++ *
++ * Since: 1.12
++ */
++ gst_rtp_bin_signals[SIGNAL_ON_BUNDLED_SSRC] =
++ g_signal_new ("on-bundled-ssrc", G_TYPE_FROM_CLASS (klass),
++ G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass,
++ on_bundled_ssrc), NULL, NULL,
++ g_cclosure_marshal_generic, G_TYPE_UINT, 1, G_TYPE_UINT);
++
++
+ g_object_class_install_property (gobject_class, PROP_SDES,
+ g_param_spec_boxed ("sdes", "SDES",
+ "The SDES items of this session",
+@@ -3021,7 +3165,7 @@ new_payload_found (GstElement * element, guint pt, GstPad * pad,
+
+ rtpbin = stream->bin;
+
+- GST_DEBUG ("new payload pad %d", pt);
++ GST_DEBUG_OBJECT (rtpbin, "new payload pad %u", pt);
+
+ GST_RTP_BIN_SHUTDOWN_LOCK (rtpbin, shutdown);
+
+@@ -3078,7 +3222,7 @@ pt_map_requested (GstElement * element, guint pt, GstRtpBinSession * session)
+
+ rtpbin = session->bin;
+
+- GST_DEBUG_OBJECT (rtpbin, "payload map requested for pt %d in session %d", pt,
++ GST_DEBUG_OBJECT (rtpbin, "payload map requested for pt %u in session %u", pt,
+ session->id);
+
+ caps = get_pt_map (session, pt);
+@@ -3099,7 +3243,7 @@ static void
+ payload_type_change (GstElement * element, guint pt, GstRtpBinSession * session)
+ {
+ GST_DEBUG_OBJECT (session->bin,
+- "emiting signal for pt type changed to %d in session %d", pt,
++ "emiting signal for pt type changed to %u in session %u", pt,
+ session->id);
+
+ g_signal_emit (session->bin, gst_rtp_bin_signals[SIGNAL_PAYLOAD_TYPE_CHANGE],
+@@ -3246,15 +3390,42 @@ no_stream:
+ }
+ }
+
+-static gboolean
+-complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session)
++static void
++session_maybe_create_bundle_demuxer (GstRtpBinSession * session)
++{
++ GstRtpBin *rtpbin;
++
++ if (session->bundle_demux)
++ return;
++
++ rtpbin = session->bin;
++ if (g_signal_has_handler_pending (rtpbin,
++ gst_rtp_bin_signals[SIGNAL_ON_BUNDLED_SSRC], 0, TRUE)) {
++ GST_DEBUG_OBJECT (rtpbin, "Adding a bundle SSRC demuxer to session %u",
++ session->id);
++ session->bundle_demux = gst_element_factory_make ("rtpssrcdemux", NULL);
++ session->bundle_demux_newpad_sig = g_signal_connect (session->bundle_demux,
++ "new-ssrc-pad", (GCallback) new_bundled_ssrc_pad_found, session);
++
++ gst_bin_add (GST_BIN_CAST (rtpbin), session->bundle_demux);
++ gst_element_sync_state_with_parent (session->bundle_demux);
++ } else {
++ GST_DEBUG_OBJECT (rtpbin,
++ "No handler for the on-bundled-ssrc signal so no need for a bundle SSRC demuxer in session %u",
++ session->id);
++ }
++}
++
++static GstPad *
++complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session,
++ gboolean bundle_demuxer_needed)
+ {
+- gchar *gname;
+ guint sessid = session->id;
+ GstPad *recv_rtp_sink;
++ GstPad *funnel_src;
+ GstElement *decoder;
+- GstElementClass *klass;
+- GstPadTemplate *templ;
++
++ g_assert (!session->recv_rtp_sink);
+
+ /* get recv_rtp pad and store */
+ session->recv_rtp_sink =
+@@ -3265,6 +3436,9 @@ complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session)
+ g_signal_connect (session->recv_rtp_sink, "notify::caps",
+ (GCallback) caps_changed, session);
+
++ if (bundle_demuxer_needed)
++ session_maybe_create_bundle_demuxer (session);
++
+ GST_DEBUG_OBJECT (rtpbin, "requesting RTP decoder");
+ decoder = session_request_element (session, SIGNAL_REQUEST_RTP_DECODER);
+ if (decoder) {
+@@ -3282,7 +3456,14 @@ complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session)
+ if (decsrc == NULL)
+ goto dec_src_failed;
+
+- ret = gst_pad_link (decsrc, session->recv_rtp_sink);
++ if (session->bundle_demux) {
++ GstPad *demux_sink;
++ demux_sink = gst_element_get_static_pad (session->bundle_demux, "sink");
++ ret = gst_pad_link (decsrc, demux_sink);
++ gst_object_unref (demux_sink);
++ } else {
++ ret = gst_pad_link (decsrc, session->recv_rtp_sink);
++ }
+ gst_object_unref (decsrc);
+
+ if (ret != GST_PAD_LINK_OK)
+@@ -3290,81 +3471,54 @@ complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session)
+
+ } else {
+ GST_DEBUG_OBJECT (rtpbin, "no RTP decoder given");
+- recv_rtp_sink = gst_object_ref (session->recv_rtp_sink);
++ if (session->bundle_demux) {
++ recv_rtp_sink =
++ gst_element_get_static_pad (session->bundle_demux, "sink");
++ } else {
++ recv_rtp_sink =
++ gst_element_get_request_pad (session->rtp_funnel, "sink_%u");
++ }
+ }
+
+- GST_DEBUG_OBJECT (rtpbin, "ghosting session sink pad");
+- klass = GST_ELEMENT_GET_CLASS (rtpbin);
+- gname = g_strdup_printf ("recv_rtp_sink_%u", sessid);
+- templ = gst_element_class_get_pad_template (klass, "recv_rtp_sink_%u");
+- session->recv_rtp_sink_ghost =
+- gst_ghost_pad_new_from_template (gname, recv_rtp_sink, templ);
+- gst_object_unref (recv_rtp_sink);
+- gst_pad_set_active (session->recv_rtp_sink_ghost, TRUE);
+- gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->recv_rtp_sink_ghost);
+- g_free (gname);
++ funnel_src = gst_element_get_static_pad (session->rtp_funnel, "src");
++ gst_pad_link (funnel_src, session->recv_rtp_sink);
++ gst_object_unref (funnel_src);
+
+- return TRUE;
++ return recv_rtp_sink;
+
+ /* ERRORS */
+ pad_failed:
+ {
+ g_warning ("rtpbin: failed to get session recv_rtp_sink pad");
+- return FALSE;
++ return NULL;
+ }
+ dec_sink_failed:
+ {
+- g_warning ("rtpbin: failed to get decoder sink pad for session %d", sessid);
+- return FALSE;
++ g_warning ("rtpbin: failed to get decoder sink pad for session %u", sessid);
++ return NULL;
+ }
+ dec_src_failed:
+ {
+- g_warning ("rtpbin: failed to get decoder src pad for session %d", sessid);
++ g_warning ("rtpbin: failed to get decoder src pad for session %u", sessid);
+ gst_object_unref (recv_rtp_sink);
+- return FALSE;
++ return NULL;
+ }
+ dec_link_failed:
+ {
+- g_warning ("rtpbin: failed to link rtp decoder for session %d", sessid);
++ g_warning ("rtpbin: failed to link rtp decoder for session %u", sessid);
+ gst_object_unref (recv_rtp_sink);
+- return FALSE;
++ return NULL;
+ }
+ }
+
+-/* Create a pad for receiving RTP for the session in @name. Must be called with
+- * RTP_BIN_LOCK.
+- */
+-static GstPad *
+-create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
++static void
++complete_session_receiver (GstRtpBin * rtpbin, GstRtpBinSession * session,
++ guint sessid)
+ {
+- guint sessid;
+ GstElement *aux;
+ GstPad *recv_rtp_src;
+- GstRtpBinSession *session;
+-
+- /* first get the session number */
+- if (name == NULL || sscanf (name, "recv_rtp_sink_%u", &sessid) != 1)
+- goto no_name;
+-
+- GST_DEBUG_OBJECT (rtpbin, "finding session %d", sessid);
+
+- /* get or create session */
+- session = find_session_by_id (rtpbin, sessid);
+- if (!session) {
+- GST_DEBUG_OBJECT (rtpbin, "creating session %d", sessid);
+- /* create session now */
+- session = create_session (rtpbin, sessid);
+- if (session == NULL)
+- goto create_error;
+- }
+-
+- /* check if pad was requested */
+- if (session->recv_rtp_sink_ghost != NULL)
+- return session->recv_rtp_sink_ghost;
+-
+- /* setup the session sink pad */
+- if (!complete_session_sink (rtpbin, session))
+- goto session_sink_failed;
++ g_assert (!session->recv_rtp_src);
+
+ session->recv_rtp_src =
+ gst_element_get_static_pad (session->session, "recv_rtp_src");
+@@ -3381,7 +3535,7 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
+
+ GST_DEBUG_OBJECT (rtpbin, "linking AUX receiver");
+
+- pname = g_strdup_printf ("sink_%d", sessid);
++ pname = g_strdup_printf ("sink_%u", sessid);
+ auxsink = gst_element_get_static_pad (aux, pname);
+ g_free (pname);
+ if (auxsink == NULL)
+@@ -3394,7 +3548,7 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
+
+ /* this can be NULL when this AUX element is not to be linked to
+ * an SSRC demuxer */
+- pname = g_strdup_printf ("src_%d", sessid);
++ pname = g_strdup_printf ("src_%u", sessid);
+ recv_rtp_src = gst_element_get_static_pad (aux, pname);
+ g_free (pname);
+ } else {
+@@ -3408,8 +3562,8 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
+ sinkdpad = gst_element_get_static_pad (session->demux, "sink");
+ GST_DEBUG_OBJECT (rtpbin, "linking demuxer RTP sink pad");
+ gst_pad_link_full (recv_rtp_src, sinkdpad, GST_PAD_LINK_CHECK_NOTHING);
+- gst_object_unref (recv_rtp_src);
+ gst_object_unref (sinkdpad);
++ gst_object_unref (recv_rtp_src);
+
+ /* connect to the new-ssrc-pad signal of the SSRC demuxer */
+ session->demux_newpad_sig = g_signal_connect (session->demux,
+@@ -3417,6 +3571,71 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
+ session->demux_padremoved_sig = g_signal_connect (session->demux,
+ "removed-ssrc-pad", (GCallback) ssrc_demux_pad_removed, session);
+ }
++
++ return;
++
++pad_failed:
++ {
++ g_warning ("rtpbin: failed to get session recv_rtp_src pad");
++ return;
++ }
++aux_sink_failed:
++ {
++ g_warning ("rtpbin: failed to get AUX sink pad for session %u", sessid);
++ return;
++ }
++aux_link_failed:
++ {
++ g_warning ("rtpbin: failed to link AUX pad to session %u", sessid);
++ return;
++ }
++}
++
++/* Create a pad for receiving RTP for the session in @name. Must be called with
++ * RTP_BIN_LOCK.
++ */
++static GstPad *
++create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
++{
++ guint sessid;
++ GstRtpBinSession *session;
++ GstPad *recv_rtp_sink;
++
++ /* first get the session number */
++ if (name == NULL || sscanf (name, "recv_rtp_sink_%u", &sessid) != 1)
++ goto no_name;
++
++ GST_DEBUG_OBJECT (rtpbin, "finding session %u", sessid);
++
++ /* get or create session */
++ session = find_session_by_id (rtpbin, sessid);
++ if (!session) {
++ GST_DEBUG_OBJECT (rtpbin, "creating session %u", sessid);
++ /* create session now */
++ session = create_session (rtpbin, sessid);
++ if (session == NULL)
++ goto create_error;
++ }
++
++ /* check if pad was requested */
++ if (session->recv_rtp_sink_ghost != NULL)
++ return session->recv_rtp_sink_ghost;
++
++ /* setup the session sink pad */
++ recv_rtp_sink = complete_session_sink (rtpbin, session, TRUE);
++ if (!recv_rtp_sink)
++ goto session_sink_failed;
++
++
++ GST_DEBUG_OBJECT (rtpbin, "ghosting session sink pad");
++ session->recv_rtp_sink_ghost =
++ gst_ghost_pad_new_from_template (name, recv_rtp_sink, templ);
++ gst_object_unref (recv_rtp_sink);
++ gst_pad_set_active (session->recv_rtp_sink_ghost, TRUE);
++ gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->recv_rtp_sink_ghost);
++
++ complete_session_receiver (rtpbin, session, sessid);
++
+ return session->recv_rtp_sink_ghost;
+
+ /* ERRORS */
+@@ -3435,21 +3654,6 @@ session_sink_failed:
+ /* warning already done */
+ return NULL;
+ }
+-pad_failed:
+- {
+- g_warning ("rtpbin: failed to get session recv_rtp_src pad");
+- return NULL;
+- }
+-aux_sink_failed:
+- {
+- g_warning ("rtpbin: failed to get AUX sink pad for session %d", sessid);
+- return NULL;
+- }
+-aux_link_failed:
+- {
+- g_warning ("rtpbin: failed to link AUX pad to session %d", sessid);
+- return NULL;
+- }
+ }
+
+ static void
+@@ -3463,6 +3667,11 @@ remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session)
+ g_signal_handler_disconnect (session->demux, session->demux_padremoved_sig);
+ session->demux_padremoved_sig = 0;
+ }
++ if (session->bundle_demux_newpad_sig) {
++ g_signal_handler_disconnect (session->bundle_demux,
++ session->bundle_demux_newpad_sig);
++ session->bundle_demux_newpad_sig = 0;
++ }
+ if (session->recv_rtp_src) {
+ gst_object_unref (session->recv_rtp_src);
+ session->recv_rtp_src = NULL;
+@@ -3480,37 +3689,14 @@ remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session)
+ }
+ }
+
+-/* Create a pad for receiving RTCP for the session in @name. Must be called with
+- * RTP_BIN_LOCK.
+- */
+ static GstPad *
+-create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
+- const gchar * name)
++complete_session_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session,
++ guint sessid, gboolean bundle_demuxer_needed)
+ {
+- guint sessid;
+ GstElement *decoder;
+- GstRtpBinSession *session;
+- GstPad *sinkdpad, *decsink;
+-
+- /* first get the session number */
+- if (name == NULL || sscanf (name, "recv_rtcp_sink_%u", &sessid) != 1)
+- goto no_name;
+-
+- GST_DEBUG_OBJECT (rtpbin, "finding session %d", sessid);
+-
+- /* get or create the session */
+- session = find_session_by_id (rtpbin, sessid);
+- if (!session) {
+- GST_DEBUG_OBJECT (rtpbin, "creating session %d", sessid);
+- /* create session now */
+- session = create_session (rtpbin, sessid);
+- if (session == NULL)
+- goto create_error;
+- }
+-
+- /* check if pad was requested */
+- if (session->recv_rtcp_sink_ghost != NULL)
+- return session->recv_rtcp_sink_ghost;
++ GstPad *sinkdpad;
++ GstPad *decsink = NULL;
++ GstPad *funnel_src;
+
+ /* get recv_rtp pad and store */
+ GST_DEBUG_OBJECT (rtpbin, "getting RTCP sink pad");
+@@ -3519,6 +3705,9 @@ create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
+ if (session->recv_rtcp_sink == NULL)
+ goto pad_failed;
+
++ if (bundle_demuxer_needed)
++ session_maybe_create_bundle_demuxer (session);
++
+ GST_DEBUG_OBJECT (rtpbin, "getting RTCP decoder");
+ decoder = session_request_element (session, SIGNAL_REQUEST_RTCP_DECODER);
+ if (decoder) {
+@@ -3535,14 +3724,26 @@ create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
+ if (decsrc == NULL)
+ goto dec_src_failed;
+
+- ret = gst_pad_link (decsrc, session->recv_rtcp_sink);
++ if (session->bundle_demux) {
++ GstPad *demux_sink;
++ demux_sink =
++ gst_element_get_static_pad (session->bundle_demux, "rtcp_sink");
++ ret = gst_pad_link (decsrc, demux_sink);
++ gst_object_unref (demux_sink);
++ } else {
++ ret = gst_pad_link (decsrc, session->recv_rtcp_sink);
++ }
+ gst_object_unref (decsrc);
+
+ if (ret != GST_PAD_LINK_OK)
+ goto dec_link_failed;
+ } else {
+ GST_DEBUG_OBJECT (rtpbin, "no RTCP decoder given");
+- decsink = gst_object_ref (session->recv_rtcp_sink);
++ if (session->bundle_demux) {
++ decsink = gst_element_get_static_pad (session->bundle_demux, "rtcp_sink");
++ } else {
++ decsink = gst_element_get_request_pad (session->rtcp_funnel, "sink_%u");
++ }
+ }
+
+ /* get srcpad, link to SSRCDemux */
+@@ -3556,26 +3757,12 @@ create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
+ gst_pad_link_full (session->sync_src, sinkdpad, GST_PAD_LINK_CHECK_NOTHING);
+ gst_object_unref (sinkdpad);
+
+- session->recv_rtcp_sink_ghost =
+- gst_ghost_pad_new_from_template (name, decsink, templ);
+- gst_object_unref (decsink);
+- gst_pad_set_active (session->recv_rtcp_sink_ghost, TRUE);
+- gst_element_add_pad (GST_ELEMENT_CAST (rtpbin),
+- session->recv_rtcp_sink_ghost);
++ funnel_src = gst_element_get_static_pad (session->rtcp_funnel, "src");
++ gst_pad_link (funnel_src, session->recv_rtcp_sink);
++ gst_object_unref (funnel_src);
+
+- return session->recv_rtcp_sink_ghost;
++ return decsink;
+
+- /* ERRORS */
+-no_name:
+- {
+- g_warning ("rtpbin: invalid name given");
+- return NULL;
+- }
+-create_error:
+- {
+- /* create_session already warned */
+- return NULL;
+- }
+ pad_failed:
+ {
+ g_warning ("rtpbin: failed to get session rtcp_sink pad");
+@@ -3583,25 +3770,82 @@ pad_failed:
+ }
+ dec_sink_failed:
+ {
+- g_warning ("rtpbin: failed to get decoder sink pad for session %d", sessid);
++ g_warning ("rtpbin: failed to get decoder sink pad for session %u", sessid);
+ return NULL;
+ }
+ dec_src_failed:
+ {
+- g_warning ("rtpbin: failed to get decoder src pad for session %d", sessid);
+- gst_object_unref (decsink);
+- return NULL;
++ g_warning ("rtpbin: failed to get decoder src pad for session %u", sessid);
++ goto cleanup;
+ }
+ dec_link_failed:
+ {
+- g_warning ("rtpbin: failed to link rtcp decoder for session %d", sessid);
+- gst_object_unref (decsink);
+- return NULL;
++ g_warning ("rtpbin: failed to link rtcp decoder for session %u", sessid);
++ goto cleanup;
+ }
+ src_pad_failed:
+ {
+ g_warning ("rtpbin: failed to get session sync_src pad");
+- gst_object_unref (decsink);
++ }
++
++cleanup:
++ gst_object_unref (decsink);
++ return NULL;
++}
++
++/* Create a pad for receiving RTCP for the session in @name. Must be called with
++ * RTP_BIN_LOCK.
++ */
++static GstPad *
++create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
++ const gchar * name)
++{
++ guint sessid;
++ GstRtpBinSession *session;
++ GstPad *decsink = NULL;
++
++ /* first get the session number */
++ if (name == NULL || sscanf (name, "recv_rtcp_sink_%u", &sessid) != 1)
++ goto no_name;
++
++ GST_DEBUG_OBJECT (rtpbin, "finding session %u", sessid);
++
++ /* get or create the session */
++ session = find_session_by_id (rtpbin, sessid);
++ if (!session) {
++ GST_DEBUG_OBJECT (rtpbin, "creating session %u", sessid);
++ /* create session now */
++ session = create_session (rtpbin, sessid);
++ if (session == NULL)
++ goto create_error;
++ }
++
++ /* check if pad was requested */
++ if (session->recv_rtcp_sink_ghost != NULL)
++ return session->recv_rtcp_sink_ghost;
++
++ decsink = complete_session_rtcp (rtpbin, session, sessid, TRUE);
++ if (!decsink)
++ goto create_error;
++
++ session->recv_rtcp_sink_ghost =
++ gst_ghost_pad_new_from_template (name, decsink, templ);
++ gst_object_unref (decsink);
++ gst_pad_set_active (session->recv_rtcp_sink_ghost, TRUE);
++ gst_element_add_pad (GST_ELEMENT_CAST (rtpbin),
++ session->recv_rtcp_sink_ghost);
++
++ return session->recv_rtcp_sink_ghost;
++
++ /* ERRORS */
++no_name:
++ {
++ g_warning ("rtpbin: invalid name given");
++ return NULL;
++ }
++create_error:
++ {
++ /* create_session already warned */
+ return NULL;
+ }
+ }
+@@ -3651,7 +3895,7 @@ complete_session_src (GstRtpBin * rtpbin, GstRtpBinSession * session)
+ GstPadLinkReturn ret;
+
+ GST_DEBUG_OBJECT (rtpbin, "linking RTP encoder");
+- ename = g_strdup_printf ("rtp_src_%d", sessid);
++ ename = g_strdup_printf ("rtp_src_%u", sessid);
+ encsrc = gst_element_get_static_pad (encoder, ename);
+ g_free (ename);
+
+@@ -3660,7 +3904,7 @@ complete_session_src (GstRtpBin * rtpbin, GstRtpBinSession * session)
+
+ send_rtp_src = encsrc;
+
+- ename = g_strdup_printf ("rtp_sink_%d", sessid);
++ ename = g_strdup_printf ("rtp_sink_%u", sessid);
+ encsink = gst_element_get_static_pad (encoder, ename);
+ g_free (ename);
+ if (encsink == NULL)
+@@ -3694,23 +3938,23 @@ complete_session_src (GstRtpBin * rtpbin, GstRtpBinSession * session)
+ /* ERRORS */
+ no_srcpad:
+ {
+- g_warning ("rtpbin: failed to get rtp source pad for session %d", sessid);
++ g_warning ("rtpbin: failed to get rtp source pad for session %u", sessid);
+ return FALSE;
+ }
+ enc_src_failed:
+ {
+- g_warning ("rtpbin: failed to get encoder src pad for session %d", sessid);
++ g_warning ("rtpbin: failed to get encoder src pad for session %u", sessid);
+ return FALSE;
+ }
+ enc_sink_failed:
+ {
+- g_warning ("rtpbin: failed to get encoder sink pad for session %d", sessid);
++ g_warning ("rtpbin: failed to get encoder sink pad for session %u", sessid);
+ gst_object_unref (send_rtp_src);
+ return FALSE;
+ }
+ enc_link_failed:
+ {
+- g_warning ("rtpbin: failed to link rtp encoder for session %d", sessid);
++ g_warning ("rtpbin: failed to link rtp encoder for session %u", sessid);
+ gst_object_unref (send_rtp_src);
+ return FALSE;
+ }
+@@ -3772,22 +4016,22 @@ create_error:
+ }
+ existing_session:
+ {
+- g_warning ("rtpbin: session %d is already a sender", sessid);
++ g_warning ("rtpbin: session %u is already a sender", sessid);
+ return FALSE;
+ }
+ pad_failed:
+ {
+- g_warning ("rtpbin: failed to get session pad for session %d", sessid);
++ g_warning ("rtpbin: failed to get session pad for session %u", sessid);
+ return FALSE;
+ }
+ aux_link_failed:
+ {
+- g_warning ("rtpbin: failed to link AUX for session %d", sessid);
++ g_warning ("rtpbin: failed to link AUX for session %u", sessid);
+ return FALSE;
+ }
+ session_src_failed:
+ {
+- g_warning ("rtpbin: failed to complete AUX for session %d", sessid);
++ g_warning ("rtpbin: failed to complete AUX for session %u", sessid);
+ return FALSE;
+ }
+ }
+@@ -3847,7 +4091,7 @@ create_send_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
+ if (!setup_aux_sender (rtpbin, session, aux))
+ goto aux_session_failed;
+
+- pname = g_strdup_printf ("sink_%d", sessid);
++ pname = g_strdup_printf ("sink_%u", sessid);
+ send_rtp_sink = gst_element_get_static_pad (aux, pname);
+ g_free (pname);
+
+@@ -3887,27 +4131,27 @@ create_error:
+ }
+ existing_session:
+ {
+- g_warning ("rtpbin: session %d is already in use", sessid);
++ g_warning ("rtpbin: session %u is already in use", sessid);
+ return NULL;
+ }
+ aux_session_failed:
+ {
+- g_warning ("rtpbin: failed to get AUX sink pad for session %d", sessid);
++ g_warning ("rtpbin: failed to get AUX sink pad for session %u", sessid);
+ return NULL;
+ }
+ aux_sink_failed:
+ {
+- g_warning ("rtpbin: failed to get AUX sink pad for session %d", sessid);
++ g_warning ("rtpbin: failed to get AUX sink pad for session %u", sessid);
+ return NULL;
+ }
+ pad_failed:
+ {
+- g_warning ("rtpbin: failed to get session pad for session %d", sessid);
++ g_warning ("rtpbin: failed to get session pad for session %u", sessid);
+ return NULL;
+ }
+ session_src_failed:
+ {
+- g_warning ("rtpbin: failed to setup source pads for session %d", sessid);
++ g_warning ("rtpbin: failed to setup source pads for session %u", sessid);
+ return NULL;
+ }
+ }
+@@ -3978,13 +4222,13 @@ create_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
+
+ GST_DEBUG_OBJECT (rtpbin, "linking RTCP encoder");
+
+- ename = g_strdup_printf ("rtcp_src_%d", sessid);
++ ename = g_strdup_printf ("rtcp_src_%u", sessid);
+ encsrc = gst_element_get_static_pad (encoder, ename);
+ g_free (ename);
+ if (encsrc == NULL)
+ goto enc_src_failed;
+
+- ename = g_strdup_printf ("rtcp_sink_%d", sessid);
++ ename = g_strdup_printf ("rtcp_sink_%u", sessid);
+ encsink = gst_element_get_static_pad (encoder, ename);
+ g_free (ename);
+ if (encsink == NULL)
+@@ -4021,23 +4265,23 @@ no_session:
+ }
+ pad_failed:
+ {
+- g_warning ("rtpbin: failed to get rtcp pad for session %d", sessid);
++ g_warning ("rtpbin: failed to get rtcp pad for session %u", sessid);
+ return NULL;
+ }
+ enc_src_failed:
+ {
+- g_warning ("rtpbin: failed to get encoder src pad for session %d", sessid);
++ g_warning ("rtpbin: failed to get encoder src pad for session %u", sessid);
+ return NULL;
+ }
+ enc_sink_failed:
+ {
+- g_warning ("rtpbin: failed to get encoder sink pad for session %d", sessid);
++ g_warning ("rtpbin: failed to get encoder sink pad for session %u", sessid);
+ gst_object_unref (encsrc);
+ return NULL;
+ }
+ enc_link_failed:
+ {
+- g_warning ("rtpbin: failed to link rtcp encoder for session %d", sessid);
++ g_warning ("rtpbin: failed to link rtcp encoder for session %u", sessid);
+ gst_object_unref (encsrc);
+ return NULL;
+ }
+diff --git a/gst/rtpmanager/gstrtpbin.h b/gst/rtpmanager/gstrtpbin.h
+index fb13a47..384b76d 100644
+--- a/gst/rtpmanager/gstrtpbin.h
++++ b/gst/rtpmanager/gstrtpbin.h
+@@ -127,6 +127,8 @@ struct _GstRtpBinClass {
+
+ void (*on_new_sender_ssrc) (GstRtpBin *rtpbin, guint session, guint32 ssrc);
+ void (*on_sender_ssrc_active) (GstRtpBin *rtpbin, guint session, guint32 ssrc);
++
++ guint (*on_bundled_ssrc) (GstRtpBin *rtpbin, guint ssrc);
+ };
+
+ GType gst_rtp_bin_get_type (void);
diff --git a/Tools/gtk/patches/gst-plugins-good-0004-qtdemux-add-context-for-a-preferred-protection.patch b/Tools/gtk/patches/gst-plugins-good-0004-qtdemux-add-context-for-a-preferred-protection.patch
new file mode 100644
index 000000000..fb15e018f
--- /dev/null
+++ b/Tools/gtk/patches/gst-plugins-good-0004-qtdemux-add-context-for-a-preferred-protection.patch
@@ -0,0 +1,320 @@
+From ae4f7d4f09a051c2fbbd05e4df9f79fa6522104f Mon Sep 17 00:00:00 2001
+From: Xabier Rodriguez Calvar <calvaris@igalia.com>
+Date: Fri, 16 Sep 2016 16:08:18 +0200
+Subject: [PATCH] qtdemux: add context for a preferred protection
+
+qtdemux selected the first system corresponding to a working GStreamer
+decryptor. With this change, before selecting that decryptor, qtdemux
+will check if it has context (a preferred decryptor id) and if not, it
+will request it.
+
+The request includes track-id, available key system ids for the
+available decryptors and event the events so that the init data is
+accessible.
+---
+ gst/isomp4/qtdemux.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++++--
+ gst/isomp4/qtdemux.h | 2 +-
+ 2 files changed, 204 insertions(+), 7 deletions(-)
+
+diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c
+index 0425e66..e05e75e 100644
+--- a/gst/isomp4/qtdemux.c
++++ b/gst/isomp4/qtdemux.c
+@@ -480,6 +480,8 @@ static GstIndex *gst_qtdemux_get_index (GstElement * element);
+ #endif
+ static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
+ GstStateChange transition);
++static void gst_qtdemux_set_context (GstElement * element,
++ GstContext * context);
+ static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
+ static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
+ GstObject * parent, GstPadMode mode, gboolean active);
+@@ -554,6 +556,7 @@ gst_qtdemux_class_init (GstQTDemuxClass * klass)
+ gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
+ gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
+ #endif
++ gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
+
+ gst_tag_register_musicbrainz_tags ();
+
+@@ -612,6 +615,7 @@ gst_qtdemux_init (GstQTDemux * qtdemux)
+ qtdemux->cenc_aux_info_sizes = NULL;
+ qtdemux->cenc_aux_sample_count = 0;
+ qtdemux->protection_system_ids = NULL;
++ qtdemux->preferred_protection_system_id = NULL;
+ g_queue_init (&qtdemux->protection_event_queue);
+ gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
+ qtdemux->flowcombiner = gst_flow_combiner_new ();
+@@ -1972,6 +1976,10 @@ gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
+ g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
+ NULL);
+ g_queue_clear (&qtdemux->protection_event_queue);
++ if (qtdemux->preferred_protection_system_id) {
++ g_free (qtdemux->preferred_protection_system_id);
++ qtdemux->preferred_protection_system_id = NULL;
++ }
+ }
+ qtdemux->offset = 0;
+ gst_adapter_clear (qtdemux->adapter);
+@@ -2404,6 +2412,29 @@ gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
+ }
+
+ static void
++gst_qtdemux_set_context (GstElement * element, GstContext * context)
++{
++ GstQTDemux *qtdemux = GST_QTDEMUX (element);
++
++ g_return_if_fail (GST_IS_CONTEXT (context));
++
++ if (g_strcmp0 (gst_context_get_context_type (context),
++ "drm-preferred-decryption-system-id") == 0) {
++ const GstStructure *s;
++
++ s = gst_context_get_structure (context);
++ qtdemux->preferred_protection_system_id =
++ g_strdup (gst_structure_get_string (s, "decryption-system-id"));
++ GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
++ qtdemux->preferred_protection_system_id);
++ }
++
++ GST_TRACE_OBJECT (element, "chaining set_context to superclass %p or %p",
++ GST_ELEMENT_GET_CLASS (element), parent_class);
++ GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
++}
++
++static void
+ qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
+ {
+ /* counts as header data */
+@@ -3392,6 +3423,8 @@ qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
+ event = gst_event_new_protection (sysid_string, pssh,
+ (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
+ for (i = 0; i < qtdemux->n_streams; ++i) {
++ GST_TRACE_OBJECT (qtdemux,
++ "adding protection event for stream %d and system %s", i, sysid_string);
+ g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
+ gst_event_ref (event));
+ }
+@@ -4993,6 +5026,12 @@ gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
+ GstEvent *event;
+
+ while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
++#if (!GST_DISABLE_GST_DEBUG)
++ const gchar *system_id = NULL;
++ gst_event_parse_protection (event, &system_id, NULL, NULL);
++ GST_TRACE_OBJECT (qtdemux, "pushing again protection event for system %s",
++ system_id);
++#endif
+ gst_pad_push_event (stream->pad, event);
+ }
+
+@@ -6947,11 +6986,148 @@ qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
+ }
+
+ static gboolean
++pad_query (const GValue * item, GValue * value, gpointer user_data)
++{
++ GstPad *pad = g_value_get_object (item);
++ GstQuery *query = user_data;
++ gboolean res;
++
++ res = gst_pad_peer_query (pad, query);
++
++ if (res) {
++ g_value_set_boolean (value, TRUE);
++ return FALSE;
++ }
++
++ GST_INFO_OBJECT (pad, "pad peer query failed");
++ return TRUE;
++}
++
++static gboolean
++gst_qtdemux_run_query (GstElement * element, GstQuery * query,
++ GstPadDirection direction)
++{
++ GstIterator *it;
++ GstIteratorFoldFunction func = pad_query;
++ GValue res = { 0, };
++
++ g_value_init (&res, G_TYPE_BOOLEAN);
++ g_value_set_boolean (&res, FALSE);
++
++ /* Ask neighbor */
++ if (direction == GST_PAD_SRC)
++ it = gst_element_iterate_src_pads (element);
++ else
++ it = gst_element_iterate_sink_pads (element);
++
++ while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
++ gst_iterator_resync (it);
++
++ gst_iterator_free (it);
++
++ return g_value_get_boolean (&res);
++}
++
++static void
++gst_qtdemux_request_protection_context_if_needed (GstQTDemux * qtdemux,
++ QtDemuxStream * stream)
++{
++ GstQuery *query;
++ GstContext *ctxt;
++ GstElement *element = GST_ELEMENT (qtdemux);
++ GstStructure *st;
++ gchar **filtered_sys_ids;
++ GValue event_list = G_VALUE_INIT;
++ GList *walk;
++
++ /* 1. Check if we already have the context. */
++ if (qtdemux->preferred_protection_system_id != NULL) {
++ GST_LOG_OBJECT (element,
++ "already have the protection context, no need to request it again");
++ return;
++ }
++
++ GST_TRACE_OBJECT (qtdemux, "currently we have detected %u protection systems",
++ qtdemux->protection_system_ids->len);
++ g_ptr_array_add (qtdemux->protection_system_ids, NULL);
++ filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
++ (const gchar **) qtdemux->protection_system_ids->pdata);
++ g_ptr_array_remove_index (qtdemux->protection_system_ids,
++ qtdemux->protection_system_ids->len - 1);
++ if (filtered_sys_ids == NULL || filtered_sys_ids[0] == NULL) {
++ GST_LOG_OBJECT (qtdemux, "no suitable decryptors found, not issuing the "
++ "context request");
++ g_strfreev (filtered_sys_ids);
++ return;
++ }
++ GST_TRACE_OBJECT (qtdemux, "found suitable decryptors, running the context "
++ "request");
++
++ if (stream->protection_scheme_event_queue.length) {
++ GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
++ stream->protection_scheme_event_queue.length);
++ walk = stream->protection_scheme_event_queue.tail;
++ } else {
++ GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
++ qtdemux->protection_event_queue.length);
++ walk = qtdemux->protection_event_queue.tail;
++ }
++
++ g_value_init (&event_list, GST_TYPE_LIST);
++ for (; walk; walk = g_list_previous (walk)) {
++ GValue *event_value = g_new0 (GValue, 1);
++ g_value_init (event_value, GST_TYPE_EVENT);
++ g_value_set_boxed (event_value, walk->data);
++ gst_value_list_append_and_take_value (&event_list, event_value);
++ }
++
++ /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
++ * check if downstream already has a context of the specific type
++ * 2b) Query upstream as above.
++ */
++ query = gst_query_new_context ("drm-preferred-decryption-system-id");
++ st = (GstStructure *) gst_query_get_structure (query);
++ gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
++ "stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids, NULL);
++ gst_structure_set_value (st, "stream-encryption-events", &event_list);
++ if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
++ gst_query_parse_context (query, &ctxt);
++ GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
++ gst_element_set_context (element, ctxt);
++ } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
++ gst_query_parse_context (query, &ctxt);
++ GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
++ gst_element_set_context (element, ctxt);
++ } else {
++ /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
++ * the required context type and afterwards check if a
++ * usable context was set now as in 1). The message could
++ * be handled by the parent bins of the element and the
++ * application.
++ */
++ GstMessage *msg;
++
++ GST_INFO_OBJECT (element, "posting need context message");
++ msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
++ "drm-preferred-decryption-system-id");
++ st = (GstStructure *) gst_message_get_structure (msg);
++ gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
++ "stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids, NULL);
++ gst_structure_set_value (st, "stream-encryption-events", &event_list);
++ gst_element_post_message (element, msg);
++ }
++
++ g_strfreev (filtered_sys_ids);
++ g_value_unset (&event_list);
++ gst_query_unref (query);
++}
++
++static gboolean
+ gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
+ QtDemuxStream * stream)
+ {
+ GstStructure *s;
+- const gchar *selected_system;
++ const gchar *selected_system = NULL;
+
+ g_return_val_if_fail (qtdemux != NULL, FALSE);
+ g_return_val_if_fail (stream != NULL, FALSE);
+@@ -6966,17 +7142,38 @@ gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
+ "cenc protection system information has been found");
+ return FALSE;
+ }
+- g_ptr_array_add (qtdemux->protection_system_ids, NULL);
+- selected_system = gst_protection_select_system ((const gchar **)
+- qtdemux->protection_system_ids->pdata);
+- g_ptr_array_remove_index (qtdemux->protection_system_ids,
+- qtdemux->protection_system_ids->len - 1);
++
++ gst_qtdemux_request_protection_context_if_needed (qtdemux, stream);
++ if (qtdemux->preferred_protection_system_id != NULL) {
++ guint i;
++ for (i = 0; i < qtdemux->protection_system_ids->len; i++) {
++ if (g_strcmp0 (g_ptr_array_index (qtdemux->protection_system_ids, i),
++ qtdemux->preferred_protection_system_id) == 0) {
++ const gchar *preferred_system_array[] =
++ { qtdemux->preferred_protection_system_id, NULL };
++ selected_system = gst_protection_select_system (preferred_system_array);
++ break;
++ }
++ }
++ }
++
++ if (!selected_system) {
++ g_ptr_array_add (qtdemux->protection_system_ids, NULL);
++ selected_system = gst_protection_select_system ((const gchar **)
++ qtdemux->protection_system_ids->pdata);
++ g_ptr_array_remove_index (qtdemux->protection_system_ids,
++ qtdemux->protection_system_ids->len - 1);
++ }
++
+ if (!selected_system) {
+ GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
+ "suitable decryptor element has been found");
+ return FALSE;
+ }
+
++ GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
++ selected_system);
++
+ s = gst_caps_get_structure (stream->caps, 0);
+ if (!gst_structure_has_name (s, "application/x-cenc")) {
+ gst_structure_set (s,
+diff --git a/gst/isomp4/qtdemux.h b/gst/isomp4/qtdemux.h
+index 53bd071..55c4f63 100644
+--- a/gst/isomp4/qtdemux.h
++++ b/gst/isomp4/qtdemux.h
+@@ -153,7 +153,7 @@ struct _GstQTDemux {
+ guint64 cenc_aux_info_offset;
+ guint8 *cenc_aux_info_sizes;
+ guint32 cenc_aux_sample_count;
+-
++ gchar *preferred_protection_system_id;
+ };
+
+ struct _GstQTDemuxClass {
+--
+2.11.0
+
diff --git a/Tools/gtk/patches/gst-plugins-good-Revert-qtdemux-expose-streams-with-first-moof-for-fr.patch b/Tools/gtk/patches/gst-plugins-good-Revert-qtdemux-expose-streams-with-first-moof-for-fr.patch
new file mode 100644
index 000000000..3a60db477
--- /dev/null
+++ b/Tools/gtk/patches/gst-plugins-good-Revert-qtdemux-expose-streams-with-first-moof-for-fr.patch
@@ -0,0 +1,133 @@
+From 1a81bd90d4a3e59d6669a0bbfa456f1ed4e5db48 Mon Sep 17 00:00:00 2001
+From: Xabier Rodriguez Calvar <calvaris@igalia.com>
+Date: Thu, 7 Apr 2016 13:57:16 +0200
+Subject: [PATCH] Revert "qtdemux: expose streams with first moof for
+ fragmented format"
+
+This reverts commit d8bb6687ea251570c331038279a43d448167d6ad.
+---
+ gst/isomp4/qtdemux.c | 54 ++++++++++++++++------------------------------------
+ gst/isomp4/qtdemux.h | 1 -
+ 2 files changed, 16 insertions(+), 39 deletions(-)
+
+diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c
+index 39be163..9636b4b 100644
+--- a/gst/isomp4/qtdemux.c
++++ b/gst/isomp4/qtdemux.c
+@@ -609,7 +609,6 @@ gst_qtdemux_init (GstQTDemux * qtdemux)
+ qtdemux->state = QTDEMUX_STATE_INITIAL;
+ qtdemux->pullbased = FALSE;
+ qtdemux->posted_redirect = FALSE;
+- qtdemux->pending_configure = FALSE;
+ qtdemux->neededbytes = 16;
+ qtdemux->todrop = 0;
+ qtdemux->adapter = gst_adapter_new ();
+@@ -2049,7 +2048,6 @@ gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
+ gst_caps_replace (&qtdemux->media_caps, NULL);
+ qtdemux->timescale = 0;
+ qtdemux->got_moov = FALSE;
+- qtdemux->pending_configure = FALSE;
+ } else if (qtdemux->mss_mode) {
+ gst_flow_combiner_reset (qtdemux->flowcombiner);
+ for (n = 0; n < qtdemux->n_streams; n++)
+@@ -6104,7 +6102,6 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
+ &fourcc);
+ if (fourcc == FOURCC_moov) {
+ gint n;
+- gboolean got_samples = FALSE;
+
+ /* in usual fragmented setup we could try to scan for more
+ * and end up at the the moov (after mdat) again */
+@@ -6136,27 +6133,19 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
+ qtdemux_node_dump (demux, demux->moov_node);
+ qtdemux_parse_tree (demux);
+ qtdemux_prepare_streams (demux);
++ if (!demux->got_moov)
++ qtdemux_expose_streams (demux);
++ else {
+
+- for (n = 0; n < demux->n_streams; n++) {
+- QtDemuxStream *stream = demux->streams[n];
+- got_samples |= stream->stbl_index >= 0;
+- }
+- if (!demux->fragmented || got_samples) {
+- if (!demux->got_moov) {
+- qtdemux_expose_streams (demux);
+- } else {
+- for (n = 0; n < demux->n_streams; n++) {
+- QtDemuxStream *stream = demux->streams[n];
+- gst_qtdemux_configure_stream (demux, stream);
+- }
++ for (n = 0; n < demux->n_streams; n++) {
++ QtDemuxStream *stream = demux->streams[n];
++
++ gst_qtdemux_configure_stream (demux, stream);
+ }
+- gst_qtdemux_check_send_pending_segment (demux);
+- demux->pending_configure = FALSE;
+- } else {
+- demux->pending_configure = TRUE;
+ }
+
+ demux->got_moov = TRUE;
++ gst_qtdemux_check_send_pending_segment (demux);
+
+ /* fragmented streams headers shouldn't contain edts atoms */
+ if (!demux->fragmented) {
+@@ -6175,7 +6164,6 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
+ guint64 dist = 0;
+ GstClockTime prev_pts;
+ guint64 prev_offset;
+- gint n;
+
+ GST_DEBUG_OBJECT (demux, "Parsing [moof]");
+
+@@ -6209,25 +6197,15 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
+ ret = GST_FLOW_ERROR;
+ goto done;
+ }
+- /* in MSS we need to expose the pads after the first moof as we won't get a moov
+- * Also, fragmented format need to be exposed if a moov have no valid sample data */
+- if (demux->mss_mode || demux->pending_configure) {
+- if (!demux->exposed) {
+- if (!demux->pending_newsegment) {
+- GstSegment segment;
+- gst_segment_init (&segment, GST_FORMAT_TIME);
+- GST_DEBUG_OBJECT (demux, "new pending_newsegment");
+- demux->pending_newsegment = gst_event_new_segment (&segment);
+- }
+- qtdemux_expose_streams (demux);
+- } else {
+- for (n = 0; n < demux->n_streams; n++) {
+- QtDemuxStream *stream = demux->streams[n];
+- gst_qtdemux_configure_stream (demux, stream);
+- }
++ /* in MSS we need to expose the pads after the first moof as we won't get a moov */
++ if (demux->mss_mode && !demux->exposed) {
++ if (!demux->pending_newsegment) {
++ GstSegment segment;
++ gst_segment_init (&segment, GST_FORMAT_TIME);
++ GST_DEBUG_OBJECT (demux, "new pending_newsegment");
++ demux->pending_newsegment = gst_event_new_segment (&segment);
+ }
+- gst_qtdemux_check_send_pending_segment (demux);
+- demux->pending_configure = FALSE;
++ qtdemux_expose_streams (demux);
+ }
+ } else {
+ GST_DEBUG_OBJECT (demux, "Discarding [moof]");
+diff --git a/gst/isomp4/qtdemux.h b/gst/isomp4/qtdemux.h
+index 6061215..ecf0c63 100644
+--- a/gst/isomp4/qtdemux.h
++++ b/gst/isomp4/qtdemux.h
+@@ -89,7 +89,6 @@ struct _GstQTDemux {
+ gboolean posted_redirect;
+
+ /* push based variables */
+- gboolean pending_configure;
+ guint neededbytes;
+ guint todrop;
+ GstAdapter *adapter;
+--
+2.8.0.rc3
+
diff --git a/Tools/gtk/patches/gst-plugins-good-use-the-tfdt-decode-time.patch b/Tools/gtk/patches/gst-plugins-good-use-the-tfdt-decode-time.patch
new file mode 100644
index 000000000..c3c08dfed
--- /dev/null
+++ b/Tools/gtk/patches/gst-plugins-good-use-the-tfdt-decode-time.patch
@@ -0,0 +1,89 @@
+From 1556043c00eb60d3871b4baa8b029175c16c7097 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Enrique=20Oca=C3=B1a=20Gonz=C3=A1lez?= <eocanha@igalia.com>
+Date: Mon, 24 Oct 2016 16:56:31 +0000
+Subject: [PATCH] Use the tfdt decode time on byte streams when it's
+ significantly different than the time in the last sample
+
+We consider there's a sifnificant difference when it's larger than on second
+or than half the duration of the last processed fragment in case the latter is
+larger.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=754230
+---
+ gst/isomp4/qtdemux.c | 25 +++++++++++++++++++++++++
+ 1 file changed, 25 insertions(+)
+
+diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c
+index db2d361..5430a39 100644
+--- a/gst/isomp4/qtdemux.c
++++ b/gst/isomp4/qtdemux.c
+@@ -95,6 +95,8 @@
+
+ #define STREAM_IS_EOS(s) (s->time_position == GST_CLOCK_TIME_NONE)
+
++#define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
++
+ GST_DEBUG_CATEGORY (qtdemux_debug);
+
+ /*typedef struct _QtNode QtNode; */
+@@ -256,6 +258,7 @@ struct _QtDemuxStream
+ guint32 n_samples_moof; /* sample count in a moof */
+ guint64 duration_moof; /* duration in timescale of a moof, used for figure out
+ * the framerate of fragmented format stream */
++ guint64 duration_last_moof;
+ guint32 offset_in_sample;
+ guint32 max_buffer_size;
+
+@@ -1828,6 +1831,7 @@ _create_stream (void)
+ stream->protection_scheme_info = NULL;
+ stream->n_samples_moof = 0;
+ stream->duration_moof = 0;
++ stream->duration_last_moof = 0;
+ g_queue_init (&stream->protection_scheme_event_queue);
+ return stream;
+ }
+@@ -2315,6 +2319,7 @@ gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
+
+ stream->n_samples_moof = 0;
+ stream->duration_moof = 0;
++ stream->duration_last_moof = 0;
+ }
+
+ static void
+@@ -2883,6 +2888,25 @@ qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
+ stream->samples[stream->n_samples - 1].timestamp +
+ stream->samples[stream->n_samples - 1].duration;
+
++ /* If this is a GST_FORMAT_BYTES stream and there's a significant
++ * difference (1 sec.) between decode_ts and timestamp, prefer the
++ * former */
++ if (!qtdemux->upstream_format_is_time
++ && ABSDIFF (decode_ts, timestamp) >
++ MAX (stream->duration_last_moof / 2,
++ GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
++ GST_INFO_OBJECT (qtdemux,
++ "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
++ ") are significantly different (more than %" GST_TIME_FORMAT
++ "), using decode_ts",
++ GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
++ GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
++ GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
++ MAX (stream->duration_last_moof / 2,
++ GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
++ timestamp = decode_ts;
++ }
++
+ gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
+ GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
+ " (extends previous samples)", GST_TIME_ARGS (gst_ts));
+@@ -3544,6 +3568,7 @@ qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
+
+ /* initialise moof sample data */
+ stream->n_samples_moof = 0;
++ stream->duration_last_moof = stream->duration_moof;
+ stream->duration_moof = 0;
+
+ /* Track Run node */
+--
+2.1.4
+
diff --git a/Tools/gtk/patches/gstreamer-0001-protection-added-function-to-filter-system-ids.patch b/Tools/gtk/patches/gstreamer-0001-protection-added-function-to-filter-system-ids.patch
new file mode 100644
index 000000000..e72ef6c13
--- /dev/null
+++ b/Tools/gtk/patches/gstreamer-0001-protection-added-function-to-filter-system-ids.patch
@@ -0,0 +1,77 @@
+From 7772eb350591682b6a315c8a87a58131f731f1d4 Mon Sep 17 00:00:00 2001
+From: Xabier Rodriguez Calvar <calvaris@igalia.com>
+Date: Wed, 19 Oct 2016 16:44:16 +0200
+Subject: [PATCH] protection: added function to filter system ids
+
+gst_protection_filter_systems_by_available_decryptors takes an array of
+strings and returns a new array of strings filtered by the avaible
+decryptors for them so the ones you get are the ones that you should be
+able to decrypt.
+---
+ gst/gstprotection.c | 36 ++++++++++++++++++++++++++++++++++++
+ gst/gstprotection.h | 2 ++
+ 2 files changed, 38 insertions(+)
+
+diff --git a/gst/gstprotection.c b/gst/gstprotection.c
+index 8ee52ea..2d7e5e0 100644
+--- a/gst/gstprotection.c
++++ b/gst/gstprotection.c
+@@ -191,6 +191,42 @@ gst_protection_select_system (const gchar ** system_identifiers)
+ return retval;
+ }
+
++gchar **
++gst_protection_filter_systems_by_available_decryptors (const gchar **
++ system_identifiers)
++{
++ GList *decryptors, *walk;
++ gchar **retval;
++ guint i = 0, decryptors_number;
++
++ decryptors =
++ gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_DECRYPTOR,
++ GST_RANK_MARGINAL);
++
++ decryptors_number = g_list_length (decryptors);
++ retval = g_new (gchar *, decryptors_number + 1);
++
++ GST_TRACE ("found %u decrytors", decryptors_number);
++
++ for (walk = decryptors; walk; walk = g_list_next (walk)) {
++ GstElementFactory *fact = (GstElementFactory *) walk->data;
++
++ const char *found_sys_id =
++ gst_protection_factory_check (fact, system_identifiers);
++ GST_TRACE ("factory %s is valid for %s", GST_OBJECT_NAME (fact),
++ found_sys_id);
++
++ if (found_sys_id) {
++ retval[i++] = g_strdup (found_sys_id);
++ }
++ }
++ retval[i] = NULL;
++
++ gst_plugin_feature_list_free (decryptors);
++
++ return retval;
++}
++
+ static const gchar *
+ gst_protection_factory_check (GstElementFactory * fact,
+ const gchar ** system_identifiers)
+diff --git a/gst/gstprotection.h b/gst/gstprotection.h
+index f2f54c4..95976c5 100644
+--- a/gst/gstprotection.h
++++ b/gst/gstprotection.h
+@@ -66,6 +66,8 @@ GstProtectionMeta *gst_buffer_add_protection_meta (GstBuffer * buffer,
+ GstStructure * info);
+
+ const gchar *gst_protection_select_system (const gchar ** system_identifiers);
++gchar ** gst_protection_filter_systems_by_available_decryptors (
++ const gchar ** system_identifiers);
+
+ G_END_DECLS
+ #endif /* __GST_PROTECTION_META_H__ */
+--
+2.10.2
+
diff --git a/Tools/gtk/patches/gtk+-configure-fix-detecting-CUPS-2.x.patch b/Tools/gtk/patches/gtk+-configure-fix-detecting-CUPS-2.x.patch
new file mode 100644
index 000000000..1099f36f2
--- /dev/null
+++ b/Tools/gtk/patches/gtk+-configure-fix-detecting-CUPS-2.x.patch
@@ -0,0 +1,11 @@
+--- a/configure 2016-12-06 14:33:55.708778846 -0500
++++ b/configure 2016-12-06 14:35:09.695069930 -0500
+@@ -25092,7 +25092,7 @@
+ CUPS_API_MAJOR=`echo $ECHO_N $CUPS_API_VERSION | awk -F. '{print $1}'`
+ CUPS_API_MINOR=`echo $ECHO_N $CUPS_API_VERSION | awk -F. '{print $2}'`
+
+- if test $CUPS_API_MAJOR -gt 1 -o \
++ if test $CUPS_API_MAJOR -lt 1 -o \
+ $CUPS_API_MAJOR -eq 1 -a $CUPS_API_MINOR -lt 2; then
+ as_fn_error $? "CUPS >= 1.2 not found" "$LINENO" 5
+ fi
diff --git a/Tools/gtk/patches/icudata-stdlibs.patch b/Tools/gtk/patches/icudata-stdlibs.patch
new file mode 100644
index 000000000..5e92bdec1
--- /dev/null
+++ b/Tools/gtk/patches/icudata-stdlibs.patch
@@ -0,0 +1,15 @@
+Index: icu-52~m1/source/config/mh-linux
+===================================================================
+--- icu-52~m1.orig/source/config/mh-linux 2013-09-14 18:53:23.284040467 -0400
++++ icu-52~m1/source/config/mh-linux 2013-09-14 18:53:23.284040467 -0400
+@@ -21,7 +21,9 @@
+ LD_RPATH_PRE = -Wl,-rpath,
+
+ ## These are the library specific LDFLAGS
+-LDFLAGSICUDT=-nodefaultlibs -nostdlib
++#LDFLAGSICUDT=-nodefaultlibs -nostdlib
++# Debian change: linking icudata as data only causes too many problems.
++LDFLAGSICUDT=
+
+ ## Compiler switch to embed a library name
+ # The initial tab in the next line is to prevent icu-config from reading it.
diff --git a/Tools/gtk/patches/libnice-0001-TURN-allow-REALM-to-be-empty.patch b/Tools/gtk/patches/libnice-0001-TURN-allow-REALM-to-be-empty.patch
new file mode 100644
index 000000000..7f52e4021
--- /dev/null
+++ b/Tools/gtk/patches/libnice-0001-TURN-allow-REALM-to-be-empty.patch
@@ -0,0 +1,50 @@
+From 0c55166a817ec51096460f789234ef49237000cc Mon Sep 17 00:00:00 2001
+From: Alessandro Decina <alessandro.d@gmail.com>
+Date: Thu, 24 Mar 2016 10:48:27 +1100
+Subject: [PATCH 1/2] TURN: allow REALM to be empty
+
+---
+ agent/conncheck.c | 6 ++----
+ stun/stunhmac.c | 6 ++++--
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/agent/conncheck.c b/agent/conncheck.c
+index 057fc81..97bf536 100644
+--- a/agent/conncheck.c
++++ b/agent/conncheck.c
+@@ -2768,13 +2768,11 @@ static gboolean priv_map_reply_to_relay_request (NiceAgent *agent, StunMessage *
+ agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
+ stun_message_get_class (resp) == STUN_ERROR &&
+ stun_message_find_error (resp, &code) ==
+- STUN_MESSAGE_RETURN_SUCCESS &&
+- recv_realm != NULL && recv_realm_len > 0) {
+-
++ STUN_MESSAGE_RETURN_SUCCESS) {
+ if (code == 438 ||
+ (code == 401 &&
+ !(recv_realm_len == sent_realm_len &&
+- sent_realm != NULL &&
++ recv_realm != NULL && sent_realm != NULL &&
+ memcmp (sent_realm, recv_realm, sent_realm_len) == 0))) {
+ d->stun_resp_msg = *resp;
+ memcpy (d->stun_resp_buffer, resp->buffer,
+diff --git a/stun/stunhmac.c b/stun/stunhmac.c
+index df5deb6..f73943f 100644
+--- a/stun/stunhmac.c
++++ b/stun/stunhmac.c
+@@ -90,8 +90,10 @@ static const uint8_t *priv_trim_var (const uint8_t *var, size_t *var_len)
+ ptr++;
+ (*var_len)--;
+ }
+- while(ptr[*var_len-1] == '"' ||
+- ptr[*var_len-1] == 0) {
++
++ while(*var_len > 0 &&
++ (ptr[*var_len-1] == '"' ||
++ ptr[*var_len-1] == 0)) {
+ (*var_len)--;
+ }
+
+--
+2.3.4
+
diff --git a/Tools/gtk/patches/libnice-0001-nicesrc-spin-the-agent-mainloop-in-a-separate-thread.patch b/Tools/gtk/patches/libnice-0001-nicesrc-spin-the-agent-mainloop-in-a-separate-thread.patch
new file mode 100644
index 000000000..6af57e8b2
--- /dev/null
+++ b/Tools/gtk/patches/libnice-0001-nicesrc-spin-the-agent-mainloop-in-a-separate-thread.patch
@@ -0,0 +1,253 @@
+From 3196a96a408a90f707dff3f31fa3d05d64aeb68a Mon Sep 17 00:00:00 2001
+From: Alessandro Decina <alessandro.d@gmail.com>
+Date: Tue, 13 Oct 2015 12:49:19 +1100
+Subject: [PATCH] nicesrc: spin the agent mainloop in a separate thread
+
+Don't run the mainloop from the srcpad task, since that can get blocked in the
+pipeline and cause unnecessary STUN retrasmissions (at best) and completely
+block the agent (at worst).
+---
+ gst/gstnicesrc.c | 158 ++++++++++++++++++++++++++++++++-----------------------
+ gst/gstnicesrc.h | 4 +-
+ 2 files changed, 93 insertions(+), 69 deletions(-)
+
+diff --git a/gst/gstnicesrc.c b/gst/gstnicesrc.c
+index d369e09..eb59fe9 100644
+--- a/gst/gstnicesrc.c
++++ b/gst/gstnicesrc.c
+@@ -48,6 +48,14 @@ GST_DEBUG_CATEGORY_STATIC (nicesrc_debug);
+
+ #define BUFFER_SIZE (65536)
+
++static gboolean
++gst_nice_src_start (
++ GstBaseSrc *basesrc);
++
++static gboolean
++gst_nice_src_stop (
++ GstBaseSrc *basesrc);
++
+ static GstFlowReturn
+ gst_nice_src_create (
+ GstPushSrc *basesrc,
+@@ -57,10 +65,6 @@ static gboolean
+ gst_nice_src_unlock (
+ GstBaseSrc *basesrc);
+
+-static gboolean
+-gst_nice_src_unlock_stop (
+- GstBaseSrc *basesrc);
+-
+ static void
+ gst_nice_src_set_property (
+ GObject *object,
+@@ -116,8 +120,9 @@ gst_nice_src_class_init (GstNiceSrcClass *klass)
+ gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_nice_src_create);
+
+ gstbasesrc_class = (GstBaseSrcClass *) klass;
++ gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_nice_src_start);
++ gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_nice_src_stop);
+ gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_nice_src_unlock);
+- gstbasesrc_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_nice_src_unlock_stop);
+
+ gobject_class = (GObjectClass *) klass;
+ gobject_class->set_property = gst_nice_src_set_property;
+@@ -179,9 +184,83 @@ gst_nice_src_init (GstNiceSrc *src)
+ src->component_id = 0;
+ src->mainctx = g_main_context_new ();
+ src->mainloop = g_main_loop_new (src->mainctx, FALSE);
+- src->unlocked = FALSE;
+- src->idle_source = NULL;
+ src->outbufs = g_queue_new ();
++ src->agent_io_thread = NULL;
++ g_cond_init (&src->outcond);
++}
++
++static gpointer
++gst_nice_src_agent_io_thread (gpointer data)
++{
++ GstNiceSrc *nicesrc = GST_NICE_SRC (data);
++
++ GST_INFO_OBJECT (nicesrc, "starting agent io thread");
++ g_main_loop_run (nicesrc->mainloop);
++ GST_INFO_OBJECT (nicesrc, "exiting agent io thread");
++
++ return NULL;
++}
++
++static gboolean
++main_loop_running_cb (gpointer data)
++{
++ GstNiceSrc *nicesrc = GST_NICE_SRC (data);
++
++ GST_OBJECT_LOCK (nicesrc);
++ /* _start() and _stop() could both be waiting for the mainloop to start so we
++ * need to broadcast */
++ g_cond_broadcast (&nicesrc->outcond);
++ GST_OBJECT_UNLOCK (nicesrc);
++
++ return FALSE;
++}
++
++static gboolean
++gst_nice_src_start (GstBaseSrc * basesrc)
++{
++ GstNiceSrc *nicesrc = GST_NICE_SRC (basesrc);
++ GSource *source;
++ gchar *thread_name;
++
++ GST_OBJECT_LOCK (nicesrc);
++ source = g_idle_source_new ();
++ g_source_set_callback (source,
++ (GSourceFunc) main_loop_running_cb, nicesrc, NULL);
++ g_source_attach (source, nicesrc->mainctx);
++ g_source_unref (source);
++
++ thread_name = g_strdup_printf ("%s:agent_io", GST_OBJECT_NAME (nicesrc));
++ nicesrc->agent_io_thread = g_thread_new (thread_name, gst_nice_src_agent_io_thread, nicesrc);
++ g_free (thread_name);
++ /* wait until the agent thread starts spinning the mainloop or _stop() is
++ * called */
++ while (GST_BASE_SRC_IS_STARTING (basesrc) &&
++ !g_main_loop_is_running (nicesrc->mainloop))
++ g_cond_wait (&nicesrc->outcond, GST_OBJECT_GET_LOCK (nicesrc));
++ GST_OBJECT_UNLOCK (nicesrc);
++
++ return TRUE;
++}
++
++static gboolean
++gst_nice_src_stop (GstBaseSrc * basesrc)
++{
++ GstNiceSrc *nicesrc = GST_NICE_SRC (basesrc);
++ GThread *agent_io_thread = NULL;
++
++ GST_OBJECT_LOCK (nicesrc);
++ /* here we wait for the agent thread created in _start() to be scheduled so
++ * that we don't risk calling _quit() first and then _run() on the mainloop */
++ while (!g_main_loop_is_running (nicesrc->mainloop))
++ g_cond_wait (&nicesrc->outcond, GST_OBJECT_GET_LOCK (nicesrc));
++ g_main_loop_quit (nicesrc->mainloop);
++ agent_io_thread = nicesrc->agent_io_thread;
++ nicesrc->agent_io_thread = NULL;
++ GST_OBJECT_UNLOCK (nicesrc);
++
++ g_thread_join (agent_io_thread);
++
++ return TRUE;
+ }
+
+ static void
+@@ -207,62 +286,17 @@ gst_nice_src_read_callback (NiceAgent *agent,
+ #endif
+ GST_OBJECT_LOCK (nicesrc);
+ g_queue_push_tail (nicesrc->outbufs, buffer);
+- g_main_loop_quit (nicesrc->mainloop);
++ g_cond_signal (&nicesrc->outcond);
+ GST_OBJECT_UNLOCK (nicesrc);
+ }
+
+ static gboolean
+-gst_nice_src_unlock_idler (gpointer data)
+-{
+- GstNiceSrc *nicesrc = GST_NICE_SRC (data);
+-
+- GST_OBJECT_LOCK (nicesrc);
+- if (nicesrc->unlocked)
+- g_main_loop_quit (nicesrc->mainloop);
+-
+- if (nicesrc->idle_source) {
+- g_source_destroy (nicesrc->idle_source);
+- g_source_unref (nicesrc->idle_source);
+- nicesrc->idle_source = NULL;
+- }
+- GST_OBJECT_UNLOCK (nicesrc);
+-
+- return FALSE;
+-}
+-
+-static gboolean
+ gst_nice_src_unlock (GstBaseSrc *src)
+ {
+ GstNiceSrc *nicesrc = GST_NICE_SRC (src);
+
+ GST_OBJECT_LOCK (src);
+- nicesrc->unlocked = TRUE;
+-
+- g_main_loop_quit (nicesrc->mainloop);
+-
+- if (!nicesrc->idle_source) {
+- nicesrc->idle_source = g_idle_source_new ();
+- g_source_set_priority (nicesrc->idle_source, G_PRIORITY_HIGH);
+- g_source_set_callback (nicesrc->idle_source, gst_nice_src_unlock_idler, src, NULL);
+- g_source_attach (nicesrc->idle_source, g_main_loop_get_context (nicesrc->mainloop));
+- }
+- GST_OBJECT_UNLOCK (src);
+-
+- return TRUE;
+-}
+-
+-static gboolean
+-gst_nice_src_unlock_stop (GstBaseSrc *src)
+-{
+- GstNiceSrc *nicesrc = GST_NICE_SRC (src);
+-
+- GST_OBJECT_LOCK (src);
+- nicesrc->unlocked = FALSE;
+- if (nicesrc->idle_source) {
+- g_source_destroy (nicesrc->idle_source);
+- g_source_unref(nicesrc->idle_source);
+- }
+- nicesrc->idle_source = NULL;
++ g_cond_signal (&nicesrc->outcond);
+ GST_OBJECT_UNLOCK (src);
+
+ return TRUE;
+@@ -278,19 +312,8 @@ gst_nice_src_create (
+ GST_LOG_OBJECT (nicesrc, "create called");
+
+ GST_OBJECT_LOCK (basesrc);
+- if (nicesrc->unlocked) {
+- GST_OBJECT_UNLOCK (basesrc);
+-#if GST_CHECK_VERSION (1,0,0)
+- return GST_FLOW_FLUSHING;
+-#else
+- return GST_FLOW_WRONG_STATE;
+-#endif
+- }
+- if (g_queue_is_empty (nicesrc->outbufs)) {
+- GST_OBJECT_UNLOCK (basesrc);
+- g_main_loop_run (nicesrc->mainloop);
+- GST_OBJECT_LOCK (basesrc);
+- }
++ if (g_queue_is_empty (nicesrc->outbufs))
++ g_cond_wait (&nicesrc->outcond, GST_OBJECT_GET_LOCK (nicesrc));
+
+ *buffer = g_queue_pop_head (nicesrc->outbufs);
+ GST_OBJECT_UNLOCK (basesrc);
+@@ -331,6 +354,7 @@ gst_nice_src_dispose (GObject *object)
+ g_queue_free (src->outbufs);
+ }
+ src->outbufs = NULL;
++ g_cond_clear (&src->outcond);
+
+ G_OBJECT_CLASS (gst_nice_src_parent_class)->dispose (object);
+ }
+diff --git a/gst/gstnicesrc.h b/gst/gstnicesrc.h
+index 5d3f554..2d9f674 100644
+--- a/gst/gstnicesrc.h
++++ b/gst/gstnicesrc.h
+@@ -68,8 +68,8 @@ struct _GstNiceSrc
+ GMainContext *mainctx;
+ GMainLoop *mainloop;
+ GQueue *outbufs;
+- gboolean unlocked;
+- GSource *idle_source;
++ GCond outcond;
++ GThread *agent_io_thread;
+ };
+
+ typedef struct _GstNiceSrcClass GstNiceSrcClass;
+--
+2.3.4
+
diff --git a/Tools/gtk/patches/librsvg-2.36.1-bump-up-config.guess-to-support-aarch64.patch b/Tools/gtk/patches/librsvg-2.36.1-bump-up-config.guess-to-support-aarch64.patch
new file mode 100644
index 000000000..a20af4ce1
--- /dev/null
+++ b/Tools/gtk/patches/librsvg-2.36.1-bump-up-config.guess-to-support-aarch64.patch
@@ -0,0 +1,1581 @@
+diff -ur librsvg-2.36.1-orig/config.guess librsvg-2.36.1/config.guess
+--- librsvg-2.36.1-orig/config.guess 2012-02-03 13:14:58.000000000 +0100
++++ librsvg-2.36.1/config.guess 2014-09-25 18:36:54.000000000 +0200
+@@ -1,14 +1,12 @@
+ #! /bin/sh
+ # Attempt to guess a canonical system name.
+-# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+-# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+-# Free Software Foundation, Inc.
++# Copyright 1992-2014 Free Software Foundation, Inc.
+
+-timestamp='2009-11-20'
++timestamp='2014-03-23'
+
+ # This file is free software; you can redistribute it and/or modify it
+ # under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
++# the Free Software Foundation; either version 3 of the License, or
+ # (at your option) any later version.
+ #
+ # This program is distributed in the hope that it will be useful, but
+@@ -17,26 +15,22 @@
+ # General Public License for more details.
+ #
+ # You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+-# 02110-1301, USA.
++# along with this program; if not, see <http://www.gnu.org/licenses/>.
+ #
+ # As a special exception to the GNU General Public License, if you
+ # distribute this file as part of a program that contains a
+ # configuration script generated by Autoconf, you may include it under
+-# the same distribution terms that you use for the rest of that program.
+-
+-
+-# Originally written by Per Bothner. Please send patches (context
+-# diff format) to <config-patches@gnu.org> and include a ChangeLog
+-# entry.
++# the same distribution terms that you use for the rest of that
++# program. This Exception is an additional permission under section 7
++# of the GNU General Public License, version 3 ("GPLv3").
+ #
+-# This script attempts to guess a canonical system name similar to
+-# config.sub. If it succeeds, it prints the system name on stdout, and
+-# exits with 0. Otherwise, it exits with 1.
++# Originally written by Per Bothner.
+ #
+ # You can get the latest version of this script from:
+ # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
++#
++# Please send patches with a ChangeLog entry to config-patches@gnu.org.
++
+
+ me=`echo "$0" | sed -e 's,.*/,,'`
+
+@@ -56,8 +50,7 @@
+ GNU config.guess ($timestamp)
+
+ Originally written by Per Bothner.
+-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+-2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
++Copyright 1992-2014 Free Software Foundation, Inc.
+
+ This is free software; see the source for copying conditions. There is NO
+ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+@@ -139,12 +132,33 @@
+ UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+ UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
++case "${UNAME_SYSTEM}" in
++Linux|GNU|GNU/*)
++ # If the system lacks a compiler, then just pick glibc.
++ # We could probably try harder.
++ LIBC=gnu
++
++ eval $set_cc_for_build
++ cat <<-EOF > $dummy.c
++ #include <features.h>
++ #if defined(__UCLIBC__)
++ LIBC=uclibc
++ #elif defined(__dietlibc__)
++ LIBC=dietlibc
++ #else
++ LIBC=gnu
++ #endif
++ EOF
++ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
++ ;;
++esac
++
+ # Note: order is significant - the case branches are not exclusive.
+
+ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+- # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
++ # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+@@ -180,7 +194,7 @@
+ fi
+ ;;
+ *)
+- os=netbsd
++ os=netbsd
+ ;;
+ esac
+ # The OS release
+@@ -201,6 +215,10 @@
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit ;;
++ *:Bitrig:*:*)
++ UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
++ echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
++ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+@@ -223,7 +241,7 @@
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+- UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
++ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+@@ -269,7 +287,10 @@
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+- exit ;;
++ # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
++ exitcode=$?
++ trap '' 0
++ exit $exitcode ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+@@ -295,12 +316,12 @@
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+- echo powerpc-ibm-os400
++ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit ;;
+- arm:riscos:*:*|arm:RISCOS:*:*)
++ arm*:riscos:*:*|arm*:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+@@ -394,23 +415,23 @@
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+- echo m68k-atari-mint${UNAME_RELEASE}
++ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+- exit ;;
++ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+- echo m68k-atari-mint${UNAME_RELEASE}
++ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+- echo m68k-milan-mint${UNAME_RELEASE}
+- exit ;;
++ echo m68k-milan-mint${UNAME_RELEASE}
++ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+- echo m68k-hades-mint${UNAME_RELEASE}
+- exit ;;
++ echo m68k-hades-mint${UNAME_RELEASE}
++ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+- echo m68k-unknown-mint${UNAME_RELEASE}
+- exit ;;
++ echo m68k-unknown-mint${UNAME_RELEASE}
++ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+@@ -480,8 +501,8 @@
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+- # DG/UX returns AViiON for all architectures
+- UNAME_PROCESSOR=`/usr/bin/uname -p`
++ # DG/UX returns AViiON for all architectures
++ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+@@ -494,7 +515,7 @@
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+- exit ;;
++ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+@@ -551,7 +572,7 @@
+ echo rs6000-ibm-aix3.2
+ fi
+ exit ;;
+- *:AIX:*:[456])
++ *:AIX:*:[4567])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+@@ -594,52 +615,52 @@
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+- sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+- case "${sc_cpu_version}" in
+- 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+- 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+- 532) # CPU_PA_RISC2_0
+- case "${sc_kernel_bits}" in
+- 32) HP_ARCH="hppa2.0n" ;;
+- 64) HP_ARCH="hppa2.0w" ;;
++ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
++ case "${sc_cpu_version}" in
++ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
++ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
++ 532) # CPU_PA_RISC2_0
++ case "${sc_kernel_bits}" in
++ 32) HP_ARCH="hppa2.0n" ;;
++ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+- esac ;;
+- esac
++ esac ;;
++ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+- sed 's/^ //' << EOF >$dummy.c
++ sed 's/^ //' << EOF >$dummy.c
++
++ #define _HPUX_SOURCE
++ #include <stdlib.h>
++ #include <unistd.h>
++
++ int main ()
++ {
++ #if defined(_SC_KERNEL_BITS)
++ long bits = sysconf(_SC_KERNEL_BITS);
++ #endif
++ long cpu = sysconf (_SC_CPU_VERSION);
+
+- #define _HPUX_SOURCE
+- #include <stdlib.h>
+- #include <unistd.h>
+-
+- int main ()
+- {
+- #if defined(_SC_KERNEL_BITS)
+- long bits = sysconf(_SC_KERNEL_BITS);
+- #endif
+- long cpu = sysconf (_SC_CPU_VERSION);
+-
+- switch (cpu)
+- {
+- case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+- case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+- case CPU_PA_RISC2_0:
+- #if defined(_SC_KERNEL_BITS)
+- switch (bits)
+- {
+- case 64: puts ("hppa2.0w"); break;
+- case 32: puts ("hppa2.0n"); break;
+- default: puts ("hppa2.0"); break;
+- } break;
+- #else /* !defined(_SC_KERNEL_BITS) */
+- puts ("hppa2.0"); break;
+- #endif
+- default: puts ("hppa1.0"); break;
+- }
+- exit (0);
+- }
++ switch (cpu)
++ {
++ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
++ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
++ case CPU_PA_RISC2_0:
++ #if defined(_SC_KERNEL_BITS)
++ switch (bits)
++ {
++ case 64: puts ("hppa2.0w"); break;
++ case 32: puts ("hppa2.0n"); break;
++ default: puts ("hppa2.0"); break;
++ } break;
++ #else /* !defined(_SC_KERNEL_BITS) */
++ puts ("hppa2.0"); break;
++ #endif
++ default: puts ("hppa1.0"); break;
++ }
++ exit (0);
++ }
+ EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+@@ -730,22 +751,22 @@
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+- exit ;;
++ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+- exit ;;
++ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+- exit ;;
++ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+- exit ;;
++ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+- exit ;;
++ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+@@ -769,14 +790,14 @@
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+- FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+- echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+- exit ;;
++ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
++ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
++ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
++ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+- FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+- echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
++ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
++ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
++ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+@@ -788,30 +809,35 @@
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+- case ${UNAME_MACHINE} in
+- pc98)
+- echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
++ UNAME_PROCESSOR=`/usr/bin/uname -p`
++ case ${UNAME_PROCESSOR} in
+ amd64)
+ echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ *)
+- echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
++ echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ esac
+ exit ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit ;;
++ *:MINGW64*:*)
++ echo ${UNAME_MACHINE}-pc-mingw64
++ exit ;;
+ *:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit ;;
++ *:MSYS*:*)
++ echo ${UNAME_MACHINE}-pc-msys
++ exit ;;
+ i*:windows32*:*)
+- # uname -m includes "-pc" on this system.
+- echo ${UNAME_MACHINE}-mingw32
++ # uname -m includes "-pc" on this system.
++ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit ;;
+ *:Interix*:*)
+- case ${UNAME_MACHINE} in
++ case ${UNAME_MACHINE} in
+ x86)
+ echo i586-pc-interix${UNAME_RELEASE}
+ exit ;;
+@@ -848,15 +874,22 @@
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+- echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
++ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+- echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
++ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+ exit ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit ;;
++ aarch64:Linux:*:*)
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
++ exit ;;
++ aarch64_be:Linux:*:*)
++ UNAME_MACHINE=aarch64_be
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
++ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+@@ -866,52 +899,56 @@
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+- esac
++ esac
+ objdump --private-headers /bin/sh | grep -q ld.so.1
+- if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+- echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
++ if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
++ exit ;;
++ arc:Linux:*:* | arceb:Linux:*:*)
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ arm*:Linux:*:*)
+ eval $set_cc_for_build
+ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_EABI__
+ then
+- echo ${UNAME_MACHINE}-unknown-linux-gnu
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ else
+- echo ${UNAME_MACHINE}-unknown-linux-gnueabi
++ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
++ | grep -q __ARM_PCS_VFP
++ then
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
++ else
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
++ fi
+ fi
+ exit ;;
+ avr32*:Linux:*:*)
+- echo ${UNAME_MACHINE}-unknown-linux-gnu
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ cris:Linux:*:*)
+- echo cris-axis-linux-gnu
++ echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+ exit ;;
+ crisv32:Linux:*:*)
+- echo crisv32-axis-linux-gnu
++ echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+ exit ;;
+ frv:Linux:*:*)
+- echo frv-unknown-linux-gnu
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
++ exit ;;
++ hexagon:Linux:*:*)
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ i*86:Linux:*:*)
+- LIBC=gnu
+- eval $set_cc_for_build
+- sed 's/^ //' << EOF >$dummy.c
+- #ifdef __dietlibc__
+- LIBC=dietlibc
+- #endif
+-EOF
+- eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+- echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
++ echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+ exit ;;
+ ia64:Linux:*:*)
+- echo ${UNAME_MACHINE}-unknown-linux-gnu
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ m32r*:Linux:*:*)
+- echo ${UNAME_MACHINE}-unknown-linux-gnu
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ m68*:Linux:*:*)
+- echo ${UNAME_MACHINE}-unknown-linux-gnu
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ mips:Linux:*:* | mips64:Linux:*:*)
+ eval $set_cc_for_build
+@@ -930,51 +967,63 @@
+ #endif
+ EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+- test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
++ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
+ ;;
+- or32:Linux:*:*)
+- echo or32-unknown-linux-gnu
++ openrisc*:Linux:*:*)
++ echo or1k-unknown-linux-${LIBC}
++ exit ;;
++ or32:Linux:*:* | or1k*:Linux:*:*)
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ padre:Linux:*:*)
+- echo sparc-unknown-linux-gnu
++ echo sparc-unknown-linux-${LIBC}
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+- echo hppa64-unknown-linux-gnu
++ echo hppa64-unknown-linux-${LIBC}
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+- PA7*) echo hppa1.1-unknown-linux-gnu ;;
+- PA8*) echo hppa2.0-unknown-linux-gnu ;;
+- *) echo hppa-unknown-linux-gnu ;;
++ PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
++ PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
++ *) echo hppa-unknown-linux-${LIBC} ;;
+ esac
+ exit ;;
+ ppc64:Linux:*:*)
+- echo powerpc64-unknown-linux-gnu
++ echo powerpc64-unknown-linux-${LIBC}
+ exit ;;
+ ppc:Linux:*:*)
+- echo powerpc-unknown-linux-gnu
++ echo powerpc-unknown-linux-${LIBC}
++ exit ;;
++ ppc64le:Linux:*:*)
++ echo powerpc64le-unknown-linux-${LIBC}
++ exit ;;
++ ppcle:Linux:*:*)
++ echo powerpcle-unknown-linux-${LIBC}
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+- echo ${UNAME_MACHINE}-ibm-linux
++ echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
+ exit ;;
+ sh64*:Linux:*:*)
+- echo ${UNAME_MACHINE}-unknown-linux-gnu
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ sh*:Linux:*:*)
+- echo ${UNAME_MACHINE}-unknown-linux-gnu
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+- echo ${UNAME_MACHINE}-unknown-linux-gnu
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
++ exit ;;
++ tile*:Linux:*:*)
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ vax:Linux:*:*)
+- echo ${UNAME_MACHINE}-dec-linux-gnu
++ echo ${UNAME_MACHINE}-dec-linux-${LIBC}
+ exit ;;
+ x86_64:Linux:*:*)
+- echo x86_64-unknown-linux-gnu
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ xtensa*:Linux:*:*)
+- echo ${UNAME_MACHINE}-unknown-linux-gnu
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+@@ -983,11 +1032,11 @@
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+- # Unixware is an offshoot of SVR4, but it has its own version
+- # number series starting with 2...
+- # I am not positive that other SVR4 systems won't match this,
++ # Unixware is an offshoot of SVR4, but it has its own version
++ # number series starting with 2...
++ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+- # Use sysv4.2uw... so that sysv4* matches it.
++ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit ;;
+ i*86:OS/2:*:*)
+@@ -1019,7 +1068,7 @@
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+- # UnixWare 7.x, OpenUNIX and OpenServer 6.
++ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+@@ -1047,13 +1096,13 @@
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+- # uname -m prints for DJGPP always 'pc', but it prints nothing about
+- # the processor, so we play safe by assuming i586.
++ # uname -m prints for DJGPP always 'pc', but it prints nothing about
++ # the processor, so we play safe by assuming i586.
+ # Note: whatever this is, it MUST be the same as what config.sub
+ # prints for the "djgpp" host, or else GDB configury will decide that
+ # this is a cross-build.
+ echo i586-pc-msdosdjgpp
+- exit ;;
++ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+@@ -1088,8 +1137,8 @@
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+- /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+- && { echo i486-ncr-sysv4; exit; } ;;
++ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
++ && { echo i486-ncr-sysv4; exit; } ;;
+ NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+ OS_REL='.3'
+ test -r /etc/.relid \
+@@ -1132,10 +1181,10 @@
+ echo ns32k-sni-sysv
+ fi
+ exit ;;
+- PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+- # says <Richard.M.Bartel@ccMail.Census.GOV>
+- echo i586-unisys-sysv4
+- exit ;;
++ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
++ # says <Richard.M.Bartel@ccMail.Census.GOV>
++ echo i586-unisys-sysv4
++ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+@@ -1161,11 +1210,11 @@
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+- echo mips-nec-sysv${UNAME_RELEASE}
++ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+- echo mips-unknown-sysv${UNAME_RELEASE}
++ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+- exit ;;
++ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+@@ -1178,6 +1227,9 @@
+ BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
+ echo i586-pc-haiku
+ exit ;;
++ x86_64:Haiku:*:*)
++ echo x86_64-unknown-haiku
++ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit ;;
+@@ -1204,19 +1256,31 @@
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+- case $UNAME_PROCESSOR in
+- i386)
+- eval $set_cc_for_build
+- if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+- if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+- (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+- grep IS_64BIT_ARCH >/dev/null
+- then
+- UNAME_PROCESSOR="x86_64"
+- fi
+- fi ;;
+- unknown) UNAME_PROCESSOR=powerpc ;;
+- esac
++ eval $set_cc_for_build
++ if test "$UNAME_PROCESSOR" = unknown ; then
++ UNAME_PROCESSOR=powerpc
++ fi
++ if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
++ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
++ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
++ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
++ grep IS_64BIT_ARCH >/dev/null
++ then
++ case $UNAME_PROCESSOR in
++ i386) UNAME_PROCESSOR=x86_64 ;;
++ powerpc) UNAME_PROCESSOR=powerpc64 ;;
++ esac
++ fi
++ fi
++ elif test "$UNAME_PROCESSOR" = i386 ; then
++ # Avoid executing cc on OS X 10.9, as it ships with a stub
++ # that puts up a graphical alert prompting to install
++ # developer tools. Any system running Mac OS X 10.7 or
++ # later (Darwin 11 and later) is required to have a 64-bit
++ # processor. This is not true of the ARM version of Darwin
++ # that Apple uses in portable devices.
++ UNAME_PROCESSOR=x86_64
++ fi
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+@@ -1230,7 +1294,10 @@
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+- NSE-?:NONSTOP_KERNEL:*:*)
++ NEO-?:NONSTOP_KERNEL:*:*)
++ echo neo-tandem-nsk${UNAME_RELEASE}
++ exit ;;
++ NSE-*:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSR-?:NONSTOP_KERNEL:*:*)
+@@ -1275,13 +1342,13 @@
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+- echo mips-sei-seiux${UNAME_RELEASE}
++ echo mips-sei-seiux${UNAME_RELEASE}
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+- UNAME_MACHINE=`(uname -p) 2>/dev/null`
++ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+@@ -1299,158 +1366,10 @@
+ i*86:AROS:*:*)
+ echo ${UNAME_MACHINE}-pc-aros
+ exit ;;
+-esac
+-
+-#echo '(No uname command or uname output not recognized.)' 1>&2
+-#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+-
+-eval $set_cc_for_build
+-cat >$dummy.c <<EOF
+-#ifdef _SEQUENT_
+-# include <sys/types.h>
+-# include <sys/utsname.h>
+-#endif
+-main ()
+-{
+-#if defined (sony)
+-#if defined (MIPSEB)
+- /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+- I don't know.... */
+- printf ("mips-sony-bsd\n"); exit (0);
+-#else
+-#include <sys/param.h>
+- printf ("m68k-sony-newsos%s\n",
+-#ifdef NEWSOS4
+- "4"
+-#else
+- ""
+-#endif
+- ); exit (0);
+-#endif
+-#endif
+-
+-#if defined (__arm) && defined (__acorn) && defined (__unix)
+- printf ("arm-acorn-riscix\n"); exit (0);
+-#endif
+-
+-#if defined (hp300) && !defined (hpux)
+- printf ("m68k-hp-bsd\n"); exit (0);
+-#endif
+-
+-#if defined (NeXT)
+-#if !defined (__ARCHITECTURE__)
+-#define __ARCHITECTURE__ "m68k"
+-#endif
+- int version;
+- version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+- if (version < 4)
+- printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+- else
+- printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+- exit (0);
+-#endif
+-
+-#if defined (MULTIMAX) || defined (n16)
+-#if defined (UMAXV)
+- printf ("ns32k-encore-sysv\n"); exit (0);
+-#else
+-#if defined (CMU)
+- printf ("ns32k-encore-mach\n"); exit (0);
+-#else
+- printf ("ns32k-encore-bsd\n"); exit (0);
+-#endif
+-#endif
+-#endif
+-
+-#if defined (__386BSD__)
+- printf ("i386-pc-bsd\n"); exit (0);
+-#endif
+-
+-#if defined (sequent)
+-#if defined (i386)
+- printf ("i386-sequent-dynix\n"); exit (0);
+-#endif
+-#if defined (ns32000)
+- printf ("ns32k-sequent-dynix\n"); exit (0);
+-#endif
+-#endif
+-
+-#if defined (_SEQUENT_)
+- struct utsname un;
+-
+- uname(&un);
+-
+- if (strncmp(un.version, "V2", 2) == 0) {
+- printf ("i386-sequent-ptx2\n"); exit (0);
+- }
+- if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+- printf ("i386-sequent-ptx1\n"); exit (0);
+- }
+- printf ("i386-sequent-ptx\n"); exit (0);
+-
+-#endif
+-
+-#if defined (vax)
+-# if !defined (ultrix)
+-# include <sys/param.h>
+-# if defined (BSD)
+-# if BSD == 43
+- printf ("vax-dec-bsd4.3\n"); exit (0);
+-# else
+-# if BSD == 199006
+- printf ("vax-dec-bsd4.3reno\n"); exit (0);
+-# else
+- printf ("vax-dec-bsd\n"); exit (0);
+-# endif
+-# endif
+-# else
+- printf ("vax-dec-bsd\n"); exit (0);
+-# endif
+-# else
+- printf ("vax-dec-ultrix\n"); exit (0);
+-# endif
+-#endif
+-
+-#if defined (alliant) && defined (i860)
+- printf ("i860-alliant-bsd\n"); exit (0);
+-#endif
+-
+- exit (1);
+-}
+-EOF
+-
+-$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+- { echo "$SYSTEM_NAME"; exit; }
+-
+-# Apollos put the system type in the environment.
+-
+-test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+-
+-# Convex versions that predate uname can use getsysinfo(1)
+-
+-if [ -x /usr/convex/getsysinfo ]
+-then
+- case `getsysinfo -f cpu_type` in
+- c1*)
+- echo c1-convex-bsd
+- exit ;;
+- c2*)
+- if getsysinfo -f scalar_acc
+- then echo c32-convex-bsd
+- else echo c2-convex-bsd
+- fi
++ x86_64:VMkernel:*:*)
++ echo ${UNAME_MACHINE}-unknown-esx
+ exit ;;
+- c34*)
+- echo c34-convex-bsd
+- exit ;;
+- c38*)
+- echo c38-convex-bsd
+- exit ;;
+- c4*)
+- echo c4-convex-bsd
+- exit ;;
+- esac
+-fi
++esac
+
+ cat >&2 <<EOF
+ $0: unable to guess system type
+diff -ur librsvg-2.36.1-orig/config.sub librsvg-2.36.1/config.sub
+--- librsvg-2.36.1-orig/config.sub 2012-02-03 13:14:58.000000000 +0100
++++ librsvg-2.36.1/config.sub 2014-09-25 18:37:12.000000000 +0200
+@@ -1,38 +1,31 @@
+ #! /bin/sh
+ # Configuration validation subroutine script.
+-# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+-# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+-# Free Software Foundation, Inc.
+-
+-timestamp='2009-11-20'
+-
+-# This file is (in principle) common to ALL GNU software.
+-# The presence of a machine in this file suggests that SOME GNU software
+-# can handle that machine. It does not imply ALL GNU software can.
+-#
+-# This file is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
++# Copyright 1992-2014 Free Software Foundation, Inc.
++
++timestamp='2014-09-11'
++
++# This file is free software; you can redistribute it and/or modify it
++# under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 3 of the License, or
+ # (at your option) any later version.
+ #
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-# GNU General Public License for more details.
++# This program is distributed in the hope that it will be useful, but
++# WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++# General Public License for more details.
+ #
+ # You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+-# 02110-1301, USA.
++# along with this program; if not, see <http://www.gnu.org/licenses/>.
+ #
+ # As a special exception to the GNU General Public License, if you
+ # distribute this file as part of a program that contains a
+ # configuration script generated by Autoconf, you may include it under
+-# the same distribution terms that you use for the rest of that program.
++# the same distribution terms that you use for the rest of that
++# program. This Exception is an additional permission under section 7
++# of the GNU General Public License, version 3 ("GPLv3").
+
+
+-# Please send patches to <config-patches@gnu.org>. Submit a context
+-# diff and a properly formatted GNU ChangeLog entry.
++# Please send patches with a ChangeLog entry to config-patches@gnu.org.
+ #
+ # Configuration subroutine to validate and canonicalize a configuration type.
+ # Supply the specified configuration type as an argument.
+@@ -75,8 +68,7 @@
+ version="\
+ GNU config.sub ($timestamp)
+
+-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+-2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
++Copyright 1992-2014 Free Software Foundation, Inc.
+
+ This is free software; see the source for copying conditions. There is NO
+ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+@@ -123,13 +115,18 @@
+ # Here we must recognize all the valid KERNEL-OS combinations.
+ maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+ case $maybe_os in
+- nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+- uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
++ nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
++ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
++ knetbsd*-gnu* | netbsd*-gnu* | \
+ kopensolaris*-gnu* | \
+ storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
++ android-linux)
++ os=-linux-android
++ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
++ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+@@ -152,12 +149,12 @@
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+- -apple | -axis | -knuth | -cray | -microblaze)
++ -apple | -axis | -knuth | -cray | -microblaze*)
+ os=
+ basic_machine=$1
+ ;;
+- -bluegene*)
+- os=-cnk
++ -bluegene*)
++ os=-cnk
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+@@ -173,10 +170,10 @@
+ os=-chorusos
+ basic_machine=$1
+ ;;
+- -chorusrdb)
+- os=-chorusrdb
++ -chorusrdb)
++ os=-chorusrdb
+ basic_machine=$1
+- ;;
++ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+@@ -221,6 +218,12 @@
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
++ -lynx*178)
++ os=-lynxos178
++ ;;
++ -lynx*5)
++ os=-lynxos5
++ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+@@ -245,20 +248,28 @@
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
++ | aarch64 | aarch64_be \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+- | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
++ | arc | arceb \
++ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
++ | avr | avr32 \
++ | be32 | be64 \
+ | bfin \
+- | c4x | clipper \
++ | c4x | c8051 | clipper \
+ | d10v | d30v | dlx | dsp16xx \
++ | epiphany \
+ | fido | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
++ | hexagon \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
++ | k1om \
++ | le32 | le64 \
+ | lm32 \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+- | maxq | mb | microblaze | mcore | mep | metag \
++ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+@@ -272,38 +283,51 @@
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
++ | mipsisa32r6 | mipsisa32r6el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
++ | mipsisa64r6 | mipsisa64r6el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
++ | mipsr5900 | mipsr5900el \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | moxie \
+ | mt \
+ | msp430 \
+- | nios | nios2 \
++ | nds32 | nds32le | nds32be \
++ | nios | nios2 | nios2eb | nios2el \
+ | ns16k | ns32k \
+- | or32 \
++ | open8 | or1k | or1knd | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+- | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
++ | powerpc | powerpc64 | powerpc64le | powerpcle \
+ | pyramid \
+- | rx \
++ | riscv32 | riscv64 \
++ | rl78 | rx \
+ | score \
+ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+- | spu | strongarm \
+- | tahoe | thumb | tic4x | tic80 | tron \
++ | spu \
++ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+ | ubicom32 \
+- | v850 | v850e \
++ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+ | we32k \
+- | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
++ | x86 | xc16x | xstormy16 | xtensa \
+ | z8k | z80)
+ basic_machine=$basic_machine-unknown
+ ;;
+- m6811 | m68hc11 | m6812 | m68hc12 | picochip)
+- # Motorola 68HC11/12.
++ c54x)
++ basic_machine=tic54x-unknown
++ ;;
++ c55x)
++ basic_machine=tic55x-unknown
++ ;;
++ c6x)
++ basic_machine=tic6x-unknown
++ ;;
++ m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+@@ -313,6 +337,21 @@
+ basic_machine=mt-unknown
+ ;;
+
++ strongarm | thumb | xscale)
++ basic_machine=arm-unknown
++ ;;
++ xgate)
++ basic_machine=$basic_machine-unknown
++ os=-none
++ ;;
++ xscaleeb)
++ basic_machine=armeb-unknown
++ ;;
++
++ xscaleel)
++ basic_machine=armel-unknown
++ ;;
++
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+@@ -327,25 +366,31 @@
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
++ | aarch64-* | aarch64_be-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+- | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
++ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* | avr32-* \
++ | be32-* | be64-* \
+ | bfin-* | bs2000-* \
+- | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+- | clipper-* | craynv-* | cydra-* \
++ | c[123]* | c30-* | [cjt]90-* | c4x-* \
++ | c8051-* | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
++ | hexagon-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
++ | k1om-* \
++ | le32-* | le64-* \
+ | lm32-* \
+ | m32c-* | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+- | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
++ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
++ | microblaze-* | microblazeel-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+@@ -359,33 +404,41 @@
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
++ | mipsisa32r6-* | mipsisa32r6el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
++ | mipsisa64r6-* | mipsisa64r6el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
++ | mipsr5900-* | mipsr5900el-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | mt-* \
+ | msp430-* \
+- | nios-* | nios2-* \
++ | nds32-* | nds32le-* | nds32be-* \
++ | nios-* | nios2-* | nios2eb-* | nios2el-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
++ | open8-* \
++ | or1k*-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+- | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
++ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+ | pyramid-* \
+- | romp-* | rs6000-* | rx-* \
++ | rl78-* | romp-* | rs6000-* | rx-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+- | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+- | tahoe-* | thumb-* \
+- | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \
++ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
++ | tahoe-* \
++ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
++ | tile*-* \
+ | tron-* \
+ | ubicom32-* \
+- | v850-* | v850e-* | vax-* \
++ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
++ | vax-* \
+ | we32k-* \
+- | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
++ | x86-* | x86_64-* | xc16x-* | xps100-* \
+ | xstormy16-* | xtensa*-* \
+ | ymp-* \
+ | z8k-* | z80-*)
+@@ -410,7 +463,7 @@
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+- abacus)
++ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+@@ -480,11 +533,20 @@
+ basic_machine=powerpc-ibm
+ os=-cnk
+ ;;
++ c54x-*)
++ basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
++ ;;
++ c55x-*)
++ basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
++ ;;
++ c6x-*)
++ basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
++ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+- cegcc)
++ cegcc)
+ basic_machine=arm-unknown
+ os=-cegcc
+ ;;
+@@ -516,7 +578,7 @@
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+- cr16)
++ cr16 | cr16-*)
+ basic_machine=cr16-unknown
+ os=-elf
+ ;;
+@@ -674,7 +736,6 @@
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+-# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+@@ -732,11 +793,15 @@
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+- microblaze)
++ microblaze*)
+ basic_machine=microblaze-xilinx
+ ;;
++ mingw64)
++ basic_machine=x86_64-pc
++ os=-mingw64
++ ;;
+ mingw32)
+- basic_machine=i386-pc
++ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ mingw32ce)
+@@ -764,6 +829,10 @@
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
++ moxiebox)
++ basic_machine=moxie-unknown
++ os=-moxiebox
++ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+@@ -771,10 +840,18 @@
+ ms1-*)
+ basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+ ;;
++ msys)
++ basic_machine=i686-pc
++ os=-msys
++ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
++ nacl)
++ basic_machine=le32-unknown
++ os=-nacl
++ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+@@ -839,6 +916,12 @@
+ np1)
+ basic_machine=np1-gould
+ ;;
++ neo-tandem)
++ basic_machine=neo-tandem
++ ;;
++ nse-tandem)
++ basic_machine=nse-tandem
++ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+@@ -921,9 +1004,10 @@
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+- ppc) basic_machine=powerpc-unknown
++ ppc | ppcbe) basic_machine=powerpc-unknown
+ ;;
+- ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
++ ppc-* | ppcbe-*)
++ basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+@@ -948,7 +1032,11 @@
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+- rdos)
++ rdos | rdos64)
++ basic_machine=x86_64-pc
++ os=-rdos
++ ;;
++ rdos32)
+ basic_machine=i386-pc
+ os=-rdos
+ ;;
+@@ -1017,6 +1105,9 @@
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
++ strongarm-* | thumb-*)
++ basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
++ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+@@ -1073,20 +1164,8 @@
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+- tic54x | c54x*)
+- basic_machine=tic54x-unknown
+- os=-coff
+- ;;
+- tic55x | c55x*)
+- basic_machine=tic55x-unknown
+- os=-coff
+- ;;
+- tic6x | c6x*)
+- basic_machine=tic6x-unknown
+- os=-coff
+- ;;
+ tile*)
+- basic_machine=tile-unknown
++ basic_machine=$basic_machine-unknown
+ os=-linux-gnu
+ ;;
+ tx39)
+@@ -1156,6 +1235,9 @@
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
++ xscale-* | xscalee[bl]-*)
++ basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
++ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+@@ -1253,11 +1335,11 @@
+ if [ x"$os" != x"" ]
+ then
+ case $os in
+- # First match some system type aliases
+- # that might get confused with valid system types.
++ # First match some system type aliases
++ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+- -auroraux)
+- os=-auroraux
++ -auroraux)
++ os=-auroraux
+ ;;
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+@@ -1281,28 +1363,29 @@
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+- | -sym* | -kopensolaris* \
++ | -sym* | -kopensolaris* | -plan9* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* | -aros* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+- | -openbsd* | -solidbsd* \
++ | -bitrig* | -openbsd* | -solidbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* | -cegcc* \
+- | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+- | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+- | -uxpv* | -beos* | -mpeix* | -udk* \
++ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
++ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
++ | -linux-newlib* | -linux-musl* | -linux-uclibc* \
++ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+- | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
++ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+@@ -1341,7 +1424,7 @@
+ -opened*)
+ os=-openedition
+ ;;
+- -os400*)
++ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+@@ -1390,7 +1473,7 @@
+ -sinix*)
+ os=-sysv4
+ ;;
+- -tpf*)
++ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+@@ -1426,15 +1509,14 @@
+ -aros*)
+ os=-aros
+ ;;
+- -kaos*)
+- os=-kaos
+- ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -dicos*)
+ os=-dicos
+ ;;
++ -nacl*)
++ ;;
+ -none)
+ ;;
+ *)
+@@ -1457,10 +1539,10 @@
+ # system, and we'll never get to this point.
+
+ case $basic_machine in
+- score-*)
++ score-*)
+ os=-elf
+ ;;
+- spu-*)
++ spu-*)
+ os=-elf
+ ;;
+ *-acorn)
+@@ -1472,8 +1554,23 @@
+ arm*-semi)
+ os=-aout
+ ;;
+- c4x-* | tic4x-*)
+- os=-coff
++ c4x-* | tic4x-*)
++ os=-coff
++ ;;
++ c8051-*)
++ os=-elf
++ ;;
++ hexagon-*)
++ os=-elf
++ ;;
++ tic54x-*)
++ os=-coff
++ ;;
++ tic55x-*)
++ os=-coff
++ ;;
++ tic6x-*)
++ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+@@ -1493,14 +1590,11 @@
+ ;;
+ m68000-sun)
+ os=-sunos3
+- # This also exists in the configure program, but was not the
+- # default.
+- # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+- mep-*)
++ mep-*)
+ os=-elf
+ ;;
+ mips*-cisco)
+@@ -1527,7 +1621,7 @@
+ *-ibm)
+ os=-aix
+ ;;
+- *-knuth)
++ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
diff --git a/Tools/gtk/patches/libsoup-auth-Fix-async-authentication-when-flag-SOUP_MESSAGE.patch b/Tools/gtk/patches/libsoup-auth-Fix-async-authentication-when-flag-SOUP_MESSAGE.patch
new file mode 100644
index 000000000..67545df38
--- /dev/null
+++ b/Tools/gtk/patches/libsoup-auth-Fix-async-authentication-when-flag-SOUP_MESSAGE.patch
@@ -0,0 +1,130 @@
+From afee3002ff45b7a00df3d6804fa7d329b907d361 Mon Sep 17 00:00:00 2001
+From: Carlos Garcia Campos <cgarcia@igalia.com>
+Date: Mon, 30 Jan 2017 13:57:12 +0100
+Subject: [PATCH 1/2] auth: Fix async authentication when flag
+ SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE is used
+
+When the flag SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE is used, it's not possible
+to successfully authenticate, and SOUP_STATUS_UNAUTHORIZED is always
+returned even when soup_auth_autenticate was called with the right
+credentials. This happens because we set the auth on the soup message right
+after emitting the authenticate signal only if it was authenticated. If the
+signal pauses the message, the auth will no longer be associated to the message,
+and not cached either because flag SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE is
+present. Since we always check if the auth returned by
+soup_auth_get_message is ready before trying to use it, we can simply
+always set the auth on the mssage right after emitting the authenticate
+signal even if it was not authenticated yet. If it's eventually
+authenticated then got-body callback will check it's ready to re-queue
+the message as expected.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=777936
+---
+ libsoup/soup-auth-manager.c | 4 +--
+ tests/auth-test.c | 61 +++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 63 insertions(+), 2 deletions(-)
+
+diff --git a/libsoup/soup-auth-manager.c b/libsoup/soup-auth-manager.c
+index 704661bc..9ff446cc 100644
+--- a/libsoup/soup-auth-manager.c
++++ b/libsoup/soup-auth-manager.c
+@@ -625,7 +625,7 @@ auth_got_headers (SoupMessage *msg, gpointer manager)
+ /* If we need to authenticate, try to do it. */
+ authenticate_auth (manager, auth, msg,
+ prior_auth_failed, FALSE, TRUE);
+- soup_message_set_auth (msg, soup_auth_is_ready (auth, msg) ? auth : NULL);
++ soup_message_set_auth (msg, auth);
+ g_object_unref (auth);
+ g_mutex_unlock (&priv->lock);
+ }
+@@ -689,7 +689,7 @@ proxy_auth_got_headers (SoupMessage *msg, gpointer manager)
+ /* If we need to authenticate, try to do it. */
+ authenticate_auth (manager, auth, msg,
+ prior_auth_failed, TRUE, TRUE);
+- soup_message_set_proxy_auth (msg, soup_auth_is_ready (auth, msg) ? auth : NULL);
++ soup_message_set_proxy_auth (msg, auth);
+ g_object_unref (auth);
+ g_mutex_unlock (&priv->lock);
+ }
+diff --git a/tests/auth-test.c b/tests/auth-test.c
+index b674c61c..23e22133 100644
+--- a/tests/auth-test.c
++++ b/tests/auth-test.c
+@@ -1336,6 +1336,66 @@ do_message_do_not_use_auth_cache_test (void)
+ }
+
+ static void
++async_no_auth_cache_authenticate (SoupSession *session, SoupMessage *msg,
++ SoupAuth *auth, gboolean retrying, SoupAuth **auth_out)
++{
++ debug_printf (1, " async_no_auth_cache_authenticate\n");
++
++ soup_session_pause_message (session, msg);
++ *auth_out = g_object_ref (auth);
++ g_main_loop_quit (loop);
++}
++
++static void
++async_no_auth_cache_finished (SoupSession *session, SoupMessage *msg, gpointer user_data)
++{
++ debug_printf (1, " async_no_auth_cache_finished\n");
++
++ g_main_loop_quit (loop);
++}
++
++static void
++do_async_message_do_not_use_auth_cache_test (void)
++{
++ SoupSession *session;
++ SoupMessage *msg;
++ char *uri;
++ SoupAuth *auth = NULL;
++ SoupMessageFlags flags;
++
++ SOUP_TEST_SKIP_IF_NO_APACHE;
++
++ loop = g_main_loop_new (NULL, TRUE);
++ session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
++ uri = g_strconcat (base_uri, "Basic/realm1/", NULL);
++
++ msg = soup_message_new ("GET", uri);
++ g_free (uri);
++ g_signal_connect (session, "authenticate",
++ G_CALLBACK (async_no_auth_cache_authenticate), &auth);
++ flags = soup_message_get_flags (msg);
++ soup_message_set_flags (msg, flags | SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE);
++ g_object_ref (msg);
++ soup_session_queue_message (session, msg, async_no_auth_cache_finished, NULL);
++ g_main_loop_run (loop);
++
++ soup_test_assert_message_status (msg, SOUP_STATUS_UNAUTHORIZED);
++
++ soup_test_assert (auth, "msg didn't get authenticate signal");
++ soup_auth_authenticate (auth, "user1", "realm1");
++ g_object_unref (auth);
++
++ soup_session_unpause_message (session, msg);
++ g_main_loop_run (loop);
++
++ soup_test_assert_message_status (msg, SOUP_STATUS_OK);
++
++ soup_test_session_abort_unref (session);
++ g_object_unref (msg);
++ g_main_loop_unref (loop);
++}
++
++static void
+ has_authorization_header_authenticate (SoupSession *session, SoupMessage *msg,
+ SoupAuth *auth, gboolean retrying, gpointer data)
+ {
+@@ -1432,6 +1492,7 @@ main (int argc, char **argv)
+ g_test_add_func ("/auth/disappearing-auth", do_disappearing_auth_test);
+ g_test_add_func ("/auth/clear-credentials", do_clear_credentials_test);
+ g_test_add_func ("/auth/message-do-not-use-auth-cache", do_message_do_not_use_auth_cache_test);
++ g_test_add_func ("/auth/async-message-do-not-use-auth-cache", do_async_message_do_not_use_auth_cache_test);
+ g_test_add_func ("/auth/authorization-header-request", do_message_has_authorization_header_test);
+
+ ret = g_test_run ();
+--
+2.11.0
+
diff --git a/Tools/gtk/patches/libsoup-auth-do-not-use-cached-credentials-in-lookup-method-.patch b/Tools/gtk/patches/libsoup-auth-do-not-use-cached-credentials-in-lookup-method-.patch
new file mode 100644
index 000000000..7d3ab58b2
--- /dev/null
+++ b/Tools/gtk/patches/libsoup-auth-do-not-use-cached-credentials-in-lookup-method-.patch
@@ -0,0 +1,114 @@
+From c8401c372adc9a9cb11fc870c390affb10379cfa Mon Sep 17 00:00:00 2001
+From: Carlos Garcia Campos <cgarcia@igalia.com>
+Date: Sat, 11 Feb 2017 17:44:46 +0100
+Subject: [PATCH 2/2] auth: do not use cached credentials in lookup method when
+ flag SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE is present
+
+This is causing that a request with flag
+SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE success if a previous request without
+the flag stored the credentials. This patch also fixes another issues
+with the test /auth/message-do-not-use-auth-cache, the case of providing
+the credentials in the url was working because do_digest_nonce_test()
+didn't disconnect the authenticate signal that was actually used. This
+is because soup_uri_to_string removes the password from the uri. The
+test needs to use a custom message created with
+soup_message_new_from_uri() instead of using do_digest_nonce_test().
+
+https://bugzilla.gnome.org/show_bug.cgi?id=778497
+---
+ libsoup/soup-auth-manager.c | 6 ++++++
+ tests/auth-test.c | 29 +++++++++++++++++++++++++----
+ 2 files changed, 31 insertions(+), 4 deletions(-)
+
+diff --git a/libsoup/soup-auth-manager.c b/libsoup/soup-auth-manager.c
+index 9ff446cc..b32ba900 100644
+--- a/libsoup/soup-auth-manager.c
++++ b/libsoup/soup-auth-manager.c
+@@ -472,6 +472,9 @@ lookup_auth (SoupAuthManagerPrivate *priv, SoupMessage *msg)
+ if (auth && soup_auth_is_ready (auth, msg))
+ return auth;
+
++ if (soup_message_get_flags (msg) & SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE)
++ return NULL;
++
+ host = get_auth_host_for_uri (priv, soup_message_get_uri (msg));
+ if (!host->auth_realms && !make_auto_ntlm_auth (priv, host))
+ return NULL;
+@@ -496,6 +499,9 @@ lookup_proxy_auth (SoupAuthManagerPrivate *priv, SoupMessage *msg)
+ if (auth && soup_auth_is_ready (auth, msg))
+ return auth;
+
++ if (soup_message_get_flags (msg) & SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE)
++ return NULL;
++
+ return priv->proxy_auth;
+ }
+
+diff --git a/tests/auth-test.c b/tests/auth-test.c
+index 23e22133..2d66da9e 100644
+--- a/tests/auth-test.c
++++ b/tests/auth-test.c
+@@ -442,6 +442,12 @@ do_digest_nonce_test (SoupSession *session,
+ got_401 ? "got" : "did not get");
+ soup_test_assert_message_status (msg, SOUP_STATUS_OK);
+
++ if (expect_signal) {
++ g_signal_handlers_disconnect_by_func (session,
++ G_CALLBACK (digest_nonce_authenticate),
++ NULL);
++ }
++
+ g_object_unref (msg);
+ }
+
+@@ -1297,9 +1303,10 @@ do_message_do_not_use_auth_cache_test (void)
+ {
+ SoupSession *session;
+ SoupAuthManager *manager;
++ SoupMessage *msg;
++ SoupMessageFlags flags;
+ SoupURI *soup_uri;
+ char *uri;
+- char *uri_with_credentials;
+
+ SOUP_TEST_SKIP_IF_NO_APACHE;
+
+@@ -1318,18 +1325,32 @@ do_message_do_not_use_auth_cache_test (void)
+ soup_uri = soup_uri_new (uri);
+ soup_uri_set_user (soup_uri, "user1");
+ soup_uri_set_password (soup_uri, "realm1");
+- uri_with_credentials = soup_uri_to_string (soup_uri, FALSE);
++ msg = soup_message_new_from_uri (SOUP_METHOD_GET, soup_uri);
++ flags = soup_message_get_flags (msg);
++ soup_message_set_flags (msg, flags | SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE);
++ soup_session_send_message (session, msg);
++ soup_test_assert_message_status (msg, SOUP_STATUS_OK);
++ g_object_unref (msg);
+ soup_uri_free (soup_uri);
+- do_digest_nonce_test (session, "Fourth", uri_with_credentials, FALSE, TRUE, FALSE);
+- g_free (uri_with_credentials);
+
+ manager = SOUP_AUTH_MANAGER (soup_session_get_feature (session, SOUP_TYPE_AUTH_MANAGER));
++
+ soup_auth_manager_clear_cached_credentials (manager);
+
+ /* Now check that credentials are not stored */
+ do_digest_nonce_test (session, "First", uri, FALSE, TRUE, TRUE);
+ do_digest_nonce_test (session, "Second", uri, TRUE, TRUE, TRUE);
+ do_digest_nonce_test (session, "Third", uri, TRUE, FALSE, FALSE);
++
++ /* Credentials were stored for uri, but if we set SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE flag,
++ * and we don't have the authenticate signal, it should respond with 401
++ */
++ msg = soup_message_new (SOUP_METHOD_GET, uri);
++ flags = soup_message_get_flags (msg);
++ soup_message_set_flags (msg, flags | SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE);
++ soup_session_send_message (session, msg);
++ soup_test_assert_message_status (msg, SOUP_STATUS_UNAUTHORIZED);
++ g_object_unref (msg);
+ g_free (uri);
+
+ soup_test_session_abort_unref (session);
+--
+2.11.0
+
diff --git a/Tools/gtk/patches/mesa-gallivm-Fix-build-after-LLVM-commit-211259.patch b/Tools/gtk/patches/mesa-gallivm-Fix-build-after-LLVM-commit-211259.patch
new file mode 100644
index 000000000..75f38e552
--- /dev/null
+++ b/Tools/gtk/patches/mesa-gallivm-Fix-build-after-LLVM-commit-211259.patch
@@ -0,0 +1,29 @@
+From 564821c917f4a9d5a0de2ee77b90b0cd85e3d3a6 Mon Sep 17 00:00:00 2001
+From: Aaron Watry <awatry@gmail.com>
+Date: Fri, 20 Jun 2014 19:13:30 -0500
+Subject: [PATCH] gallivm: Fix build after LLVM commit 211259
+
+Signed-off-by: Aaron Watry <awatry@gmail.com>
+Reviewed-by: Tom Stellard <thomas.stellard@amd.com>
+---
+ src/gallium/auxiliary/gallivm/lp_bld_debug.cpp | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/src/gallium/auxiliary/gallivm/lp_bld_debug.cpp b/src/gallium/auxiliary/gallivm/lp_bld_debug.cpp
+index df26883..413a0c2 100644
+--- a/src/gallium/auxiliary/gallivm/lp_bld_debug.cpp
++++ b/src/gallium/auxiliary/gallivm/lp_bld_debug.cpp
+@@ -51,7 +51,9 @@
+ #include <llvm/MC/MCInstPrinter.h>
+ #include <llvm/MC/MCRegisterInfo.h>
+
+-#if HAVE_LLVM >= 0x0303
++#if HAVE_LLVM >= 0x0305
++#define OwningPtr std::unique_ptr
++#elif HAVE_LLVM >= 0x0303
+ #include <llvm/ADT/OwningPtr.h>
+ #endif
+
+--
+2.1.0
+
diff --git a/Tools/gtk/patches/openh264-configure.patch b/Tools/gtk/patches/openh264-configure.patch
new file mode 100644
index 000000000..7bf1bd5a1
--- /dev/null
+++ b/Tools/gtk/patches/openh264-configure.patch
@@ -0,0 +1,12 @@
+--- /dev/null 2015-06-05 15:20:34.000000000 +1000
++++ pseudo-configure 2015-06-05 15:20:37.000000000 +1000
+@@ -0,0 +1,8 @@
++#!/bin/sh
++
++X=Makefile
++sed -e "s:^PREFIX=.*:PREFIX=$JHBUILD_PREFIX:" ${X} > ${X}.tmp && mv ${X}.tmp ${X}
++sed -e "s:^SHAREDLIB_DIR=.*:SHAREDLIB_DIR=$CMAKE_LIBRARY_PATH:" ${X} > ${X}.tmp && mv ${X}.tmp ${X}
++
++X=build/x86-common.mk
++sed -e "s:^ASM =.*:ASM = yasm:" $X > ${X}.tmp && mv ${X}.tmp $X
+
diff --git a/Tools/gtk/patches/rtspsrc-timeout-on-udpsrc-is-in-nanoseconds.patch b/Tools/gtk/patches/rtspsrc-timeout-on-udpsrc-is-in-nanoseconds.patch
new file mode 100644
index 000000000..87ed49087
--- /dev/null
+++ b/Tools/gtk/patches/rtspsrc-timeout-on-udpsrc-is-in-nanoseconds.patch
@@ -0,0 +1,27 @@
+From e0bb1fe30985aa0784825388500cc4fa92c1ff9c Mon Sep 17 00:00:00 2001
+From: Wim Taymans <wim.taymans@collabora.co.uk>
+Date: Wed, 12 Dec 2012 11:09:42 +0100
+Subject: [PATCH 2/2] rtspsrc: timeout on udpsrc is in nanoseconds
+
+---
+ gst/rtsp/gstrtspsrc.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/gst/rtsp/gstrtspsrc.c b/gst/rtsp/gstrtspsrc.c
+index 98577b8..902d8ff 100644
+--- a/gst/rtsp/gstrtspsrc.c
++++ b/gst/rtsp/gstrtspsrc.c
+@@ -2812,8 +2812,8 @@ gst_rtspsrc_stream_configure_udp (GstRTSPSrc * src, GstRTSPStream * stream,
+ /* configure a timeout on the UDP port. When the timeout message is
+ * posted, we assume UDP transport is not possible. We reconnect using TCP
+ * if we can. */
+- g_object_set (G_OBJECT (stream->udpsrc[0]), "timeout", src->udp_timeout,
+- NULL);
++ g_object_set (G_OBJECT (stream->udpsrc[0]), "timeout",
++ src->udp_timeout * 1000, NULL);
+
+ /* get output pad of the UDP source. */
+ *outpad = gst_element_get_static_pad (stream->udpsrc[0], "src");
+--
+1.8.1.2
+
diff --git a/Tools/gtk/patches/shared-mime-info-xht-glob.patch b/Tools/gtk/patches/shared-mime-info-xht-glob.patch
new file mode 100644
index 000000000..667ae4991
--- /dev/null
+++ b/Tools/gtk/patches/shared-mime-info-xht-glob.patch
@@ -0,0 +1,21 @@
+From 6e5818deb54fdfa70f5798fc1df1d5c3eaba42df Mon Sep 17 00:00:00 2001
+From: Bastien Nocera <hadess@hadess.net>
+Date: Thu, 7 Jan 2016 15:48:47 +0100
+Subject: Add *.xht as a glob for XHTML files
+
+
+diff --git a/freedesktop.org.xml.in b/freedesktop.org.xml.in
+index dc12655..48696d9 100644
+--- a/freedesktop.org.xml.in
++++ b/freedesktop.org.xml.in
+@@ -3669,6 +3669,7 @@ command to generate the output files.
+ <sub-class-of type="application/xml"/>
+ <generic-icon name="text-html"/>
+ <glob pattern="*.xhtml"/>
++ <glob pattern="*.xht"/>
+ <root-XML namespaceURI='http://www.w3.org/1999/xhtml' localName='html'/>
+ </mime-type>
+ <mime-type type="application/zip">
+--
+cgit v0.10.2
+
diff --git a/Tools/gtk/patches/shared-mime-info-xhtml-magic.patch b/Tools/gtk/patches/shared-mime-info-xhtml-magic.patch
new file mode 100644
index 000000000..4d0e81615
--- /dev/null
+++ b/Tools/gtk/patches/shared-mime-info-xhtml-magic.patch
@@ -0,0 +1,26 @@
+From 4961dc3e48d13c0c675ad7c135419b864813ca55 Mon Sep 17 00:00:00 2001
+From: Bastien Nocera <hadess@hadess.net>
+Date: Thu, 7 Jan 2016 15:49:16 +0100
+Subject: Add magic for XHTML files
+
+
+diff --git a/freedesktop.org.xml.in b/freedesktop.org.xml.in
+index 48696d9..9ea2f95 100644
+--- a/freedesktop.org.xml.in
++++ b/freedesktop.org.xml.in
+@@ -3670,6 +3670,12 @@ command to generate the output files.
+ <generic-icon name="text-html"/>
+ <glob pattern="*.xhtml"/>
+ <glob pattern="*.xht"/>
++ <magic priority="60">
++ <match type="string" value="//W3C//DTD XHTML " offset="0:256"/>
++ <match type="string" value="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" offset="0:256"/>
++ <match type="string" value="&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml" offset="0:256"/>
++ <match type="string" value="&lt;HTML xmlns=&quot;http://www.w3.org/1999/xhtml" offset="0:256"/>
++ </magic>
+ <root-XML namespaceURI='http://www.w3.org/1999/xhtml' localName='html'/>
+ </mime-type>
+ <mime-type type="application/zip">
+--
+cgit v0.10.2
+
diff --git a/Tools/gtk/patches/udpsrc-improve-timeouts.patch b/Tools/gtk/patches/udpsrc-improve-timeouts.patch
new file mode 100644
index 000000000..d26e346a8
--- /dev/null
+++ b/Tools/gtk/patches/udpsrc-improve-timeouts.patch
@@ -0,0 +1,53 @@
+From dbbdf54778771535dfea5ddbdeeaba89d9bc7be6 Mon Sep 17 00:00:00 2001
+From: Wim Taymans <wim.taymans@collabora.co.uk>
+Date: Wed, 12 Dec 2012 11:08:13 +0100
+Subject: [PATCH 1/2] udpsrc: improve timeouts
+
+Make it possible to set the timeout after we went to the READY state by using
+the timeout when checking the condition. This also makes it possible to set the
+timeout with a higher granularity than seconds.
+---
+ gst/udp/gstudpsrc.c | 16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+diff --git a/gst/udp/gstudpsrc.c b/gst/udp/gstudpsrc.c
+index bdad5b3..5b54021 100644
+--- a/gst/udp/gstudpsrc.c
++++ b/gst/udp/gstudpsrc.c
+@@ -397,13 +397,20 @@ retry:
+ goto no_select;
+
+ do {
++ gint64 timeout;
++
+ try_again = FALSE;
+
++ if (udpsrc->timeout)
++ timeout = udpsrc->timeout / 1000;
++ else
++ timeout = -1;
++
+ GST_LOG_OBJECT (udpsrc, "doing select, timeout %" G_GUINT64_FORMAT,
+- udpsrc->timeout);
++ timeout);
+
+- if (!g_socket_condition_wait (udpsrc->used_socket, G_IO_IN | G_IO_PRI,
+- udpsrc->cancellable, &err)) {
++ if (!g_socket_condition_timed_wait (udpsrc->used_socket, G_IO_IN | G_IO_PRI,
++ timeout, udpsrc->cancellable, &err)) {
+ if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_BUSY)
+ || g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ goto stopped;
+@@ -823,9 +830,6 @@ gst_udpsrc_start (GstBaseSrc * bsrc)
+ goto getsockname_error;
+ }
+
+- if (src->timeout)
+- g_socket_set_timeout (src->used_socket, src->timeout / GST_SECOND);
+-
+ #if GLIB_CHECK_VERSION (2, 35, 7)
+ {
+ gint val = 0;
+--
+1.8.1.2
+
diff --git a/Tools/gtk/patches/xserver-remove-bogus-dependencies.patch b/Tools/gtk/patches/xserver-remove-bogus-dependencies.patch
new file mode 100644
index 000000000..e17753e37
--- /dev/null
+++ b/Tools/gtk/patches/xserver-remove-bogus-dependencies.patch
@@ -0,0 +1,43 @@
+From 879f42531ff04be578c39f9d44548aeb3ded67fd Mon Sep 17 00:00:00 2001
+From: Gustavo Noronha Silva <gustavo.noronha@collabora.com>
+Date: Wed, 8 May 2013 19:44:15 -0300
+Subject: [PATCH 2/2] Filter out -l parameters when setting dependencies
+
+Newer make (Fedora 19) gets confused when it finds a -l parameter in a
+dependency, and tries to make it as a target, causing the build to fail.
+
+Signed-off-by: Gustavo Noronha Silva <gustavo.noronha@collabora.com>
+---
+ hw/vfb/Makefile.am | 2 +-
+ test/Makefile.am | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/hw/vfb/Makefile.am b/hw/vfb/Makefile.am
+index 9f4992c..06830ae 100644
+--- a/hw/vfb/Makefile.am
++++ b/hw/vfb/Makefile.am
+@@ -20,7 +20,7 @@ XVFB_LIBS = \
+ $(top_builddir)/Xi/libXistubs.la
+
+ Xvfb_LDADD = $(XVFB_LIBS) $(XVFB_SYS_LIBS) $(XSERVER_SYS_LIBS)
+-Xvfb_DEPENDENCIES = $(XVFB_LIBS)
++Xvfb_DEPENDENCIES = $(filter-out -l%,$(XVFB_LIBS))
+ Xvfb_LDFLAGS = $(LD_EXPORT_SYMBOLS_FLAG)
+
+ relink:
+diff --git a/test/Makefile.am b/test/Makefile.am
+index 34f53fc..3509306 100644
+--- a/test/Makefile.am
++++ b/test/Makefile.am
+@@ -131,7 +131,7 @@ libxservertest_la_LIBADD += \
+ endif
+ endif
+
+-libxservertest_la_DEPENDENCIES = $(libxservertest_la_LIBADD)
++libxservertest_la_DEPENDENCIES = $(filter-out -l%,$(libxservertest_la_LIBADD))
+ endif
+
+ EXTRA_DIST = ddxstubs.c
+--
+1.8.2.1
+
diff --git a/Tools/gtk/patches/xserver-search-for-DRI-drivers-at-LIBGL_DRIVERS_PATH-environ.patch b/Tools/gtk/patches/xserver-search-for-DRI-drivers-at-LIBGL_DRIVERS_PATH-environ.patch
new file mode 100644
index 000000000..ad380c851
--- /dev/null
+++ b/Tools/gtk/patches/xserver-search-for-DRI-drivers-at-LIBGL_DRIVERS_PATH-environ.patch
@@ -0,0 +1,84 @@
+From fcbd29debee422bcb147057a089fd1da5e699656 Mon Sep 17 00:00:00 2001
+From: Carlos Alberto Lopez Perez <clopez@igalia.com>
+Date: Wed, 23 Mar 2016 03:47:58 +0100
+Subject: [PATCH xserver] Search for DRI drivers at LIBGL_DRIVERS_PATH
+ environment variable.
+
+ * The Mesa driver uses this environment variable to override the
+ default compiled search path for DRI drivers.
+
+ * This is useful for testing purposes when the user needs to
+ override the system default one at runtime.
+---
+ glx/glxdricommon.c | 40 ++++++++++++++++++++++++++++++----------
+ 1 file changed, 30 insertions(+), 10 deletions(-)
+
+diff --git a/glx/glxdricommon.c b/glx/glxdricommon.c
+index 62cce13..543f631 100644
+--- a/glx/glxdricommon.c
++++ b/glx/glxdricommon.c
+@@ -246,8 +246,6 @@ glxConvertConfigs(const __DRIcoreExtension * core,
+ return head.next;
+ }
+
+-static const char dri_driver_path[] = DRI_DRIVER_PATH;
+-
+ /* Temporary define to allow building without a dri_interface.h from
+ * updated Mesa. Some day when we don't care about Mesa that old any
+ * more this can be removed.
+@@ -261,22 +259,44 @@ glxProbeDriver(const char *driverName,
+ void **coreExt, const char *coreName, int coreVersion,
+ void **renderExt, const char *renderName, int renderVersion)
+ {
+- int i;
++ int i, len;
+ void *driver;
+ char filename[PATH_MAX];
+ char *get_extensions_name;
+ const __DRIextension **extensions = NULL;
++ const char *dri_driver_path, *p, *next;
+
+- snprintf(filename, sizeof filename, "%s/%s_dri.so",
+- dri_driver_path, driverName);
++ dri_driver_path = getenv("LIBGL_DRIVERS_PATH");
++
++ if (dri_driver_path == NULL)
++ dri_driver_path = DRI_DRIVER_PATH;
++
++ for (p = dri_driver_path; *p; p = next) {
++ next = strchr(p, ':');
++ if (next == NULL) {
++ len = strlen(p);
++ next = p + len;
++ }
++ else {
++ len = next - p;
++ next++;
++ }
++
++ snprintf(filename, sizeof filename, "%.*s/%s_dri.so",
++ len, p, driverName);
++
++ driver = dlopen(filename, RTLD_LAZY | RTLD_LOCAL);
++ if (driver == NULL)
++ LogMessage(X_ERROR, "AIGLX error: dlopen of %s failed (%s)\n",
++ filename, dlerror());
++ else
++ break;
+
+- driver = dlopen(filename, RTLD_LAZY | RTLD_LOCAL);
+- if (driver == NULL) {
+- LogMessage(X_ERROR, "AIGLX error: dlopen of %s failed (%s)\n",
+- filename, dlerror());
+- goto cleanup_failure;
+ }
+
++ if (driver == NULL)
++ goto cleanup_failure;
++
+ if (asprintf(&get_extensions_name, "%s_%s",
+ __DRI_DRIVER_GET_EXTENSIONS, driverName) != -1) {
+ const __DRIextension **(*get_extensions)(void);
+--
+2.1.4
+
diff --git a/Tools/gtk/webkitdom.py b/Tools/gtk/webkitdom.py
deleted file mode 100755
index 221defba6..000000000
--- a/Tools/gtk/webkitdom.py
+++ /dev/null
@@ -1,285 +0,0 @@
-#!/usr/bin/env python
-# Copyright (C) 2013 Igalia S.L.
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301 USA
-
-import common
-import os
-import re
-import sys
-
-from ConfigParser import SafeConfigParser
-
-
-class WebKitDOMDocGenerator(object):
-
- DELETED_CLASSES = [
- "WebKitDOMBarInfo",
- "WebKitDOMHTMLPropertiesCollection",
- "WebKitDOMMemoryInfo",
- "WebKitDOMMicroDataItemValue",
- "WebKitDOMPropertyNodeList"]
-
- def __init__(self, symbol_files, file_handle):
- self._symbol_files = symbol_files
- self._file_handle = file_handle
-
- def write_header(self):
- pass
-
- def write_section(self, symbol_file):
- raise NotImplementedError
-
- def write_deleted_classes(self):
- raise NotImplementedError
-
- def write_footer(self):
- pass
-
- def write(self, string):
- self._file_handle.write(string)
-
- @staticmethod
- def is_deprecated_symbol_file(file_path):
- return 'WebKitDOMDeprecated' in file_path
-
- def generate(self):
- self.write_header()
- for symbol_file in self._symbol_files:
- if WebKitDOMDocGenerator.is_deprecated_symbol_file(symbol_file):
- continue
- self.write_section(symbol_file)
- self.write_deleted_classes()
- self.write_footer()
-
-
-class WebKitDOMDocGeneratorSGML(WebKitDOMDocGenerator):
- def write_header(self):
- self.write('''<?xml version="1.0"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
-<!ENTITY version SYSTEM "version.xml">
-]>
-<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
- <bookinfo>
- <title>WebKitDOMGTK+ Reference Manual</title>
- <releaseinfo>for WebKitDOMGTK+ &version;</releaseinfo>
- </bookinfo>
-
- <chapter>
- <title>Class Overview</title>
-''')
-
- def write_section(self, symbol_file):
- basename = os.path.basename(symbol_file)
- self.write(' <xi:include href="xml/%s"/>\n' % basename.replace(".symbols", ".xml"))
-
- def write_deleted_classes(self):
- for class_name in self.DELETED_CLASSES:
- self.write(' <xi:include href="xml/%s.xml"/>\n' % class_name)
-
- def write_footer(self):
- self.write(''' </chapter>
-
- <index id="index-all">
- <title>Index</title>
- <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
- </index>
- <index id="api-index-deprecated" role="deprecated">
- <title>Index of deprecated symbols</title>
- <xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
- </index>
-
- <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
-</book>
-''')
-
-
-class WebKitDOMDocGeneratorSections(WebKitDOMDocGenerator):
- def __init__(self, symbol_files, file_handle):
- super(WebKitDOMDocGeneratorSections, self).__init__(symbol_files, file_handle)
-
- self._first_decamelize_re = re.compile('(.)([A-Z][a-z]+)')
- self._second_decamelize_re = re.compile('([a-z0-9])([A-Z])')
- self._dom_class_re = re.compile('(^WebKitDOM)(.+)$')
- self._function_re = re.compile('^.+ (.+)\((.+)\)$')
-
- self.deprecated_symbosl = {}
- for symbol_file in symbol_files:
- if WebKitDOMDocGenerator.is_deprecated_symbol_file(symbol_file):
- self._deprecated_symbols = self._find_deprecated_symbols(symbol_file)
- break
-
- def _dom_class(self, class_name):
- return self._dom_class_re.sub(r'\2', class_name)
-
- def _dom_class_decamelize(self, class_name):
- s1 = self._first_decamelize_re.sub(r'\1_\2', self._dom_class(class_name))
- retval = self._second_decamelize_re.sub(r'\1_\2', s1)
-
- # Fix some exceptions.
- retval = retval.replace('Web_Kit', 'WebKit')
- retval = retval.replace('X_Path', 'XPath')
- retval = retval.replace('HTMLI_Frame', 'HTML_IFrame')
-
- return retval
-
- def _deleted_class(self, function):
- for deleted_class in self.DELETED_CLASSES:
- decamelized = 'webkit_dom_%s' % self._dom_class_decamelize(deleted_class).lower()
- if function.startswith(decamelized):
- return deleted_class
- return None
-
- def _find_deprecated_symbols(self, symbol_file):
- retval = {}
- f = open(symbol_file, 'r')
- for line in f.readlines():
- match = self._function_re.match(line)
- if not match:
- continue
-
- function = match.group(1)
- args = match.group(2).split(', ')
- class_name = args[0].strip('*')
- if class_name == 'void':
- class_name = self._deleted_class(function)
-
- retval.setdefault(class_name, []).append(function)
-
- return retval
-
- def _symbol_list(self, symbol_file):
- retval = []
- f = open(symbol_file, 'r')
- for line in f.readlines():
- match = self._function_re.match(line)
- if not match or match.group(1).endswith('get_type'):
- continue
- retval.append(match.group(1))
-
- return retval
-
- def write_section(self, symbol_file):
- class_name = os.path.basename(symbol_file).replace(".symbols", "")
- is_custom = class_name == 'WebKitDOMCustom'
- is_interface = class_name == 'WebKitDOMEventTarget'
- is_object = class_name == 'WebKitDOMObject'
- self.write('<SECTION>\n')
- self.write('<FILE>%s</FILE>\n<TITLE>%s</TITLE>\n' % (class_name, class_name))
- if not is_custom:
- self.write('%s\n' % class_name)
- self.write('\n')
- self.write('\n'.join(self._symbol_list(symbol_file)) + '\n')
- try:
- deprecated_functions = self._deprecated_symbols[class_name]
- self.write('\n'.join(deprecated_functions) + '\n')
- except KeyError:
- pass
- if not is_custom:
- self.write('\n<SUBSECTION Standard>\n')
- self.write('%sClass\n' % class_name)
- dom_class = self._dom_class_decamelize(class_name).upper()
- self.write('WEBKIT_TYPE_DOM_%s\n' % dom_class)
- self.write('WEBKIT_DOM_%s\n' % dom_class)
- if is_object:
- self.write('WEBKIT_IS_DOM_%s\n' % dom_class)
- else:
- self.write('WEBKIT_DOM_IS_%s\n' % dom_class)
- self.write('WEBKIT_DOM_%s_CLASS\n' % dom_class)
- if is_interface:
- self.write('WEBKIT_DOM_%s_GET_IFACE\n' % dom_class)
- else:
- if is_object:
- self.write('WEBKIT_IS_DOM_%s_CLASS\n' % dom_class)
- else:
- self.write('WEBKIT_DOM_IS_%s_CLASS\n' % dom_class)
- self.write('WEBKIT_DOM_%s_GET_CLASS\n' % dom_class)
- self.write('\n<SUBSECTION Private>\n')
- if is_object:
- self.write('%sPrivate\n' % class_name)
- self.write('webkit_dom_%s_get_type\n' % dom_class.lower())
- self.write('</SECTION>\n\n')
-
- def write_deleted_classes(self):
- for class_name in self.DELETED_CLASSES:
- self.write('<SECTION>\n')
- self.write('<FILE>%s</FILE>\n<TITLE>%s</TITLE>\n' % (class_name, class_name))
- self.write('\n'.join([name for name in self._deprecated_symbols[class_name] if not name.endswith('get_type')]) + '\n')
- self.write('\n<SUBSECTION Private>\n')
- self.write('webkit_dom_%s_get_type\n' % self._dom_class_decamelize(class_name).lower())
- self.write('</SECTION>\n\n')
-
- def write_footer(self):
- self.write('<SECTION>\n')
- self.write('<FILE>webkitdomdefines</FILE>\n<TITLE>WebKitDOMDefines</TITLE>\n')
- self.write('<SUBSECTION Private>\n')
- self.write('WEBKIT_API\nWEBKIT_DEPRECATED\nWEBKIT_DEPRECATED_FOR\n')
- self.write('</SECTION>\n\n')
-
-
-def write_doc_files():
- doc_dir = common.build_path('DerivedSources', 'webkitdom', 'docs')
-
- try:
- os.mkdir(doc_dir)
- except:
- pass # Commonly happens if the directory already exists.
-
- with open(os.path.join(doc_dir, 'webkitdomgtk-sections.txt'), 'w') as sections_file:
- generator = WebKitDOMDocGeneratorSections(get_all_webkitdom_symbol_files(), sections_file)
- generator.generate()
- with open(os.path.join(doc_dir, 'webkitdomgtk-docs.sgml'), 'w') as sgml_file:
- generator = WebKitDOMDocGeneratorSGML(get_all_webkitdom_symbol_files(), sgml_file)
- generator.generate()
-
-
-def header_name_list_from_gtkdoc_config_file():
- config_file = common.build_path('gtkdoc-webkitdom.cfg')
- if not os.path.isfile(config_file):
- sys.stderr.write("Could not find config file at %s\n" % config_file)
- return sys.exit(1)
-
- config = SafeConfigParser()
- config.read(config_file)
- module_name = config.sections()[0]
- return [os.path.basename(f) for f in str(config.get(module_name, 'headers')).replace(';', ' ').split()]
-
-
-def get_all_webkitdom_symbol_files():
- static_symbol_files_path = common.top_level_path('Source', 'WebCore', 'bindings', 'gobject')
- generated_symbol_files_path = common.build_path('DerivedSources', 'webkitdom')
-
- symbol_files = []
- for header_name in header_name_list_from_gtkdoc_config_file():
- # webkitdomdefines.h doesn't have a corresponding symbols file and webkitdom.symbols is a
- # file containing the expected symbols results.
- if header_name in ("webkitdom.h", "webkitdomdefines.h"):
- continue
-
- symbol_file = header_name.replace(".h", ".symbols")
- path = os.path.join(static_symbol_files_path, symbol_file)
- if os.path.exists(path):
- symbol_files.append(path)
- continue
- path = os.path.join(generated_symbol_files_path, symbol_file)
- if os.path.exists(path):
- symbol_files.append(path)
- continue
- sys.stderr.write("Could not find symbol file for header: %s\n" % header_name)
- sys.exit(1)
-
- return symbol_files
diff --git a/Tools/gtk/ycm_extra_conf.py b/Tools/gtk/ycm_extra_conf.py
new file mode 100644
index 000000000..871e8af8e
--- /dev/null
+++ b/Tools/gtk/ycm_extra_conf.py
@@ -0,0 +1,132 @@
+#!/usr/bin/env python
+# Copyright (C) 2013 Danilo Cesar Lemes de Paula <danilo.eu@gmail.com>
+# Copyright (C) 2014 ChangSeok Oh <shivamidow@gmail.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import sys
+import ycm_core
+
+# It's very likely that this script is a symlink somewhere in the WebKit directory,
+# so we try to find the actual script location so that we can locate the tools
+# directory.
+original_file = __file__[:-1] if __file__.endswith(".pyc") else __file__
+if os.path.islink(original_file):
+ parent_folder = os.path.abspath(os.path.dirname(original_file))
+ link_file = os.path.join(parent_folder, os.readlink(original_file))
+ __tools_directory = os.path.dirname(link_file)
+else:
+ __tools_directory = os.path.dirname(original_file)
+
+sys.path.insert(0, os.path.abspath(__tools_directory))
+import common
+
+
+FLAGS_PRECEDING_PATHS = ['-isystem', '-I', '-iquote', '--sysroot=']
+def transform_relative_paths_to_absolute_paths(arguments, build_path):
+ result = []
+ make_next_absolute = False
+ for argument in arguments:
+ if make_next_absolute:
+ make_next_absolute = False
+ if not argument.startswith('/'):
+ argument = os.path.join(build_path, argument)
+ elif argument in FLAGS_PRECEDING_PATHS:
+ # Some flags precede the path in the list. For those we make the
+ # next argument absolute.
+ make_next_absolute = True
+ else:
+ # Some argument contain the flag and the path together. For these
+ # we parse the argument out of the path.
+ for flag in FLAGS_PRECEDING_PATHS:
+ if argument.startswith(flag):
+ argument = flag + os.path.join(build_path, argument[len(flag):])
+ break
+
+ result.append(argument)
+ return result
+
+
+def get_build_path():
+ webkitbuild_path = os.path.join(common.get_build_path(fatal=False), '..')
+ if not os.path.exists(webkitbuild_path):
+ return None
+
+ release_build_path = os.path.join(webkitbuild_path, 'Release')
+ debug_build_path = os.path.join(webkitbuild_path, 'Debug')
+
+ try:
+ release_mtime = os.path.getmtime(os.path.join(release_build_path, 'compile_commands.json'))
+ except os.error:
+ release_mtime = 0
+ try:
+ debug_mtime = os.path.getmtime(os.path.join(debug_build_path, 'compile_commands.json'))
+ except os.error:
+ debug_mtime = 0
+
+ return release_build_path if release_mtime >= debug_mtime else debug_build_path
+
+
+def FlagsForFile(filename, **kwargs):
+ """This is the main entry point for YCM. Its interface is fixed.
+
+ Args:
+ filename: (String) Path to source file being edited.
+
+ Returns:
+ (Dictionary)
+ 'flags': (List of Strings) Command line flags.
+ 'do_cache': (Boolean) True if the result should be cached.
+ """
+
+ result = {'flags': ['-std=c++11', '-x', 'c++'], 'do_cache': True}
+
+ # Headers can't be built, so we get the source file flags instead.
+ if filename.endswith('.h'):
+ alternative_extensions = ['.cpp', '.c']
+ for alternative_extension in alternative_extensions:
+ alternative_filename = filename[:-2] + alternative_extension
+ if os.path.exists(alternative_filename):
+ filename = alternative_filename
+ break
+ else:
+ return result
+ # Force config.h file inclusion, for GLib macros.
+ result['flags'].append("-includeconfig.h")
+
+ build_path = os.path.normpath(get_build_path())
+ if not build_path:
+ print "Could not find WebKit build path."
+ return result
+
+ database = ycm_core.CompilationDatabase(build_path)
+ if not database:
+ print "Could not find compile_commands.json in %s, You might forget to add CMAKE_EXPORT_COMPILE_COMMANDS=ON to cmakeargs" % build_path
+ return result
+
+ compilation_info = database.GetCompilationInfoForFile(filename)
+ if not compilation_info:
+ print "No compilation info."
+ return result
+
+ result['flags'] = transform_relative_paths_to_absolute_paths(list(compilation_info.compiler_flags_), compilation_info.compiler_working_dir_)
+ return result
+
+
+if __name__ == "__main__":
+ import sys
+ if len(sys.argv) >= 2:
+ print FlagsForFile(sys.argv[1])
diff --git a/Tools/jhbuild/jhbuildutils.py b/Tools/jhbuild/jhbuildutils.py
new file mode 100644
index 000000000..c00160e7e
--- /dev/null
+++ b/Tools/jhbuild/jhbuildutils.py
@@ -0,0 +1,56 @@
+import glob
+import os.path
+import sys
+import __builtin__
+
+top_level_dir = None
+
+
+def top_level_path(*args):
+ global top_level_dir
+ if not top_level_dir:
+ top_level_dir = os.path.join(os.path.dirname(__file__), '..', '..')
+ return os.path.join(*(top_level_dir,) + args)
+
+
+def get_dependencies_path(platform):
+ dependencies_dir = "%s%s" % ('Dependencies', platform.upper())
+ if 'WEBKIT_OUTPUTDIR' in os.environ:
+ return os.path.abspath(os.path.join(os.environ['WEBKIT_OUTPUTDIR'], dependencies_dir))
+ else:
+ return os.path.abspath(top_level_path('WebKitBuild', dependencies_dir))
+
+
+def get_config_file_for_platform(platform):
+ return top_level_path('Tools', platform, 'jhbuildrc')
+
+
+def enter_jhbuild_environment_if_available(platform):
+ if not os.path.exists(get_dependencies_path(platform)):
+ return False
+
+ # Sometimes jhbuild chooses to install in a way that reads the library from the source directory, so fall
+ # back to that method.
+ source_path = os.path.join(get_dependencies_path(platform), "Source", "jhbuild")
+ sys.path.insert(0, source_path)
+
+ # When loading jhbuild from the source checkout it fails if the SRCDIR, PKGDATADIR or DATADIR aren't present.
+ __builtin__.__dict__['SRCDIR'] = source_path
+ __builtin__.__dict__['PKGDATADIR'] = None
+ __builtin__.__dict__['DATADIR'] = None
+
+ # We don't know the Python version, so we just assume that we can safely take the first one in the list.
+ site_packages_path = glob.glob(os.path.join(get_dependencies_path(platform), "Root", "lib", "*", "site-packages"))
+ if len(site_packages_path):
+ site_packages_path = site_packages_path[0]
+ sys.path.insert(0, site_packages_path)
+
+ try:
+ import jhbuild.config
+ from jhbuild.errors import FatalError
+ config = jhbuild.config.Config(get_config_file_for_platform(platform), [])
+ except FatalError, exception:
+ sys.stderr.write('Could not load jhbuild config file: %s\n' % exception.args[0])
+ return False
+
+ return True