From 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c Mon Sep 17 00:00:00 2001 From: Lorry Tar Creator Date: Tue, 27 Jun 2017 06:07:23 +0000 Subject: webkitgtk-2.16.5 --- Tools/CMakeLists.txt | 48 + Tools/DumpRenderTree/AccessibilityController.cpp | 16 + Tools/DumpRenderTree/AccessibilityController.h | 6 +- Tools/DumpRenderTree/AccessibilityTextMarker.h | 8 +- Tools/DumpRenderTree/AccessibilityUIElement.cpp | 462 +++- Tools/DumpRenderTree/AccessibilityUIElement.h | 60 +- .../Bindings/CodeGeneratorDumpRenderTree.pm | 563 ++++ Tools/DumpRenderTree/CMakeLists.txt | 100 + Tools/DumpRenderTree/DefaultPolicyDelegate.h | 13 + Tools/DumpRenderTree/DerivedSources.make | 50 + Tools/DumpRenderTree/DumpRenderTree.h | 23 +- Tools/DumpRenderTree/DumpRenderTreeCommon.cpp | 35 +- .../DumpRenderTreeFileDraggingSource.h | 43 + Tools/DumpRenderTree/DumpRenderTreePrefix.h | 13 +- .../ForwardingHeaders/runtime/ArrayBufferView.h | 1 + .../ForwardingHeaders/runtime/JSArrayBufferView.h | 1 + .../ForwardingHeaders/runtime/JSExportMacros.h | 1 + .../ForwardingHeaders/runtime/TypedArrayInlines.h | 1 + Tools/DumpRenderTree/GCController.cpp | 2 +- Tools/DumpRenderTree/GCController.h | 4 +- Tools/DumpRenderTree/JavaScriptThreading.cpp | 157 ++ Tools/DumpRenderTree/JavaScriptThreading.h | 2 +- Tools/DumpRenderTree/PixelDumpSupport.cpp | 18 +- Tools/DumpRenderTree/PixelDumpSupport.h | 14 +- .../TestNetscapePlugIn/CMakeLists.txt | 61 + .../ForwardingHeaders/WebKit/npapi.h | 1 + .../ForwardingHeaders/WebKit/npfunctions.h | 1 + .../ForwardingHeaders/WebKit/npruntime.h | 1 + .../TestNetscapePlugIn/PluginObject.cpp | 44 +- .../TestNetscapePlugIn/PluginTest.cpp | 19 + .../DumpRenderTree/TestNetscapePlugIn/PluginTest.h | 7 + .../Tests/EvaluateJSWithinNPP_New.cpp | 56 + .../Tests/InvokeDestroysPluginWithinNPP_New.cpp | 67 + ...luginScriptableObjectOverridesAllProperties.cpp | 82 + .../TestNetscapePlugIn/Tests/SlowNPPNew.cpp | 87 + .../TestNetscapePlugIn/Tests/URLRedirect.cpp | 167 ++ Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp | 55 +- .../unix/ForwardingHeaders/WebKit/npapi.h | 1 - .../unix/ForwardingHeaders/WebKit/npfunctions.h | 1 - .../unix/ForwardingHeaders/WebKit/npruntime.h | 1 - Tools/DumpRenderTree/TestOptions.h | 37 + Tools/DumpRenderTree/TestRunner.cpp | 466 ++-- Tools/DumpRenderTree/TestRunner.h | 106 +- Tools/DumpRenderTree/TextInputController.h | 41 + Tools/DumpRenderTree/WorkQueue.cpp | 7 +- Tools/DumpRenderTree/WorkQueue.h | 8 +- Tools/DumpRenderTree/WorkQueueItem.h | 2 +- Tools/DumpRenderTree/atk/AccessibilityCallbacks.h | 44 - .../atk/AccessibilityCallbacksAtk.cpp | 297 --- .../atk/AccessibilityControllerAtk.cpp | 145 - .../atk/AccessibilityNotificationHandlerAtk.cpp | 55 - .../atk/AccessibilityNotificationHandlerAtk.h | 51 - .../atk/AccessibilityUIElementAtk.cpp | 1604 ----------- .../DumpRenderTree/cairo/PixelDumpSupportCairo.cpp | 2 +- Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.h | 13 +- Tools/DumpRenderTree/config.h | 45 +- .../gtk/AccessibilityControllerGtk.cpp | 79 - Tools/DumpRenderTree/gtk/DumpRenderTree.cpp | 1557 ----------- Tools/DumpRenderTree/gtk/DumpRenderTreeGtk.h | 50 - Tools/DumpRenderTree/gtk/EditingCallbacks.cpp | 202 -- Tools/DumpRenderTree/gtk/EditingCallbacks.h | 35 - Tools/DumpRenderTree/gtk/EventSender.cpp | 1004 ------- Tools/DumpRenderTree/gtk/EventSender.h | 42 - Tools/DumpRenderTree/gtk/GCControllerGtk.cpp | 50 - Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp | 115 - .../gtk/SelfScrollingWebKitWebView.cpp | 78 - .../gtk/SelfScrollingWebKitWebView.h | 51 - Tools/DumpRenderTree/gtk/TestRunnerGtk.cpp | 914 ------- Tools/DumpRenderTree/gtk/TextInputController.cpp | 215 -- Tools/DumpRenderTree/gtk/TextInputController.h | 37 - Tools/DumpRenderTree/gtk/WorkQueueItemGtk.cpp | 102 - Tools/GNUmakefile.am | 277 -- Tools/GtkLauncher/GNUmakefile.am | 42 - Tools/GtkLauncher/LauncherInspectorWindow.c | 115 - Tools/GtkLauncher/LauncherInspectorWindow.h | 51 - Tools/GtkLauncher/main.c | 564 ---- Tools/ImageDiff/CMakeLists.txt | 14 + Tools/ImageDiff/PlatformGTK.cmake | 11 + Tools/ImageDiff/gtk/ImageDiff.cpp | 17 +- Tools/MiniBrowser/MBToolbarItem.h | 27 + Tools/MiniBrowser/MiniBrowserWebProcessPlugIn.h | 34 + Tools/MiniBrowser/gtk/BrowserDownloadsBar.c | 1 + Tools/MiniBrowser/gtk/BrowserSearchBar.c | 12 +- Tools/MiniBrowser/gtk/BrowserSettingsDialog.c | 55 +- Tools/MiniBrowser/gtk/BrowserTab.c | 552 ++++ Tools/MiniBrowser/gtk/BrowserTab.h | 60 + Tools/MiniBrowser/gtk/BrowserWindow.c | 898 +++++-- Tools/MiniBrowser/gtk/BrowserWindow.h | 11 +- Tools/MiniBrowser/gtk/CMakeLists.txt | 64 + Tools/MiniBrowser/gtk/GNUmakefile.am | 75 - Tools/MiniBrowser/gtk/main.c | 307 ++- Tools/Scripts/VCSUtils.pm | 2433 +++++++++++++++++ Tools/Scripts/run-gtk-tests | 494 ++++ Tools/Scripts/webkit-build-directory | 84 + Tools/Scripts/webkitdirs.pm | 2613 ++++++++++++++++++ Tools/TestWebKitAPI/CMakeLists.txt | 232 ++ Tools/TestWebKitAPI/Counters.cpp | 36 + Tools/TestWebKitAPI/Counters.h | 99 + .../ForwardingHeaders/WebCore/LayoutUnit.h | 4 + Tools/TestWebKitAPI/GNUmakefile.am | 934 ------- Tools/TestWebKitAPI/InjectedBundleController.cpp | 7 +- Tools/TestWebKitAPI/InjectedBundleController.h | 4 +- Tools/TestWebKitAPI/InjectedBundleMain.cpp | 9 +- Tools/TestWebKitAPI/InjectedBundleTest.h | 2 +- Tools/TestWebKitAPI/JavaScriptTest.cpp | 9 +- Tools/TestWebKitAPI/JavaScriptTest.h | 13 +- Tools/TestWebKitAPI/PlatformGTK.cmake | 158 ++ Tools/TestWebKitAPI/PlatformJSCOnly.cmake | 21 + Tools/TestWebKitAPI/PlatformUtilities.cpp | 12 +- Tools/TestWebKitAPI/PlatformUtilities.h | 33 +- Tools/TestWebKitAPI/PlatformWebView.h | 45 +- Tools/TestWebKitAPI/Test.h | 16 +- .../Tests/JavaScriptCore/VMInspector.cpp | 689 ----- Tools/TestWebKitAPI/Tests/WTF/AtomicString.cpp | 9 +- Tools/TestWebKitAPI/Tests/WTF/BloomFilter.cpp | 250 ++ .../Tests/WTF/CheckedArithmeticOperations.cpp | 554 +++- Tools/TestWebKitAPI/Tests/WTF/Condition.cpp | 257 ++ Tools/TestWebKitAPI/Tests/WTF/Consume.cpp | 141 + Tools/TestWebKitAPI/Tests/WTF/CrossThreadTask.cpp | 150 ++ Tools/TestWebKitAPI/Tests/WTF/DateMath.cpp | 208 ++ .../Tests/WTF/DeletedAddressOfOperator.h | 84 + Tools/TestWebKitAPI/Tests/WTF/Deque.cpp | 191 ++ Tools/TestWebKitAPI/Tests/WTF/EnumTraits.cpp | 55 + Tools/TestWebKitAPI/Tests/WTF/Expected.cpp | 512 ++++ Tools/TestWebKitAPI/Tests/WTF/Functional.cpp | 218 -- Tools/TestWebKitAPI/Tests/WTF/HashCountedSet.cpp | 468 ++++ Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp | 780 +++++- Tools/TestWebKitAPI/Tests/WTF/HashSet.cpp | 354 ++- Tools/TestWebKitAPI/Tests/WTF/LEBDecoder.cpp | 241 ++ Tools/TestWebKitAPI/Tests/WTF/ListHashSet.cpp | 98 +- Tools/TestWebKitAPI/Tests/WTF/Lock.cpp | 189 ++ Tools/TestWebKitAPI/Tests/WTF/MediaTime.cpp | 65 +- Tools/TestWebKitAPI/Tests/WTF/MetaAllocator.cpp | 6 +- Tools/TestWebKitAPI/Tests/WTF/NakedPtr.cpp | 238 ++ Tools/TestWebKitAPI/Tests/WTF/OptionSet.cpp | 297 +++ Tools/TestWebKitAPI/Tests/WTF/Optional.cpp | 150 ++ Tools/TestWebKitAPI/Tests/WTF/ParkingLot.cpp | 273 ++ Tools/TestWebKitAPI/Tests/WTF/RedBlackTree.cpp | 2 +- Tools/TestWebKitAPI/Tests/WTF/Ref.cpp | 57 +- Tools/TestWebKitAPI/Tests/WTF/RefCounter.cpp | 170 ++ Tools/TestWebKitAPI/Tests/WTF/RefLogger.cpp | 37 + Tools/TestWebKitAPI/Tests/WTF/RefLogger.h | 10 +- Tools/TestWebKitAPI/Tests/WTF/RefPtr.cpp | 58 +- Tools/TestWebKitAPI/Tests/WTF/RunLoop.cpp | 166 ++ Tools/TestWebKitAPI/Tests/WTF/Scope.cpp | 53 + Tools/TestWebKitAPI/Tests/WTF/ScopedLambda.cpp | 51 + Tools/TestWebKitAPI/Tests/WTF/SetForScope.cpp | 47 + Tools/TestWebKitAPI/Tests/WTF/StringBuilder.cpp | 25 +- .../TestWebKitAPI/Tests/WTF/StringConcatenate.cpp | 121 + Tools/TestWebKitAPI/Tests/WTF/StringHasher.cpp | 63 +- Tools/TestWebKitAPI/Tests/WTF/StringImpl.cpp | 550 +++- Tools/TestWebKitAPI/Tests/WTF/StringOperators.cpp | 16 + Tools/TestWebKitAPI/Tests/WTF/StringView.cpp | 928 +++++++ .../Tests/WTF/SynchronizedFixedQueue.cpp | 229 ++ Tools/TestWebKitAPI/Tests/WTF/TemporaryChange.cpp | 47 - .../TestWebKitAPI/Tests/WTF/TextBreakIterator.cpp | 146 + Tools/TestWebKitAPI/Tests/WTF/Time.cpp | 318 +++ Tools/TestWebKitAPI/Tests/WTF/UniqueRef.cpp | 93 + Tools/TestWebKitAPI/Tests/WTF/Variant.cpp | 228 ++ Tools/TestWebKitAPI/Tests/WTF/Vector.cpp | 430 ++- Tools/TestWebKitAPI/Tests/WTF/WTFString.cpp | 364 +++ Tools/TestWebKitAPI/Tests/WTF/WeakPtr.cpp | 193 ++ Tools/TestWebKitAPI/Tests/WTF/WorkQueue.cpp | 236 ++ .../TestWebKitAPI/Tests/WTF/darwin/OSObjectPtr.cpp | 66 + Tools/TestWebKitAPI/Tests/WTF/glib/GUniquePtr.cpp | 195 ++ .../TestWebKitAPI/Tests/WTF/glib/WorkQueueGLib.cpp | 71 + .../TestWebKitAPI/Tests/WTF/gobject/GUniquePtr.cpp | 195 -- .../Tests/WebCore/AffineTransform.cpp | 1024 +++++++ Tools/TestWebKitAPI/Tests/WebCore/CARingBuffer.cpp | 251 ++ Tools/TestWebKitAPI/Tests/WebCore/CSSParser.cpp | 84 + .../Tests/WebCore/CalculationValue.cpp | 283 ++ Tools/TestWebKitAPI/Tests/WebCore/Color.cpp | 190 ++ .../Tests/WebCore/ComplexTextController.cpp | 391 +++ .../Tests/WebCore/ContentExtensions.cpp | 2795 ++++++++++++++++++++ Tools/TestWebKitAPI/Tests/WebCore/DFACombiner.cpp | 121 + Tools/TestWebKitAPI/Tests/WebCore/DFAHelpers.h | 67 + Tools/TestWebKitAPI/Tests/WebCore/DFAMinimizer.cpp | 121 + .../TestWebKitAPI/Tests/WebCore/ExtendedColor.cpp | 162 ++ Tools/TestWebKitAPI/Tests/WebCore/FileSystem.cpp | 122 + Tools/TestWebKitAPI/Tests/WebCore/FloatPoint.cpp | 598 +++++ Tools/TestWebKitAPI/Tests/WebCore/FloatRect.cpp | 783 ++++++ Tools/TestWebKitAPI/Tests/WebCore/FloatSize.cpp | 328 +++ Tools/TestWebKitAPI/Tests/WebCore/GridPosition.cpp | 73 + .../Tests/WebCore/HTMLParserIdioms.cpp | 164 ++ Tools/TestWebKitAPI/Tests/WebCore/IntPoint.cpp | 283 ++ Tools/TestWebKitAPI/Tests/WebCore/IntRect.cpp | 615 +++++ Tools/TestWebKitAPI/Tests/WebCore/IntSize.cpp | 332 +++ Tools/TestWebKitAPI/Tests/WebCore/LayoutUnit.cpp | 42 +- .../Tests/WebCore/ParsedContentRange.cpp | 98 + Tools/TestWebKitAPI/Tests/WebCore/PublicSuffix.cpp | 78 + Tools/TestWebKitAPI/Tests/WebCore/SampleMap.cpp | 224 ++ .../TestWebKitAPI/Tests/WebCore/SecurityOrigin.cpp | 146 + Tools/TestWebKitAPI/Tests/WebCore/SharedBuffer.cpp | 163 ++ .../Tests/WebCore/SharedBufferTest.cpp | 56 + .../TestWebKitAPI/Tests/WebCore/SharedBufferTest.h | 46 + Tools/TestWebKitAPI/Tests/WebCore/TimeRanges.cpp | 291 ++ .../Tests/WebCore/TransformationMatrix.cpp | 1317 +++++++++ Tools/TestWebKitAPI/Tests/WebCore/URL.cpp | 54 +- Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp | 1305 +++++++++ .../Tests/WebCore/UserAgentQuirks.cpp | 96 + .../Tests/WebCore/YouTubePluginReplacement.cpp | 86 + .../Tests/WebCore/gtk/UserAgentQuirks.cpp | 63 - .../TestWebKitAPI/Tests/WebKit2/18-characters.html | 0 .../TestWebKitAPI/Tests/WebKit2/AboutBlankLoad.cpp | 5 + Tools/TestWebKitAPI/Tests/WebKit2/Ahem.ttf | Bin 0 -> 12480 bytes .../Tests/WebKit2/CanHandleRequest.cpp | 7 +- .../Tests/WebKit2/CanHandleRequest_Bundle.cpp | 7 +- .../Tests/WebKit2/CloseFromWithinCreatePage.cpp | 94 + .../Tests/WebKit2/CloseThenTerminate.cpp | 5 + .../TestWebKitAPI/Tests/WebKit2/CookieManager.cpp | 9 +- .../WKViewIsActiveSetIsActive.cpp | 131 + .../WKViewIsActiveSetIsActive_Bundle.cpp | 52 + .../WKViewRestoreZoomAndScrollBackForward.cpp | 129 + .../WKViewUserViewportToContents.cpp | 148 ++ .../WebKit2/CoordinatedGraphics/backforward1.html | 5 + .../WebKit2/CoordinatedGraphics/backforward2.html | 1 + .../Tests/WebKit2/DOMWindowExtensionBasic.cpp | 7 +- .../WebKit2/DOMWindowExtensionBasic_Bundle.cpp | 19 +- .../Tests/WebKit2/DOMWindowExtensionNoCache.cpp | 5 + .../WebKit2/DOMWindowExtensionNoCache_Bundle.cpp | 19 +- .../Tests/WebKit2/DidAssociateFormControls.cpp | 5 + .../WebKit2/DidAssociateFormControls_Bundle.cpp | 13 +- .../Tests/WebKit2/DidNotHandleKeyDown.cpp | 7 +- .../DidRemoveFrameFromHiearchyInPageCache.cpp | 109 + ...idRemoveFrameFromHiearchyInPageCache_Bundle.cpp | 75 + .../WebKit2/DocumentStartUserScriptAlertCrash.cpp | 7 +- .../DocumentStartUserScriptAlertCrash_Bundle.cpp | 13 +- .../WebKit2/DownloadDecideDestinationCrash.cpp | 9 +- .../Tests/WebKit2/EnumerateMediaDevices.cpp | 84 + .../EphemeralSessionPushStateNoHistoryCallback.cpp | 87 + .../Tests/WebKit2/EvaluateJavaScript.cpp | 9 +- .../TestWebKitAPI/Tests/WebKit2/EventModifiers.cpp | 82 + Tools/TestWebKitAPI/Tests/WebKit2/FailedLoad.cpp | 7 +- Tools/TestWebKitAPI/Tests/WebKit2/Find.cpp | 7 +- Tools/TestWebKitAPI/Tests/WebKit2/ForceRepaint.cpp | 7 +- Tools/TestWebKitAPI/Tests/WebKit2/FrameHandle.cpp | 70 + .../Tests/WebKit2/FrameMIMETypeHTML.cpp | 7 +- .../Tests/WebKit2/FrameMIMETypePNG.cpp | 7 +- Tools/TestWebKitAPI/Tests/WebKit2/Geolocation.cpp | 55 +- ...njectedBundleInitializationUserDataCallback.cpp | 7 +- ...BundleInitializationUserDataCallback_Bundle.cpp | 7 +- .../Tests/WebKit2/HitTestResultNodeHandle.cpp | 7 +- .../WebKit2/HitTestResultNodeHandle_Bundle.cpp | 13 +- .../Tests/WebKit2/InjectedBundleBasic.cpp | 7 +- .../Tests/WebKit2/InjectedBundleBasic_Bundle.cpp | 7 +- .../Tests/WebKit2/InjectedBundleFrameHitTest.cpp | 7 +- .../WebKit2/InjectedBundleFrameHitTest_Bundle.cpp | 17 +- ...tedBundleInitializationUserDataCallbackWins.cpp | 7 +- ...leInitializationUserDataCallbackWins_Bundle.cpp | 7 +- .../InjectedBundleMakeAllShadowRootsOpen.cpp | 109 + ...InjectedBundleMakeAllShadowRootsOpen_Bundle.cpp | 98 + .../LayoutMilestonesWithAllContentInFrame.cpp | 9 +- .../TestWebKitAPI/Tests/WebKit2/LimitTitleSize.cpp | 79 + .../LoadAlternateHTMLStringWithNonDirectoryURL.cpp | 37 +- .../LoadCanceledNoServerRedirectCallback.cpp | 11 +- ...LoadCanceledNoServerRedirectCallback_Bundle.cpp | 11 +- .../Tests/WebKit2/LoadPageOnCrash.cpp | 7 +- .../Tests/WebKit2/MenuTypesForMouseEvents.cpp | 149 ++ .../TestWebKitAPI/Tests/WebKit2/ModalAlertsSPI.cpp | 123 + .../Tests/WebKit2/MouseMoveAfterCrash.cpp | 9 +- .../Tests/WebKit2/MouseMoveAfterCrash_Bundle.cpp | 5 + .../WebKit2/NewFirstVisuallyNonEmptyLayout.cpp | 7 +- .../NewFirstVisuallyNonEmptyLayoutFails.cpp | 9 +- .../NewFirstVisuallyNonEmptyLayoutFails_Bundle.cpp | 9 +- .../NewFirstVisuallyNonEmptyLayoutForImages.cpp | 7 +- ...FirstVisuallyNonEmptyLayoutForImages_Bundle.cpp | 9 +- .../NewFirstVisuallyNonEmptyLayoutFrames.cpp | 11 +- ...NewFirstVisuallyNonEmptyLayoutFrames_Bundle.cpp | 9 +- .../NewFirstVisuallyNonEmptyLayout_Bundle.cpp | 9 +- Tools/TestWebKitAPI/Tests/WebKit2/PageGroup.cpp | 80 + .../TestWebKitAPI/Tests/WebKit2/PageLoadBasic.cpp | 27 +- ...PageLoadDidChangeLocationWithinPageForFrame.cpp | 7 +- Tools/TestWebKitAPI/Tests/WebKit2/ParentFrame.cpp | 7 +- .../Tests/WebKit2/ParentFrame_Bundle.cpp | 11 +- .../WebKit2/PasteboardNotifications_Bundle.cpp | 89 + .../Tests/WebKit2/PendingAPIRequestURL.cpp | 167 ++ .../Tests/WebKit2/PreventEmptyUserAgent.cpp | 9 +- .../PrivateBrowsingPushStateNoHistoryCallback.cpp | 32 +- .../ProvisionalURLAfterWillSendRequestCallback.cpp | 89 + ...ionalURLAfterWillSendRequestCallback_Bundle.cpp | 85 + .../Tests/WebKit2/ReloadPageAfterCrash.cpp | 7 +- .../WebKit2/ResizeReversePaginatedWebView.cpp | 11 +- .../Tests/WebKit2/ResizeWindowAfterCrash.cpp | 7 +- .../WebKit2/ResponsivenessTimerDoesntFireEarly.cpp | 5 + .../ResponsivenessTimerDoesntFireEarly_Bundle.cpp | 5 + .../RestoreSessionStateContainingFormData.cpp | 17 +- .../RestoreSessionStateWithoutNavigation.cpp | 105 + .../Tests/WebKit2/ScrollPinningBehaviors.cpp | 13 +- .../WebKit2/ShouldGoToBackForwardListItem.cpp | 7 +- .../ShouldGoToBackForwardListItem_Bundle.cpp | 9 +- .../ShouldKeepCurrentBackForwardListItemInList.cpp | 163 ++ .../Tests/WebKit2/SpacebarScrolling.cpp | 27 +- .../StopLoadingDuringDidFailProvisionalLoad.cpp | 83 + ...pLoadingDuringDidFailProvisionalLoad_bundle.cpp | 81 + .../TestWebKitAPI/Tests/WebKit2/TerminateTwice.cpp | 4 + .../WebKit2/TextFieldDidBeginAndEndEditing.cpp | 137 + .../TextFieldDidBeginAndEndEditing_Bundle.cpp | 76 + Tools/TestWebKitAPI/Tests/WebKit2/UserMedia.cpp | 85 + Tools/TestWebKitAPI/Tests/WebKit2/UserMessage.cpp | 13 +- .../Tests/WebKit2/UserMessage_Bundle.cpp | 5 + .../Tests/WebKit2/WKBundleFileHandle.cpp | 86 + .../Tests/WebKit2/WKBundleFileHandle_Bundle.cpp | 99 + .../Tests/WebKit2/WKImageCreateCGImageCrash.cpp | 41 + .../Tests/WebKit2/WKPageConfiguration.cpp | 132 + .../WKPageCopySessionStateWithFiltering.cpp | 136 + .../Tests/WebKit2/WKPageGetScaleFactorNotZero.cpp | 15 +- .../Tests/WebKit2/WKPageIsPlayingAudio.cpp | 152 ++ .../TestWebKitAPI/Tests/WebKit2/WKPreferences.cpp | 39 +- Tools/TestWebKitAPI/Tests/WebKit2/WKRetainPtr.cpp | 58 + Tools/TestWebKitAPI/Tests/WebKit2/WKString.cpp | 4 + .../Tests/WebKit2/WKStringJSString.cpp | 7 +- Tools/TestWebKitAPI/Tests/WebKit2/WebArchive.cpp | 135 + .../Tests/WebKit2/WebArchive_Bundle.cpp | 69 + .../WebKit2/WebCoreStatisticsWithNoWebProcess.cpp | 55 + Tools/TestWebKitAPI/Tests/WebKit2/WillLoad.cpp | 11 +- .../Tests/WebKit2/WillLoad_Bundle.cpp | 15 +- .../Tests/WebKit2/WillSendSubmitEvent.cpp | 5 + .../Tests/WebKit2/WillSendSubmitEvent_Bundle.cpp | 9 +- .../Tests/WebKit2/all-content-in-one-iframe.html | 1 + .../Tests/WebKit2/associate-form-controls.html | 31 + .../Tests/WebKit2/auto-submitting-form.html | 20 + .../Tests/WebKit2/autoplay-check-frame.html | 16 + .../Tests/WebKit2/autoplay-check-in-iframe.html | 16 + .../Tests/WebKit2/autoplay-check.html | 20 + .../Tests/WebKit2/autoplay-no-audio-check.html | 20 + .../Tests/WebKit2/autoplay-with-controls.html | 19 + Tools/TestWebKitAPI/Tests/WebKit2/bundle-file.html | 16 + .../WebKit2/chinese-character-with-image.html | 15 + .../WebKit2/close-from-within-create-page.html | 16 + .../Tests/WebKit2/closed-shadow-tree-test.html | 28 + .../Tests/WebKit2/contentBlockerCheck.html | 13 + .../Tests/WebKit2/custom-protocol-sync-xhr.html | 6 + .../Tests/WebKit2/enumerateMediaDevices.html | 24 + Tools/TestWebKitAPI/Tests/WebKit2/execCopy.html | 15 + .../Tests/WebKit2/file-with-anchor.html | 19 + .../TestWebKitAPI/Tests/WebKit2/file-with-mse.html | 41 + .../Tests/WebKit2/file-with-video.html | 18 + Tools/TestWebKitAPI/Tests/WebKit2/find.html | 5 + Tools/TestWebKitAPI/Tests/WebKit2/findRanges.html | 11 + .../WebKit2/geolocationGetCurrentPosition.html | 3 + ...locationGetCurrentPositionWithHighAccuracy.html | 3 + .../Tests/WebKit2/geolocationWatchPosition.html | 3 + .../geolocationWatchPositionWithHighAccuracy.html | 3 + .../TestWebKitAPI/Tests/WebKit2/getUserMedia.html | 14 + .../Tests/WebKit2/gtk/InputMethodFilter.cpp | 258 ++ Tools/TestWebKitAPI/Tests/WebKit2/icon.png | Bin 0 -> 36541 bytes .../Tests/WebKit2/input-focus-blur.html | 28 + .../Tests/WebKit2/js-play-with-controls.html | 20 + .../WebKit2/link-with-download-attribute.html | 10 + .../Tests/WebKit2/link-with-title.html | 5 + .../Tests/WebKit2/lots-of-iframes.html | 35 + .../Tests/WebKit2/lots-of-images.html | 17 + .../Tests/WebKit2/lots-of-text-vertical-lr.html | 3 + .../TestWebKitAPI/Tests/WebKit2/lots-of-text.html | 3 + .../TestWebKitAPI/Tests/WebKit2/many-iframes.html | 15 + .../modal-alerts-in-new-about-blank-window.html | 13 + .../Tests/WebKit2/mouse-button-listener.html | 30 + .../Tests/WebKit2/mouse-move-listener.html | 16 + .../Tests/WebKit2/no-autoplay-with-controls.html | 25 + .../Tests/WebKit2/open-and-close-window.html | 11 + Tools/TestWebKitAPI/Tests/WebKit2/push-state.html | 3 + .../Tests/WebKit2/set-long-title.html | 10 + .../WebKit2/should-open-external-schemes.html | 21 + .../WebKit2/simple-accelerated-compositing.html | 5 + Tools/TestWebKitAPI/Tests/WebKit2/simple-form.html | 11 + .../TestWebKitAPI/Tests/WebKit2/simple-iframe.html | 6 + Tools/TestWebKitAPI/Tests/WebKit2/simple-tall.html | 7 + Tools/TestWebKitAPI/Tests/WebKit2/simple.html | 5 + Tools/TestWebKitAPI/Tests/WebKit2/simple2.html | 5 + Tools/TestWebKitAPI/Tests/WebKit2/simple3.html | 5 + .../Tests/WebKit2/spacebar-scrolling.html | 26 + Tools/TestWebKitAPI/Tests/WebKit2/test-mse.mp4 | Bin 0 -> 80933 bytes .../Tests/WebKit2/test-without-audio-track.mp4 | Bin 0 -> 189906 bytes Tools/TestWebKitAPI/Tests/WebKit2/test.mp4 | Bin 0 -> 192844 bytes Tools/TestWebKitAPI/Tests/WebKit2/webfont.html | 15 + Tools/TestWebKitAPI/Tests/WebKit2Cocoa/AllAhem.svg | 111 + .../Tests/WebKit2Cocoa/ApplicationCache.db | Bin 0 -> 4096 bytes .../Tests/WebKit2Cocoa/ApplicationCache.db-shm | Bin 0 -> 32768 bytes .../Tests/WebKit2Cocoa/ApplicationCache.db-wal | Bin 0 -> 168952 bytes .../WebKit2Cocoa/BundleEditingDelegateProtocol.h | 40 + .../Tests/WebKit2Cocoa/BundleRangeHandleProtocol.h | 35 + .../Tests/WebKit2Cocoa/ContentFiltering.h | 28 + .../Tests/WebKit2Cocoa/ContentFiltering.html | 6 + .../Tests/WebKit2Cocoa/CookieMessage.html | 4 + .../Tests/WebKit2Cocoa/DownloadRequestBlobURL.html | 16 + .../WebKit2Cocoa/DownloadRequestOriginalURL.html | 10 + .../WebKit2Cocoa/DownloadRequestOriginalURL2.html | 6 + .../DownloadRequestOriginalURLFrame.html | 10 + .../Tests/WebKit2Cocoa/FullscreenDelegate.html | 31 + .../WebKit2Cocoa/FullscreenLayoutConstraints.html | 31 + .../WebKit2Cocoa/FullscreenTopContentInset.html | 31 + .../Tests/WebKit2Cocoa/IDBDeleteRecovery.html | 14 + .../Tests/WebKit2Cocoa/IDBDeleteRecovery.sqlite3 | Bin 0 -> 4096 bytes .../WebKit2Cocoa/IDBDeleteRecovery.sqlite3-shm | Bin 0 -> 32768 bytes .../WebKit2Cocoa/IDBDeleteRecovery.sqlite3-wal | Bin 0 -> 164832 bytes .../Tests/WebKit2Cocoa/IDBIndexUpgradeToV2.html | 21 + .../Tests/WebKit2Cocoa/IndexUpgrade.blob | 1 + .../Tests/WebKit2Cocoa/IndexUpgrade.sqlite3 | Bin 0 -> 65536 bytes .../IndexedDBDatabaseProcessKill-1.html | 33 + .../WebKit2Cocoa/IndexedDBMultiProcess-1.html | 46 + .../WebKit2Cocoa/IndexedDBMultiProcess-2.html | 92 + .../WebKit2Cocoa/IndexedDBMultiProcess-3.html | 21 + .../Tests/WebKit2Cocoa/IndexedDBPersistence-1.html | 35 + .../Tests/WebKit2Cocoa/IndexedDBPersistence-2.html | 22 + .../Tests/WebKit2Cocoa/LineBreaking.html | 45 + .../Tests/WebKit2Cocoa/LocalStorageClear.html | 6 + .../WebKit2Cocoa/LocalStorageNullEntries.html | 6 + .../LocalStorageNullEntries.localstorage | Bin 0 -> 12288 bytes .../LocalStorageNullEntries.localstorage-shm | Bin 0 -> 32768 bytes .../WebKit2Cocoa/LocalStorageQuirkEnabled.html | 10 + .../Tests/WebKit2Cocoa/RemoteObjectRegistry.h | 51 + .../Tests/WebKit2Cocoa/StoreBlobToBeDeleted.html | 41 + .../Tests/WebKit2Cocoa/UserContentWorldProtocol.h | 37 + .../WebKit2Cocoa/WebProcessKillIDBCleanup-1.html | 67 + .../WebKit2Cocoa/WebProcessKillIDBCleanup-2.html | 25 + .../Tests/WebKit2Cocoa/autofocused-text-input.html | 3 + .../WebKit2Cocoa/autoplaying-video-with-audio.html | 34 + .../Tests/WebKit2Cocoa/blinking-div.html | 23 + .../WebKit2Cocoa/change-video-source-on-click.html | 33 + .../WebKit2Cocoa/change-video-source-on-end.html | 35 + .../duplicate-completion-handler-calls.html | 9 + .../Tests/WebKit2Cocoa/editable-body.html | 7 + .../WebKit2Cocoa/enormous-video-with-sound.html | 15 + .../Tests/WebKit2Cocoa/focus-inputs.html | 15 + .../full-size-autoplaying-video-with-audio.html | 23 + .../input-field-in-scrollable-document.html | 36 + .../large-input-field-focus-onload.html | 38 + ...rge-video-hides-controls-after-seek-to-end.html | 40 + .../WebKit2Cocoa/large-video-mutes-onplaying.html | 16 + .../Tests/WebKit2Cocoa/large-video-offscreen.html | 29 + .../large-video-playing-scroll-away.html | 36 + .../large-video-seek-after-ending.html | 21 + ...eo-seek-to-beginning-and-play-after-ending.html | 23 + .../WebKit2Cocoa/large-video-test-now-playing.html | 33 + .../Tests/WebKit2Cocoa/large-video-with-audio.html | 12 + .../Tests/WebKit2Cocoa/large-video-with-audio.mp4 | Bin 0 -> 1088986 bytes .../WebKit2Cocoa/large-video-without-audio.html | 29 + .../large-videos-autoplaying-click-to-pause.html | 47 + .../large-videos-autoplaying-scroll-to-video.html | 35 + .../large-videos-paused-video-hides-controls.html | 38 + ...-videos-playing-muted-video-hides-controls.html | 36 + .../large-videos-playing-video-keeps-controls.html | 35 + .../large-videos-with-audio-autoplay.html | 18 + .../WebKit2Cocoa/large-videos-with-audio.html | 18 + .../WebKit2Cocoa/open-multiple-external-url.html | 66 + .../Tests/WebKit2Cocoa/page-with-csp-iframe.html | 14 + .../Tests/WebKit2Cocoa/page-with-csp.html | 15 + .../WebKit2Cocoa/page-without-csp-iframe.html | 11 + .../Tests/WebKit2Cocoa/page-without-csp.html | 12 + .../Tests/WebKit2Cocoa/play-audio-on-click.html | 54 + .../skinny-autoplaying-video-with-audio.html | 23 + .../WebKit2Cocoa/text-and-password-inputs.html | 39 + .../wide-autoplaying-video-with-audio.html | 23 + .../Tests/WebKit2Gtk/AutocleanupsTest.cpp | 72 + .../TestWebKitAPI/Tests/WebKit2Gtk/CMakeLists.txt | 135 + .../Tests/WebKit2Gtk/DOMDOMWindowTest.cpp | 221 ++ .../Tests/WebKit2Gtk/DOMNodeFilterTest.cpp | 204 ++ .../TestWebKitAPI/Tests/WebKit2Gtk/DOMNodeTest.cpp | 122 +- .../Tests/WebKit2Gtk/DOMXPathNSResolverTest.cpp | 124 + .../TestWebKitAPI/Tests/WebKit2Gtk/EditorTest.cpp | 131 + Tools/TestWebKitAPI/Tests/WebKit2Gtk/FrameTest.cpp | 3 + .../Tests/WebKit2Gtk/TestAuthentication.cpp | 36 +- .../Tests/WebKit2Gtk/TestAutocleanups.cpp | 70 + .../Tests/WebKit2Gtk/TestBackForwardList.cpp | 137 + .../Tests/WebKit2Gtk/TestConsoleMessage.cpp | 155 ++ .../Tests/WebKit2Gtk/TestContextMenu.cpp | 370 ++- .../Tests/WebKit2Gtk/TestCookieManager.cpp | 71 +- .../Tests/WebKit2Gtk/TestDOMDOMWindow.cpp | 152 ++ .../TestWebKitAPI/Tests/WebKit2Gtk/TestDOMNode.cpp | 37 +- .../Tests/WebKit2Gtk/TestDOMNodeFilter.cpp | 55 + .../Tests/WebKit2Gtk/TestDOMXPathNSResolver.cpp | 52 + .../Tests/WebKit2Gtk/TestDownloads.cpp | 351 ++- .../TestWebKitAPI/Tests/WebKit2Gtk/TestEditor.cpp | 42 + Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestFrame.cpp | 2 - .../Tests/WebKit2Gtk/TestInspector.cpp | 17 +- .../Tests/WebKit2Gtk/TestInspectorServer.cpp | 12 +- .../Tests/WebKit2Gtk/TestLoaderClient.cpp | 211 +- .../Tests/WebKit2Gtk/TestMultiprocess.cpp | 77 +- .../Tests/WebKit2Gtk/TestPrinting.cpp | 207 +- .../Tests/WebKit2Gtk/TestResources.cpp | 108 +- Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestSSL.cpp | 210 +- .../Tests/WebKit2Gtk/TestUIClient.cpp | 469 +++- .../Tests/WebKit2Gtk/TestWebExtensions.cpp | 130 +- .../Tests/WebKit2Gtk/TestWebKitAccessibility.cpp | 5 +- .../Tests/WebKit2Gtk/TestWebKitFaviconDatabase.cpp | 69 +- .../Tests/WebKit2Gtk/TestWebKitFindController.cpp | 2 +- .../Tests/WebKit2Gtk/TestWebKitPolicyClient.cpp | 15 +- .../Tests/WebKit2Gtk/TestWebKitSecurityOrigin.cpp | 142 + .../Tests/WebKit2Gtk/TestWebKitSettings.cpp | 23 +- .../WebKit2Gtk/TestWebKitUserContentManager.cpp | 360 +++ .../Tests/WebKit2Gtk/TestWebKitWebContext.cpp | 412 ++- .../Tests/WebKit2Gtk/TestWebKitWebView.cpp | 561 +++- .../Tests/WebKit2Gtk/TestWebKitWebViewGroup.cpp | 206 -- .../Tests/WebKit2Gtk/TestWebViewEditor.cpp | 328 ++- .../Tests/WebKit2Gtk/TestWebsiteData.cpp | 537 ++++ .../Tests/WebKit2Gtk/WebExtensionTest.cpp | 199 +- .../Tests/WebKit2Gtk/WebProcessTest.cpp | 33 +- .../Tests/WebKit2Gtk/WebProcessTest.h | 4 +- .../Tests/WebKit2Gtk/resources/blank.ico | Bin 0 -> 198 bytes .../Tests/WebKit2Gtk/resources/boring.html | 1 + .../Tests/WebKit2Gtk/resources/link-title.js | 1 + .../Tests/WebKit2Gtk/resources/silence.mpg | Bin 0 -> 33227 bytes .../Tests/WebKit2Gtk/resources/simple.json | 1 + .../Tests/WebKit2Gtk/resources/test-cert.pem | 13 + .../Tests/WebKit2Gtk/resources/test-key.pem | 16 + .../Tests/WebKit2Gtk/resources/track.ogg | Bin 0 -> 3869 bytes .../resources/webkit2gtk-tests.gresource.xml | 7 + .../CustomProtocolsInvalidScheme_Bundle.cpp | 66 + .../PreventImageLoadWithAutoResizing_Bundle.cpp | 69 + Tools/TestWebKitAPI/Tests/WebKitGtk/test_utils.c | 51 - .../Tests/WebKitGtk/testapplicationcache.c | 49 - Tools/TestWebKitAPI/Tests/WebKitGtk/testatk.c | 1476 ----------- Tools/TestWebKitAPI/Tests/WebKitGtk/testatkroles.c | 426 --- .../Tests/WebKitGtk/testcontextmenu.c | 317 --- .../Tests/WebKitGtk/testcopyandpaste.c | 266 -- .../Tests/WebKitGtk/testdomdocument.c | 445 ---- .../Tests/WebKitGtk/testdomdomwindow.c | 258 -- Tools/TestWebKitAPI/Tests/WebKitGtk/testdomnode.c | 219 -- Tools/TestWebKitAPI/Tests/WebKitGtk/testdownload.c | 325 --- .../Tests/WebKitGtk/testfavicondatabase.c | 279 -- Tools/TestWebKitAPI/Tests/WebKitGtk/testglobals.c | 110 - .../Tests/WebKitGtk/testhittestresult.c | 171 -- .../Tests/WebKitGtk/testhttpbackend.c | 75 - .../TestWebKitAPI/Tests/WebKitGtk/testkeyevents.c | 390 --- Tools/TestWebKitAPI/Tests/WebKitGtk/testloading.c | 437 --- .../Tests/WebKitGtk/testmimehandling.c | 206 -- .../Tests/WebKitGtk/testnetworkrequest.c | 96 - .../Tests/WebKitGtk/testnetworkresponse.c | 97 - .../Tests/WebKitGtk/testwebbackforwardlist.c | 326 --- .../Tests/WebKitGtk/testwebdatasource.c | 242 -- Tools/TestWebKitAPI/Tests/WebKitGtk/testwebframe.c | 220 -- .../Tests/WebKitGtk/testwebhistoryitem.c | 70 - .../Tests/WebKitGtk/testwebinspector.c | 173 -- .../Tests/WebKitGtk/testwebplugindatabase.c | 78 - .../Tests/WebKitGtk/testwebresource.c | 334 --- .../Tests/WebKitGtk/testwebsettings.c | 110 - Tools/TestWebKitAPI/Tests/WebKitGtk/testwebview.c | 749 ------ Tools/TestWebKitAPI/Tests/WebKitGtk/testwindow.c | 119 - .../TestWebKitAPI/Tests/gtk/InputMethodFilter.cpp | 310 --- Tools/TestWebKitAPI/TestsController.cpp | 33 +- Tools/TestWebKitAPI/TestsController.h | 6 +- Tools/TestWebKitAPI/Utilities.h | 36 + Tools/TestWebKitAPI/WKWebViewConfigurationExtras.h | 34 + Tools/TestWebKitAPI/WTFStringUtilities.h | 13 +- Tools/TestWebKitAPI/config.h | 38 +- Tools/TestWebKitAPI/gtk/PlatformUtilitiesGtk.cpp | 6 +- Tools/TestWebKitAPI/gtk/PlatformWebViewGtk.cpp | 40 +- .../gtk/WebKit2Gtk/LoadTrackingTest.cpp | 83 +- .../gtk/WebKit2Gtk/LoadTrackingTest.h | 6 +- Tools/TestWebKitAPI/gtk/WebKit2Gtk/TestMain.cpp | 23 +- Tools/TestWebKitAPI/gtk/WebKit2Gtk/TestMain.h | 80 +- .../TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestBus.cpp | 59 +- Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebKitTestBus.h | 6 +- .../gtk/WebKit2Gtk/WebKitTestServer.cpp | 26 +- .../gtk/WebKit2Gtk/WebKitTestServer.h | 13 +- Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebViewTest.cpp | 100 +- Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebViewTest.h | 31 +- Tools/TestWebKitAPI/gtk/main.cpp | 2 +- .../jsconly/PlatformUtilitiesJSCOnly.cpp | 57 + Tools/TestWebKitAPI/jsconly/main.cpp | 32 + Tools/WebKitTestRunner/CMakeLists.txt | 121 + Tools/WebKitTestRunner/DerivedSources.make | 62 + Tools/WebKitTestRunner/EventSenderProxy.h | 27 +- Tools/WebKitTestRunner/FontWithFeatures.otf | Bin 0 -> 14452 bytes Tools/WebKitTestRunner/FontWithFeatures.ttf | Bin 0 -> 12324 bytes Tools/WebKitTestRunner/GNUmakefile.am | 175 -- Tools/WebKitTestRunner/GeolocationProviderMock.cpp | 4 +- Tools/WebKitTestRunner/GeolocationProviderMock.h | 4 +- .../InjectedBundle/AccessibilityController.cpp | 47 +- .../InjectedBundle/AccessibilityController.h | 31 +- .../InjectedBundle/AccessibilityTextMarker.cpp | 10 +- .../InjectedBundle/AccessibilityTextMarker.h | 17 +- .../AccessibilityTextMarkerRange.cpp | 10 +- .../InjectedBundle/AccessibilityTextMarkerRange.h | 17 +- .../InjectedBundle/AccessibilityUIElement.cpp | 195 +- .../InjectedBundle/AccessibilityUIElement.h | 129 +- .../Bindings/AccessibilityController.idl | 45 + .../Bindings/AccessibilityTextMarker.idl | 29 + .../Bindings/AccessibilityTextMarkerRange.idl | 29 + .../Bindings/AccessibilityUIElement.idl | 249 ++ .../Bindings/CodeGeneratorTestRunner.pm | 577 ++++ .../Bindings/EventSendingController.idl | 72 + .../InjectedBundle/Bindings/GCController.idl | 31 + .../InjectedBundle/Bindings/JSWrappable.h | 47 - .../InjectedBundle/Bindings/JSWrapper.cpp | 80 - .../InjectedBundle/Bindings/JSWrapper.h | 57 - .../InjectedBundle/Bindings/TestRunner.idl | 262 ++ .../Bindings/TextInputController.idl | 32 + .../InjectedBundle/EventSendingController.cpp | 332 ++- .../InjectedBundle/EventSendingController.h | 25 +- .../InjectedBundle/GCController.cpp | 12 +- .../WebKitTestRunner/InjectedBundle/GCController.h | 9 +- .../InjectedBundle/InjectedBundle.cpp | 373 ++- .../InjectedBundle/InjectedBundle.h | 58 +- .../InjectedBundle/InjectedBundleMain.cpp | 4 +- .../InjectedBundle/InjectedBundlePage.cpp | 557 ++-- .../InjectedBundle/InjectedBundlePage.h | 7 +- .../WebKitTestRunner/InjectedBundle/TestRunner.cpp | 853 +++++- Tools/WebKitTestRunner/InjectedBundle/TestRunner.h | 141 +- .../InjectedBundle/TextInputController.cpp | 14 +- .../InjectedBundle/TextInputController.h | 9 +- .../atk/AccessibilityControllerAtk.cpp | 37 +- .../atk/AccessibilityNotificationHandlerAtk.cpp | 72 +- .../atk/AccessibilityNotificationHandlerAtk.h | 13 +- .../atk/AccessibilityUIElementAtk.cpp | 634 ++++- .../InjectedBundle/gtk/ActivateFontsGtk.cpp | 10 +- .../InjectedBundle/gtk/InjectedBundleUtilities.cpp | 6 +- .../InjectedBundle/gtk/InjectedBundleUtilities.h | 2 +- .../InjectedBundle/gtk/TestRunnerGtk.cpp | 25 +- Tools/WebKitTestRunner/Options.cpp | 43 +- Tools/WebKitTestRunner/Options.h | 9 +- Tools/WebKitTestRunner/PixelDumpSupport.cpp | 2 +- Tools/WebKitTestRunner/PixelDumpSupport.h | 2 +- Tools/WebKitTestRunner/PlatformGTK.cmake | 60 + Tools/WebKitTestRunner/PlatformWebView.h | 74 +- Tools/WebKitTestRunner/StringFunctions.h | 10 +- Tools/WebKitTestRunner/TestController.cpp | 1648 +++++++++--- Tools/WebKitTestRunner/TestController.h | 264 +- Tools/WebKitTestRunner/TestInvocation.cpp | 772 ++++-- Tools/WebKitTestRunner/TestInvocation.h | 74 +- Tools/WebKitTestRunner/TestOptions.cpp | 76 + Tools/WebKitTestRunner/TestOptions.h | 58 + Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h | 7 +- Tools/WebKitTestRunner/WebNotificationProvider.cpp | 116 +- Tools/WebKitTestRunner/WebNotificationProvider.h | 16 +- Tools/WebKitTestRunner/WorkQueueManager.cpp | 22 +- Tools/WebKitTestRunner/WorkQueueManager.h | 5 +- .../WebKitTestRunner/cairo/TestInvocationCairo.cpp | 11 +- Tools/WebKitTestRunner/config.h | 38 + Tools/WebKitTestRunner/gtk/EventSenderProxyGtk.cpp | 43 +- Tools/WebKitTestRunner/gtk/PlatformWebViewGtk.cpp | 95 +- Tools/WebKitTestRunner/gtk/TestControllerGtk.cpp | 83 +- Tools/WebKitTestRunner/gtk/fonts/AHEM____.TTF | Bin 0 -> 12480 bytes .../gtk/fonts/FontWithNoValidEncoding.fon | Bin 0 -> 8368 bytes Tools/WebKitTestRunner/gtk/fonts/fonts.conf | 435 +++ Tools/WebKitTestRunner/gtk/main.cpp | 9 + Tools/gtk/GNUmakefile.am | 153 -- Tools/gtk/check-for-webkitdom-api-breaks | 78 - Tools/gtk/common.py | 52 +- Tools/gtk/generate-feature-defines-files | 58 - Tools/gtk/generate-gtkdoc | 64 +- Tools/gtk/generate-inspector-gresource-manifest.py | 14 +- Tools/gtk/gtkdoc.py | 28 +- Tools/gtk/install-dependencies | 479 ++++ Tools/gtk/jhbuild.modules | 628 +++++ Tools/gtk/jhbuildrc | 44 + Tools/gtk/make-dist.py | 333 +++ Tools/gtk/manifest.txt.in | 106 + ...es-a-space-between-literal-and-identifier.patch | 30 + Tools/gtk/patches/fontconfig-fix-osx-cache.diff | 207 ++ ...freetype6-2.4.11-truetype-font-height-fix.patch | 39 + ...te-suppress-string-format-literal-warning.patch | 29 + Tools/gtk/patches/glib-warning-fix.patch | 34 + ...ugins-bad-0001-dtls-port-to-OpenSSL-1.1.0.patch | 236 ++ ...cate-Fix-error-checking-in-RSA_generate_k.patch | 37 + ...line-gets-an-EOS-when-any-rtpsources-byes.patch | 156 ++ ...d-generating-errors-when-rtcp-messages-ar.patch | 61 + ...s-good-0003-rtpbin-receive-bundle-support.patch | 1018 +++++++ ...ux-add-context-for-a-preferred-protection.patch | 320 +++ ...mux-expose-streams-with-first-moof-for-fr.patch | 133 + ...gst-plugins-good-use-the-tfdt-decode-time.patch | 89 + ...ction-added-function-to-filter-system-ids.patch | 77 + .../gtk+-configure-fix-detecting-CUPS-2.x.patch | 11 + Tools/gtk/patches/icudata-stdlibs.patch | 15 + ...libnice-0001-TURN-allow-REALM-to-be-empty.patch | 50 + ...n-the-agent-mainloop-in-a-separate-thread.patch | 253 ++ ...1-bump-up-config.guess-to-support-aarch64.patch | 1581 +++++++++++ ...ync-authentication-when-flag-SOUP_MESSAGE.patch | 130 + ...-use-cached-credentials-in-lookup-method-.patch | 114 + ...allivm-Fix-build-after-LLVM-commit-211259.patch | 29 + Tools/gtk/patches/openh264-configure.patch | 12 + ...spsrc-timeout-on-udpsrc-is-in-nanoseconds.patch | 27 + Tools/gtk/patches/shared-mime-info-xht-glob.patch | 21 + .../gtk/patches/shared-mime-info-xhtml-magic.patch | 26 + Tools/gtk/patches/udpsrc-improve-timeouts.patch | 53 + .../xserver-remove-bogus-dependencies.patch | 43 + ...DRI-drivers-at-LIBGL_DRIVERS_PATH-environ.patch | 84 + Tools/gtk/webkitdom.py | 285 -- Tools/gtk/ycm_extra_conf.py | 132 + Tools/jhbuild/jhbuildutils.py | 56 + 680 files changed, 61975 insertions(+), 23427 deletions(-) create mode 100644 Tools/CMakeLists.txt create mode 100644 Tools/DumpRenderTree/Bindings/CodeGeneratorDumpRenderTree.pm create mode 100644 Tools/DumpRenderTree/CMakeLists.txt create mode 100644 Tools/DumpRenderTree/DefaultPolicyDelegate.h create mode 100644 Tools/DumpRenderTree/DerivedSources.make create mode 100644 Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.h create mode 100644 Tools/DumpRenderTree/ForwardingHeaders/runtime/ArrayBufferView.h create mode 100644 Tools/DumpRenderTree/ForwardingHeaders/runtime/JSArrayBufferView.h create mode 100644 Tools/DumpRenderTree/ForwardingHeaders/runtime/JSExportMacros.h create mode 100644 Tools/DumpRenderTree/ForwardingHeaders/runtime/TypedArrayInlines.h create mode 100644 Tools/DumpRenderTree/JavaScriptThreading.cpp create mode 100644 Tools/DumpRenderTree/TestNetscapePlugIn/CMakeLists.txt create mode 100644 Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npapi.h create mode 100644 Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npfunctions.h create mode 100644 Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npruntime.h create mode 100644 Tools/DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSWithinNPP_New.cpp create mode 100644 Tools/DumpRenderTree/TestNetscapePlugIn/Tests/InvokeDestroysPluginWithinNPP_New.cpp create mode 100644 Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PluginScriptableObjectOverridesAllProperties.cpp create mode 100644 Tools/DumpRenderTree/TestNetscapePlugIn/Tests/SlowNPPNew.cpp create mode 100644 Tools/DumpRenderTree/TestNetscapePlugIn/Tests/URLRedirect.cpp delete mode 100644 Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npapi.h delete mode 100644 Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npfunctions.h delete mode 100644 Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npruntime.h create mode 100644 Tools/DumpRenderTree/TestOptions.h create mode 100644 Tools/DumpRenderTree/TextInputController.h delete mode 100644 Tools/DumpRenderTree/atk/AccessibilityCallbacks.h delete mode 100644 Tools/DumpRenderTree/atk/AccessibilityCallbacksAtk.cpp delete mode 100644 Tools/DumpRenderTree/atk/AccessibilityControllerAtk.cpp delete mode 100644 Tools/DumpRenderTree/atk/AccessibilityNotificationHandlerAtk.cpp delete mode 100644 Tools/DumpRenderTree/atk/AccessibilityNotificationHandlerAtk.h delete mode 100644 Tools/DumpRenderTree/atk/AccessibilityUIElementAtk.cpp delete mode 100644 Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp delete mode 100644 Tools/DumpRenderTree/gtk/DumpRenderTree.cpp delete mode 100644 Tools/DumpRenderTree/gtk/DumpRenderTreeGtk.h delete mode 100644 Tools/DumpRenderTree/gtk/EditingCallbacks.cpp delete mode 100644 Tools/DumpRenderTree/gtk/EditingCallbacks.h delete mode 100644 Tools/DumpRenderTree/gtk/EventSender.cpp delete mode 100644 Tools/DumpRenderTree/gtk/EventSender.h delete mode 100644 Tools/DumpRenderTree/gtk/GCControllerGtk.cpp delete mode 100644 Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp delete mode 100644 Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.cpp delete mode 100644 Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.h delete mode 100644 Tools/DumpRenderTree/gtk/TestRunnerGtk.cpp delete mode 100644 Tools/DumpRenderTree/gtk/TextInputController.cpp delete mode 100644 Tools/DumpRenderTree/gtk/TextInputController.h delete mode 100644 Tools/DumpRenderTree/gtk/WorkQueueItemGtk.cpp delete mode 100644 Tools/GNUmakefile.am delete mode 100644 Tools/GtkLauncher/GNUmakefile.am delete mode 100644 Tools/GtkLauncher/LauncherInspectorWindow.c delete mode 100644 Tools/GtkLauncher/LauncherInspectorWindow.h delete mode 100644 Tools/GtkLauncher/main.c create mode 100644 Tools/ImageDiff/CMakeLists.txt create mode 100644 Tools/ImageDiff/PlatformGTK.cmake create mode 100644 Tools/MiniBrowser/MBToolbarItem.h create mode 100644 Tools/MiniBrowser/MiniBrowserWebProcessPlugIn.h create mode 100644 Tools/MiniBrowser/gtk/BrowserTab.c create mode 100644 Tools/MiniBrowser/gtk/BrowserTab.h create mode 100644 Tools/MiniBrowser/gtk/CMakeLists.txt delete mode 100644 Tools/MiniBrowser/gtk/GNUmakefile.am create mode 100644 Tools/Scripts/VCSUtils.pm create mode 100755 Tools/Scripts/run-gtk-tests create mode 100755 Tools/Scripts/webkit-build-directory create mode 100755 Tools/Scripts/webkitdirs.pm create mode 100644 Tools/TestWebKitAPI/CMakeLists.txt create mode 100644 Tools/TestWebKitAPI/Counters.cpp create mode 100644 Tools/TestWebKitAPI/Counters.h create mode 100644 Tools/TestWebKitAPI/ForwardingHeaders/WebCore/LayoutUnit.h delete mode 100644 Tools/TestWebKitAPI/GNUmakefile.am create mode 100644 Tools/TestWebKitAPI/PlatformGTK.cmake create mode 100644 Tools/TestWebKitAPI/PlatformJSCOnly.cmake delete mode 100644 Tools/TestWebKitAPI/Tests/JavaScriptCore/VMInspector.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/BloomFilter.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/Condition.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/Consume.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/CrossThreadTask.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/DateMath.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/DeletedAddressOfOperator.h create mode 100644 Tools/TestWebKitAPI/Tests/WTF/Deque.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/EnumTraits.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/Expected.cpp delete mode 100644 Tools/TestWebKitAPI/Tests/WTF/Functional.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/HashCountedSet.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/LEBDecoder.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/Lock.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/NakedPtr.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/OptionSet.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/Optional.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/ParkingLot.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/RefCounter.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/RefLogger.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/RunLoop.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/Scope.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/ScopedLambda.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/SetForScope.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/StringConcatenate.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/StringView.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/SynchronizedFixedQueue.cpp delete mode 100644 Tools/TestWebKitAPI/Tests/WTF/TemporaryChange.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/TextBreakIterator.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/Time.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/UniqueRef.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/Variant.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/WTFString.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/WeakPtr.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/WorkQueue.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/darwin/OSObjectPtr.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/glib/GUniquePtr.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WTF/glib/WorkQueueGLib.cpp delete mode 100644 Tools/TestWebKitAPI/Tests/WTF/gobject/GUniquePtr.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/AffineTransform.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/CARingBuffer.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/CSSParser.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/CalculationValue.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/Color.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/ComplexTextController.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/DFACombiner.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/DFAHelpers.h create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/DFAMinimizer.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/ExtendedColor.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/FileSystem.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/FloatPoint.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/FloatRect.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/FloatSize.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/GridPosition.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/HTMLParserIdioms.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/IntPoint.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/IntRect.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/IntSize.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/ParsedContentRange.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/PublicSuffix.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/SampleMap.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/SecurityOrigin.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/SharedBuffer.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/SharedBufferTest.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/SharedBufferTest.h create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/TimeRanges.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/TransformationMatrix.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/UserAgentQuirks.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebCore/YouTubePluginReplacement.cpp delete mode 100644 Tools/TestWebKitAPI/Tests/WebCore/gtk/UserAgentQuirks.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/18-characters.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/Ahem.ttf create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/CloseFromWithinCreatePage.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/WKViewIsActiveSetIsActive.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/WKViewIsActiveSetIsActive_Bundle.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/WKViewRestoreZoomAndScrollBackForward.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/WKViewUserViewportToContents.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/backforward1.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/CoordinatedGraphics/backforward2.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/DidRemoveFrameFromHiearchyInPageCache.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/DidRemoveFrameFromHiearchyInPageCache_Bundle.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/EnumerateMediaDevices.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/EphemeralSessionPushStateNoHistoryCallback.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/EventModifiers.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/FrameHandle.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleMakeAllShadowRootsOpen.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleMakeAllShadowRootsOpen_Bundle.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/LimitTitleSize.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/MenuTypesForMouseEvents.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/ModalAlertsSPI.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/PageGroup.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/PasteboardNotifications_Bundle.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/PendingAPIRequestURL.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/ProvisionalURLAfterWillSendRequestCallback.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/ProvisionalURLAfterWillSendRequestCallback_Bundle.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/RestoreSessionStateWithoutNavigation.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/ShouldKeepCurrentBackForwardListItemInList.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/StopLoadingDuringDidFailProvisionalLoad.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/StopLoadingDuringDidFailProvisionalLoad_bundle.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/TextFieldDidBeginAndEndEditing.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/TextFieldDidBeginAndEndEditing_Bundle.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/UserMedia.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/WKBundleFileHandle.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/WKBundleFileHandle_Bundle.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/WKImageCreateCGImageCrash.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/WKPageConfiguration.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/WKPageCopySessionStateWithFiltering.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/WKPageIsPlayingAudio.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/WKRetainPtr.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/WebArchive.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/WebArchive_Bundle.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/WebCoreStatisticsWithNoWebProcess.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/all-content-in-one-iframe.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/associate-form-controls.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/auto-submitting-form.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/autoplay-check-frame.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/autoplay-check-in-iframe.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/autoplay-check.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/autoplay-no-audio-check.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/autoplay-with-controls.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/bundle-file.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/chinese-character-with-image.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/close-from-within-create-page.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/closed-shadow-tree-test.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/contentBlockerCheck.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/custom-protocol-sync-xhr.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/enumerateMediaDevices.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/execCopy.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/file-with-anchor.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/file-with-mse.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/file-with-video.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/find.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/findRanges.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/geolocationGetCurrentPosition.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/geolocationGetCurrentPositionWithHighAccuracy.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/geolocationWatchPosition.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/geolocationWatchPositionWithHighAccuracy.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/getUserMedia.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/gtk/InputMethodFilter.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/icon.png create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/input-focus-blur.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/js-play-with-controls.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/link-with-download-attribute.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/link-with-title.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/lots-of-iframes.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/lots-of-images.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/lots-of-text-vertical-lr.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/lots-of-text.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/many-iframes.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/modal-alerts-in-new-about-blank-window.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/mouse-button-listener.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/mouse-move-listener.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/no-autoplay-with-controls.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/open-and-close-window.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/push-state.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/set-long-title.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/should-open-external-schemes.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/simple-accelerated-compositing.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/simple-form.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/simple-iframe.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/simple-tall.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/simple.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/simple2.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/simple3.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/spacebar-scrolling.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/test-mse.mp4 create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/test-without-audio-track.mp4 create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/test.mp4 create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2/webfont.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/AllAhem.svg create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ApplicationCache.db create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ApplicationCache.db-shm create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ApplicationCache.db-wal create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/BundleEditingDelegateProtocol.h create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/BundleRangeHandleProtocol.h create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.h create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/ContentFiltering.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/CookieMessage.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DownloadRequestBlobURL.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DownloadRequestOriginalURL.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DownloadRequestOriginalURL2.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DownloadRequestOriginalURLFrame.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/FullscreenDelegate.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/FullscreenLayoutConstraints.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/FullscreenTopContentInset.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBDeleteRecovery.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBDeleteRecovery.sqlite3 create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBDeleteRecovery.sqlite3-shm create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBDeleteRecovery.sqlite3-wal create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IDBIndexUpgradeToV2.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexUpgrade.blob create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexUpgrade.sqlite3 create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBDatabaseProcessKill-1.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBMultiProcess-1.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBMultiProcess-2.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBMultiProcess-3.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence-1.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/IndexedDBPersistence-2.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LineBreaking.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageClear.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageNullEntries.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageNullEntries.localstorage create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageNullEntries.localstorage-shm create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LocalStorageQuirkEnabled.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/RemoteObjectRegistry.h create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/StoreBlobToBeDeleted.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/UserContentWorldProtocol.h create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WebProcessKillIDBCleanup-1.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WebProcessKillIDBCleanup-2.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/autofocused-text-input.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/autoplaying-video-with-audio.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/blinking-div.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-click.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-end.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/duplicate-completion-handler-calls.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/editable-body.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/enormous-video-with-sound.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/focus-inputs.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/full-size-autoplaying-video-with-audio.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/input-field-in-scrollable-document.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-input-field-focus-onload.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-hides-controls-after-seek-to-end.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-mutes-onplaying.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-offscreen.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-playing-scroll-away.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-after-ending.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-to-beginning-and-play-after-ending.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-test-now-playing.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-with-audio.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-with-audio.mp4 create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-without-audio.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-click-to-pause.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-scroll-to-video.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-paused-video-hides-controls.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-muted-video-hides-controls.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-video-keeps-controls.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-with-audio-autoplay.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-with-audio.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/open-multiple-external-url.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/page-with-csp-iframe.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/page-with-csp.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/page-without-csp-iframe.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/page-without-csp.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/play-audio-on-click.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/skinny-autoplaying-video-with-audio.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/text-and-password-inputs.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Cocoa/wide-autoplaying-video-with-audio.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/AutocleanupsTest.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/CMakeLists.txt create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/DOMDOMWindowTest.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/DOMNodeFilterTest.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/DOMXPathNSResolverTest.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/EditorTest.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestAutocleanups.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestConsoleMessage.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDOMDOMWindow.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDOMNodeFilter.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestDOMXPathNSResolver.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestEditor.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitSecurityOrigin.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitUserContentManager.cpp delete mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebKitWebViewGroup.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebsiteData.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/blank.ico create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/boring.html create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/link-title.js create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/silence.mpg create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/simple.json create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/test-cert.pem create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/test-key.pem create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/track.ogg create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2Gtk/resources/webkit2gtk-tests.gresource.xml create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2ObjC/CustomProtocolsInvalidScheme_Bundle.cpp create mode 100644 Tools/TestWebKitAPI/Tests/WebKit2ObjC/PreventImageLoadWithAutoResizing_Bundle.cpp delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/test_utils.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testapplicationcache.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testatk.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testatkroles.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testcontextmenu.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testcopyandpaste.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testdomdocument.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testdomdomwindow.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testdomnode.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testdownload.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testfavicondatabase.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testglobals.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testhittestresult.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testhttpbackend.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testkeyevents.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testloading.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testmimehandling.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testnetworkrequest.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testnetworkresponse.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testwebbackforwardlist.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testwebdatasource.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testwebframe.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testwebhistoryitem.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testwebinspector.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testwebplugindatabase.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testwebresource.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testwebsettings.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testwebview.c delete mode 100644 Tools/TestWebKitAPI/Tests/WebKitGtk/testwindow.c delete mode 100644 Tools/TestWebKitAPI/Tests/gtk/InputMethodFilter.cpp create mode 100644 Tools/TestWebKitAPI/Utilities.h create mode 100644 Tools/TestWebKitAPI/WKWebViewConfigurationExtras.h create mode 100644 Tools/TestWebKitAPI/jsconly/PlatformUtilitiesJSCOnly.cpp create mode 100644 Tools/TestWebKitAPI/jsconly/main.cpp create mode 100644 Tools/WebKitTestRunner/CMakeLists.txt create mode 100644 Tools/WebKitTestRunner/DerivedSources.make create mode 100644 Tools/WebKitTestRunner/FontWithFeatures.otf create mode 100644 Tools/WebKitTestRunner/FontWithFeatures.ttf delete mode 100644 Tools/WebKitTestRunner/GNUmakefile.am create mode 100644 Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityController.idl create mode 100644 Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityTextMarker.idl create mode 100644 Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityTextMarkerRange.idl create mode 100644 Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl create mode 100644 Tools/WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm create mode 100644 Tools/WebKitTestRunner/InjectedBundle/Bindings/EventSendingController.idl create mode 100644 Tools/WebKitTestRunner/InjectedBundle/Bindings/GCController.idl delete mode 100644 Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrappable.h delete mode 100644 Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.cpp delete mode 100644 Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.h create mode 100644 Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl create mode 100644 Tools/WebKitTestRunner/InjectedBundle/Bindings/TextInputController.idl create mode 100644 Tools/WebKitTestRunner/PlatformGTK.cmake create mode 100644 Tools/WebKitTestRunner/TestOptions.cpp create mode 100644 Tools/WebKitTestRunner/TestOptions.h create mode 100644 Tools/WebKitTestRunner/config.h create mode 100644 Tools/WebKitTestRunner/gtk/fonts/AHEM____.TTF create mode 100644 Tools/WebKitTestRunner/gtk/fonts/FontWithNoValidEncoding.fon create mode 100644 Tools/WebKitTestRunner/gtk/fonts/fonts.conf delete mode 100644 Tools/gtk/GNUmakefile.am delete mode 100755 Tools/gtk/check-for-webkitdom-api-breaks delete mode 100755 Tools/gtk/generate-feature-defines-files create mode 100755 Tools/gtk/install-dependencies create mode 100644 Tools/gtk/jhbuild.modules create mode 100644 Tools/gtk/jhbuildrc create mode 100755 Tools/gtk/make-dist.py create mode 100644 Tools/gtk/manifest.txt.in create mode 100644 Tools/gtk/patches/fontconfig-C-11-requires-a-space-between-literal-and-identifier.patch create mode 100644 Tools/gtk/patches/fontconfig-fix-osx-cache.diff create mode 100644 Tools/gtk/patches/freetype6-2.4.11-truetype-font-height-fix.patch create mode 100644 Tools/gtk/patches/gdate-suppress-string-format-literal-warning.patch create mode 100644 Tools/gtk/patches/glib-warning-fix.patch create mode 100644 Tools/gtk/patches/gst-plugins-bad-0001-dtls-port-to-OpenSSL-1.1.0.patch create mode 100644 Tools/gtk/patches/gst-plugins-bad-0002-dtlscertificate-Fix-error-checking-in-RSA_generate_k.patch create mode 100644 Tools/gtk/patches/gst-plugins-good-0001-rtpbin-pipeline-gets-an-EOS-when-any-rtpsources-byes.patch create mode 100644 Tools/gtk/patches/gst-plugins-good-0002-rtpbin-avoid-generating-errors-when-rtcp-messages-ar.patch create mode 100644 Tools/gtk/patches/gst-plugins-good-0003-rtpbin-receive-bundle-support.patch create mode 100644 Tools/gtk/patches/gst-plugins-good-0004-qtdemux-add-context-for-a-preferred-protection.patch create mode 100644 Tools/gtk/patches/gst-plugins-good-Revert-qtdemux-expose-streams-with-first-moof-for-fr.patch create mode 100644 Tools/gtk/patches/gst-plugins-good-use-the-tfdt-decode-time.patch create mode 100644 Tools/gtk/patches/gstreamer-0001-protection-added-function-to-filter-system-ids.patch create mode 100644 Tools/gtk/patches/gtk+-configure-fix-detecting-CUPS-2.x.patch create mode 100644 Tools/gtk/patches/icudata-stdlibs.patch create mode 100644 Tools/gtk/patches/libnice-0001-TURN-allow-REALM-to-be-empty.patch create mode 100644 Tools/gtk/patches/libnice-0001-nicesrc-spin-the-agent-mainloop-in-a-separate-thread.patch create mode 100644 Tools/gtk/patches/librsvg-2.36.1-bump-up-config.guess-to-support-aarch64.patch create mode 100644 Tools/gtk/patches/libsoup-auth-Fix-async-authentication-when-flag-SOUP_MESSAGE.patch create mode 100644 Tools/gtk/patches/libsoup-auth-do-not-use-cached-credentials-in-lookup-method-.patch create mode 100644 Tools/gtk/patches/mesa-gallivm-Fix-build-after-LLVM-commit-211259.patch create mode 100644 Tools/gtk/patches/openh264-configure.patch create mode 100644 Tools/gtk/patches/rtspsrc-timeout-on-udpsrc-is-in-nanoseconds.patch create mode 100644 Tools/gtk/patches/shared-mime-info-xht-glob.patch create mode 100644 Tools/gtk/patches/shared-mime-info-xhtml-magic.patch create mode 100644 Tools/gtk/patches/udpsrc-improve-timeouts.patch create mode 100644 Tools/gtk/patches/xserver-remove-bogus-dependencies.patch create mode 100644 Tools/gtk/patches/xserver-search-for-DRI-drivers-at-LIBGL_DRIVERS_PATH-environ.patch delete mode 100755 Tools/gtk/webkitdom.py create mode 100644 Tools/gtk/ycm_extra_conf.py create mode 100644 Tools/jhbuild/jhbuildutils.py (limited to 'Tools') 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(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(JSObjectGetPrivate(thisObject)); + return JSValueMakeBoolean(context, controller->enhancedAccessibilityEnabled()); +} + static JSValueRef getPlatformNameCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) { AccessibilityController* controller = static_cast(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 platformName() const; #if PLATFORM(WIN) @@ -89,7 +93,7 @@ private: HashMap m_notificationListeners; #endif -#if PLATFORM(MAC) +#if PLATFORM(COCOA) || PLATFORM(IOS) RetainPtr 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 -#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 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 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 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 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 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 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 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 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 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& 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(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 compRole(Adopt, toAXElement(thisObject)->computedRoleString()); + return JSValueMakeString(context, compRole.get()); +} + static JSValueRef getTitleCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) { JSRetainPtr 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 labelString(Adopt, toAXElement(thisObject)->stringForSelection()); - return JSValueMakeString(context, labelString.get()); -} - -static JSValueRef getIPhoneLabelCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) -{ - JSRetainPtr 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 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 valueString(Adopt, toAXElement(thisObject)->iphoneValue()); - return JSValueMakeString(context, valueString.get()); + JSRetainPtr 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 valueString(Adopt, toAXElement(thisObject)->iphoneIdentifier()); + JSRetainPtr 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 valueString(Adopt, toAXElement(thisObject)->iphoneTraits()); + JSRetainPtr 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&) const { } -void AccessibilityUIElement::columnHeaders(Vector&) const { } -void AccessibilityUIElement::rowHeaders(Vector&) 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 #include -#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& 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& 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 <{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, <_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, < $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, < +#include + +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, <_staticFunctionsGetterImplementation($interface), "\n"); + push(@contents, $self->_staticValuesGetterImplementation($interface)); + + if (my @functions = @{$interface->functions}) { + push(@contents, "\n// Functions\n"); + + foreach my $function (@functions) { + push(@contents, <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, <_returnExpression($attribute->type, $getterExpression)]}; +} +EOF + + unless ($attribute->isReadOnly) { + push(@contents, <_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, <@{[$self->_setterName($attribute)]}(${platformValue}); + + return true; +} +EOF + } + } + } + + push(@contents, < $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" 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(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" => 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 = <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 + +@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 -#endif - -#if PLATFORM(MAC) +#if PLATFORM(COCOA) #include "DumpRenderTreeMac.h" #elif PLATFORM(WIN) #include "DumpRenderTreeWin.h" @@ -45,6 +39,7 @@ #endif #include +#include #include #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 + +// 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 #ifdef __OBJC__ #import #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 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 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 \ 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 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 + * (C) 2012 Patrick Ganstere + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +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 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 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 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& vector) { @@ -116,20 +114,20 @@ void printPNG(const unsigned char* data, const size_t dataLength, const char* ch Vector bytesToAdd; convertChecksumToPNGComment(checksum, bytesToAdd); - printf("Content-Type: %s\n", "image/png"); - printf("Content-Length: %lu\n", static_cast(dataLength + bytesToAdd.size())); + fprintf(testResult, "Content-Type: image/png\n"); + fprintf(testResult, "Content-Length: %lu\n", static_cast(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 - -#include +#include class BitmapContext; void computeMD5HashStringForBitmapContext(BitmapContext*, char hashString[33]); -PassRefPtr createPagedBitmapContext(); -PassRefPtr createBitmapContextFromWebView(bool onscreen, bool incrementalRepaint, bool sweepHorizontally, bool drawSelectionRect); +RefPtr createPagedBitmapContext(); +RefPtr 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/ForwardingHeaders/WebKit/npapi.h b/Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npapi.h new file mode 100644 index 000000000..627bc97a9 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npapi.h @@ -0,0 +1 @@ +#include diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npfunctions.h b/Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npfunctions.h new file mode 100644 index 000000000..54a603dbb --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npfunctions.h @@ -0,0 +1 @@ +#include diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npruntime.h b/Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npruntime.h new file mode 100644 index 000000000..e435ae2ab --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/ForwardingHeaders/WebKit/npruntime.h @@ -0,0 +1 @@ +#include 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 +#include #include #include #include #include +#include +#include +#include // 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 toCString(const NPString& string) { - char* result = static_cast(malloc(string.UTF8Length + 1)); - memcpy(result, string.UTF8Characters, string.UTF8Length); - result[string.UTF8Length] = '\0'; + size_t length = string.UTF8Length; + std::unique_ptr 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 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 #include +#include +#include +#include #if defined(XP_UNIX) || defined(ANDROID) #include @@ -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 #include +#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 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 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 + +using namespace std; + +class PluginScriptableObjectOverridesAllProperties : public PluginTest { +public: + PluginScriptableObjectOverridesAllProperties(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + { + } + +private: + class PluginObject : public Object { + 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(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("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 + +using namespace std; + +class SlowNPPNew : public PluginTest { +public: + SlowNPPNew(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + { + } + +private: + class PluginObject : public Object { + 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(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("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 + +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 redirects; + +private: + // This is the test object. + class TestObject : public Object { }; + + // This is the scriptable object. It has a single "testObject" property and an "evaluate" function. + class ScriptableObject : public Object { + 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 notify(notifyString->UTF8Characters, notifyString->UTF8Length); + NPIdentifier notifyMethod = pluginTest()->NPN_GetStringIdentifier(notify.c_str()); + + Redirect& redirect = static_cast(pluginTest())->redirects[reinterpret_cast(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 url(urlString->UTF8Characters, urlString->UTF8Length); + + pluginTest()->NPN_GetURLNotify(url.c_str(), 0, reinterpret_cast(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(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("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(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(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/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npapi.h b/Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npapi.h deleted file mode 100644 index 627bc97a9..000000000 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npapi.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npfunctions.h b/Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npfunctions.h deleted file mode 100644 index 54a603dbb..000000000 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npfunctions.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npruntime.h b/Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npruntime.h deleted file mode 100644 index e435ae2ab..000000000 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/unix/ForwardingHeaders/WebKit/npruntime.h +++ /dev/null @@ -1 +0,0 @@ -#include 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 * * 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 -#include +#include +#include +#include #include +#include #include #include +#include +#include +#include #include #include -#include -#include -#include #include #include #include +#include #include #include +#include #include +#include + +#if PLATFORM(IOS) +#include +#include +#endif #if PLATFORM(MAC) && !PLATFORM(IOS) #include #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::create(const std::string& testPathOrURL, const std::string& expectedPixelHash) +Ref 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(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(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(toJS(toJS(context), arguments[0])); + JSC::VM& vm = toJS(context)->vm(); + JSC::JSLockHolder lock(vm); + + JSC::JSArrayBufferView* jsBufferView = JSC::jsDynamicCast(vm, toJS(toJS(context), arguments[0])); ASSERT(jsBufferView); - RefPtr bufferView = jsBufferView->impl(); + RefPtr bufferView = jsBufferView->unsharedImpl(); const char* buffer = static_cast(bufferView->baseAddress()); std::vector 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(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(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(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(JSObjectGetPrivate(thisObject)); - - if (argumentCount < 1) - return JSValueMakeUndefined(context); - - JSRetainPtr 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(JSObjectGetPrivate(thisObject)); - - if (argumentCount < 1) - return JSValueMakeUndefined(context); - - JSRetainPtr 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(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(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(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 result(Adopt, JSValueToStringCopy(context, arguments[0], exception)); - ASSERT(!*exception); - - double confidence = JSValueToNumber(context, arguments[1], exception); - - JSRetainPtr language(Adopt, JSValueToStringCopy(context, arguments[2], exception)); - ASSERT(!*exception); - - TestRunner* controller = static_cast(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(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(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(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(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(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(JSObjectGetPrivate(thisObject)); - double callId = JSValueToNumber(context, arguments[0], exception); - ASSERT(!*exception); - JSRetainPtr script(Adopt, JSValueToStringCopy(context, arguments[1], exception)); + JSRetainPtr script(Adopt, JSValueToStringCopy(context, arguments[0], exception)); ASSERT(!*exception); - controller->evaluateInWebInspector(static_cast(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(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(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(JSObjectGetPrivate(thisObject)); + return JSValueMakeNumber(context, controller->timeout()); +} + static JSValueRef getGlobalFlagCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) { TestRunner* controller = static_cast(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(JSObjectGetPrivate(thisObject)); + JSRetainPtr 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(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 channel(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + TestRunner* controller = static_cast(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 script = argumentCount > 0 ? JSRetainPtr(Adopt, JSValueToStringCopy(context, arguments[0], 0)) : JSRetainPtr(); + JSValueRef callback = argumentCount > 1 ? arguments[1] : JSValueMakeUndefined(context); + + TestRunner* controller = static_cast(JSObjectGetPrivate(thisObject)); + controller->runUIScript(context, script.get(), callback); + + return JSValueMakeUndefined(context); +} + static void testRunnerObjectFinalize(JSObjectRef object) { TestRunner* controller = static_cast(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 }, @@ -2195,9 +2199,6 @@ JSStaticFunction* TestRunner::staticFunctions() #if PLATFORM(IOS) { "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 }, @@ -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(maxLength + 1); + JSStringGetUTF8CString(channel, buffer.get(), maxLength + 1); + + WebCoreTestSupport::setLogChannelToAccumulate({ buffer.get() }); +} + +typedef WTF::HashMap 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(*this); + + String scriptString(JSStringGetCharactersPtr(script), JSStringGetLength(script)); + m_UIScriptContext->runUIScript(scriptString, callbackID); +} + +void TestRunner::callUIScriptCallback(unsigned callbackID, JSStringRef result) +{ + JSRetainPtr 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::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 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 #include #include #include #include -#include #include -class TestRunner : public RefCounted { +extern FILE* testResult; + +class TestRunner : public WTR::UIScriptContextDelegate, public RefCounted { + WTF_MAKE_NONCOPYABLE(TestRunner); public: - static PassRefPtr create(const std::string& testPathOrURL, const std::string& expectedPixelHash); + static Ref 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& allowedHosts() const { return m_allowedHosts; } + void setAllowedHosts(std::set 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& 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 m_willSendRequestClearHeaders; + std::set m_allowedHosts; std::vector m_audioResult; std::map m_URLsToRedirect; - + + struct UIScriptInvocationData { + unsigned callbackID; + String scriptString; + }; + + std::unique_ptr 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/TextInputController.h b/Tools/DumpRenderTree/TextInputController.h new file mode 100644 index 000000000..3472ee789 --- /dev/null +++ b/Tools/DumpRenderTree/TextInputController.h @@ -0,0 +1,41 @@ +/* + * 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. + * 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. + */ + +#import + +@class WebView; +@class WebHTMLView; +@class WebScriptObject; + +@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 +#include 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 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 + class WorkQueueItem; class WorkQueue { +friend class WTF::NeverDestroyed; + 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 -#include - -#if PLATFORM(GTK) -#include "WebCoreSupport/DumpRenderTreeSupportGtk.h" -#include -#endif - -#if PLATFORM(EFL) -#include "DumpRenderTreeChrome.h" -#include "WebCoreSupport/DumpRenderTreeSupportEfl.h" -#endif - -typedef HashMap 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 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(¶mValues[0])); - if (!accessible || !ATK_IS_OBJECT(accessible)) - return true; - - GSignalQuery signalQuery; - GUniquePtr signalName; - GUniquePtr 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(¶mValues[1]))); - signalValue.reset(g_strdup_printf("%d", g_value_get_boolean(¶mValues[2]))); - if (!g_strcmp0(g_value_get_string(¶mValues[1]), "checked")) - notificationName = "CheckedStateChanged"; - else if (!g_strcmp0(g_value_get_string(¶mValues[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(¶mValues[1]))); - if (g_value_get_boolean(¶mValues[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(¶mValues[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 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, ¬ificationNameArgument, 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 - -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 AccessibilityController::platformName() const -{ - JSRetainPtr 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(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 -#include -#include -#include - -class AccessibilityNotificationHandler : public RefCounted { -public: - static PassRefPtr 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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 buffer(static_cast(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(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(attributes->data); - GUniquePtr 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, ""); - - // 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 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& elements) -{ - StringBuilder builder; - - for (Vector::const_iterator it = elements.begin(); it != elements.end(); ++it) { - builder.append(attributesOfElement(const_cast(it))); - builder.append("\n------------\n"); - } - - return JSStringCreateWithUTF8CString(builder.toString().utf8().data()); -} - -static Vector getRowHeaders(AtkTable* accessible) -{ - Vector 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 getColumnHeaders(AtkTable* accessible) -{ - Vector 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 getVisibleCells(AccessibilityUIElement* element) -{ - Vector 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 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), ¤tValue); - - 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(¤tValue) + 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(¤tValue); -} - -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& elements) -{ - // FIXME: implement -} - -void AccessibilityUIElement::getDocumentLinks(Vector&) -{ - // FIXME: implement -} - -void AccessibilityUIElement::getChildren(Vector& 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& 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 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 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(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 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 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 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 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 text(atk_text_get_text(ATK_TEXT(m_element), 0, -1)); - GUniquePtr textWithReplacedCharacters(replaceCharactersForResults(text.get())); - GUniquePtr 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 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(g_ptr_array_index(targetList, targetCount))) { - GUniquePtr 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 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 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 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 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 columnHeaders = getColumnHeaders(ATK_TABLE(m_element)); - return createStringWithAttributes(columnHeaders); -} - -JSStringRef AccessibilityUIElement::attributesOfRowHeaders() -{ - if (!ATK_IS_TABLE(m_element)) - return JSStringCreateWithCharacters(0, 0); - - Vector 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 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 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 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 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(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 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 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 +#include #include #if PLATFORM(WIN) @@ -48,9 +47,9 @@ typedef void* PlatformBitmapBuffer; class BitmapContext : public RefCounted { public: - static PassRefPtr createByAdoptingBitmapAndContext(PlatformBitmapBuffer buffer, cairo_t* context) + static Ref 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 -#include +#include #include #ifdef __cplusplus @@ -38,39 +33,25 @@ #include #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 -#include -#include -#include - -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 idBuffer(static_cast(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 - * Copyright (C) 2008 Alp Toker - * Copyright (C) 2009 Jan Alonzo - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if PLATFORM(X11) -#include -#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 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(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 outputDir(g_build_filename(topLevelPath.data(), "WebKitBuild", NULL)); - return outputDir.get(); -} - -static CString getFontsPath() -{ - CString webkitOutputDir = getOutputDir(); - GUniquePtr fontsPath(g_build_filename(webkitOutputDir.data(), "Dependencies", "Root", "webkitgtk-test-fonts", NULL)); - if (g_file_test(fontsPath.get(), static_cast(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(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 fontConfigFilename(g_build_filename(FONTS_CONF_DIR, "fonts.conf", nullptr)); - if (!FcConfigParseAndLoad(config, reinterpret_cast(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 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 fontPath(g_build_filename(fontsPath.data(), directoryEntry, nullptr)); - if (!FcConfigAppFontAddFile(config, reinterpret_cast(fontPath.get()))) - g_error("Could not load font at %s!", fontPath.get()); - - } - - // Ahem is used by many layout tests. - GUniquePtr ahemFontFilename(g_build_filename(FONTS_CONF_DIR, "AHEM____.TTF", nullptr)); - if (!FcConfigAppFontAddFile(config, reinterpret_cast(ahemFontFilename.get()))) - g_error("Could not load font at %s!", ahemFontFilename.get()); - - for (int i = 1; i <= 9; i++) { - GUniquePtr fontFilename(g_strdup_printf("WebKitWeightWatcher%i00.ttf", i)); - GUniquePtr fontPath(g_build_filename(FONTS_CONF_DIR, "..", "..", "fonts", fontFilename.get(), nullptr)); - if (!FcConfigAppFontAddFile(config, reinterpret_cast(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 fontWithNoValidEncodingFilename(g_build_filename(FONTS_CONF_DIR, "FontWithNoValidEncoding.fon", nullptr)); - if (!FcConfigAppFontAddFile(config, reinterpret_cast(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 childData(dumpFramesAsText(static_cast(child->data))); - appendString(result, childData.get()); - } - g_slist_free(children); - } - - return result; -} - -static gint compareHistoryItems(gpointer* item1, gpointer* item2) -{ - GUniquePtr firstItemTarget(webkit_web_history_item_get_target(WEBKIT_WEB_HISTORY_ITEM(item1))); - GUniquePtr 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 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 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 password(soupURI->password); - GUniquePtr user(soupURI->user); - soupURI->password = 0; - soupURI->user = 0; - - GUniquePtr 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 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(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 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 \"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 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 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 pathBasename(g_path_get_basename(pathString.utf8().data())); - - WebKitWebFrame* mainFrame = webkit_web_view_get_main_frame(webView); - GUniquePtr 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 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 basename(g_path_get_basename(uriString)); - return CString(basename.get()); -} - -static CString descriptionSuitableForTestResult(SoupURI* uri) -{ - if (!uri) - return CString("(null)"); - - GUniquePtr 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 errorString(g_strdup_printf("", - 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 description(g_strdup_printf("", - 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 description(g_strdup_printf("", 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 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& clearHeaders = gTestRunner->willSendRequestClearHeaders(); - for (set::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 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 - * - * 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 -#include -#include -#include -#include - -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 -#include -#include -#include - -static CString dumpNodePath(WebKitDOMNode* node) -{ - GUniquePtr 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 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 pathBuffer(g_string_free(path, FALSE)); - return pathBuffer.get(); -} - -static CString dumpRange(WebKitDOMRange* range) -{ - if (!range) - return "(null)"; - - GUniquePtr 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 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/EditingCallbacks.h b/Tools/DumpRenderTree/gtk/EditingCallbacks.h deleted file mode 100644 index 7a9514917..000000000 --- a/Tools/DumpRenderTree/gtk/EditingCallbacks.h +++ /dev/null @@ -1,35 +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. - */ - -#ifndef EditingCallbacks_h -#define EditingCallbacks_h - -typedef struct _WebKitWebView WebKitWebView; -void connectEditingCallbacks(WebKitWebView*); - -#endif 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 - * Copyright (C) 2009 Holger Hans Peter Freyther - * Copyright (C) 2010 Igalia S.L. - * Copyright (C) 2012 ChangSeok Oh - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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 = ""; - else - label = gtk_menu_item_get_label(GTK_MENU_ITEM(widget)); - - JSRetainPtr 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 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 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(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(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(userData)); -} - -static void dragWithFilesDragEndCallback(GtkWidget* widget, GdkDragContext*, gpointer userData) -{ - g_signal_handlers_disconnect_by_func(widget, reinterpret_cast(dragWithFilesDragEndCallback), userData); - g_signal_handlers_disconnect_by_func(widget, reinterpret_cast(dragWithFilesDragDataGetCallback), userData); - g_strfreev(static_cast(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 testFile(adoptGRef(g_file_new_for_uri(mainFrameURI))); - GRefPtr 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 scheme(g_file_get_uri_scheme(parentDirectory.get())); - if (g_str_equal(scheme.get(), "http") || g_str_equal(scheme.get(), "https")) { - GUniquePtr 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 filenameBuffer(static_cast(g_malloc(bufferSize))); - JSStringGetUTF8CString(filenameString, filenameBuffer.get(), bufferSize); - JSStringRelease(filenameString); - - GRefPtr 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 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(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(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 - * - * 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 -#include - -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 - * 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 - -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(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 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 - -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 - -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 - * Copyright (C) 2008 Nuanti Ltd. - * Copyright (C) 2009 Jan Michael Alonzo - * Copyright (C) 2009,2011 Collabora Ltd. - * Copyright (C) 2010 Joone Hur - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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 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 testPath(g_build_filename(getTopLevelPath().data(), layoutTestsSuffix, nullptr)); - GUniquePtr testURI(g_filename_to_uri(testPath.get(), 0, 0)); - return JSStringCreateWithUTF8CString(testURI.get()); -} - -void TestRunner::queueLoad(JSStringRef url, JSStringRef target) -{ - GUniquePtr 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 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(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 sourceOriginGChar(JSStringCopyUTF8CString(sourceOrigin)); - GUniquePtr protocolGChar(JSStringCopyUTF8CString(protocol)); - GUniquePtr 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 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 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 lengthPropertyName(Adopt, JSStringCreateWithUTF8CString("length")); - JSValueRef lengthValue = JSObjectGetProperty(context, optionsArray, lengthPropertyName.get(), 0); - if (!JSValueIsNumber(context, lengthValue)) - return false; - - GUniquePtr targetString(JSStringCopyUTF8CString(target)); - - size_t length = static_cast(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 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 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 originalName(JSStringCopyUTF8CString(key)); - GUniquePtr 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(¤tPropertyValue, pspec->value_type); - - if (G_VALUE_HOLDS_STRING(¤tPropertyValue)) - g_object_set(settings, propertyName, valueAsString.get(), NULL); - else if (G_VALUE_HOLDS_BOOLEAN(¤tPropertyValue)) - g_object_set(G_OBJECT(settings), propertyName, booleanFromValue(valueAsString.get()), NULL); - else if (G_VALUE_HOLDS_INT(¤tPropertyValue)) - g_object_set(G_OBJECT(settings), propertyName, atoi(valueAsString.get()), NULL); - else if (G_VALUE_HOLDS_FLOAT(¤tPropertyValue)) { - 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 sourceCode(JSStringCopyUTF8CString(source)); - DumpRenderTreeSupportGtk::addUserScript(mainFrame, sourceCode.get(), runAtStart, allFrames); -} - -void TestRunner::addUserStyleSheet(JSStringRef source, bool allFrames) -{ - GUniquePtr 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 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 -#include -#include -#include -#include -#include - -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 stringBuffer(static_cast(g_malloc(bufferSize))); - JSStringGetUTF8CString(string, stringBuffer.get(), bufferSize); - JSStringRelease(string); - - int start = static_cast(JSValueToNumber(context, arguments[1], exception)); - ASSERT(!exception || !*exception); - - int length = static_cast(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 stringBuffer(static_cast(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(JSValueToNumber(context, arguments[0], exception)); - ASSERT(!exception || !*exception); - - int length = static_cast(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 stringBuffer(static_cast(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/TextInputController.h b/Tools/DumpRenderTree/gtk/TextInputController.h deleted file mode 100644 index 53793f637..000000000 --- a/Tools/DumpRenderTree/gtk/TextInputController.h +++ /dev/null @@ -1,37 +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 TextInputController_h -#define TextInputController_h - -typedef const struct OpaqueJSContext* JSContextRef; -typedef struct OpaqueJSValue* JSObjectRef; - -JSObjectRef makeTextInputController(JSContextRef); - -#endif 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 - * - * 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 -#include -#include -#include - -// 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 content(JSStringCopyUTF8CString(m_content.get())); - GUniquePtr baseURL(JSStringCopyUTF8CString(m_baseURL.get())); - - if (m_unreachableURL) { - GUniquePtr 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/LauncherInspectorWindow.h b/Tools/GtkLauncher/LauncherInspectorWindow.h deleted file mode 100644 index f7091d238..000000000 --- a/Tools/GtkLauncher/LauncherInspectorWindow.h +++ /dev/null @@ -1,51 +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. - */ - -#ifndef LauncherInspectorWindow_h -#define LauncherInspectorWindow_h - -#include -#include - -G_BEGIN_DECLS - -#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)) - -typedef struct _LauncherInspectorWindow LauncherInspectorWindow; -typedef struct _LauncherInspectorWindowClass LauncherInspectorWindowClass; - -GType launcher_inspector_window_get_type(void); - -GtkWidget *launcherInspectorWindowNew(WebKitWebInspector *, GtkWindow *parent); -WebKitWebView *launcherInspectorWindowGetWebView(LauncherInspectorWindow *); - -G_END_DECLS - -#endif 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 - * 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 -#include -#ifdef WTF_USE_GSTREAMER -#include -#endif -#include -#include -#include -#include - -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 #include #include +#include #include #include @@ -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/MiniBrowser/MBToolbarItem.h b/Tools/MiniBrowser/MBToolbarItem.h new file mode 100644 index 000000000..9971d4c10 --- /dev/null +++ b/Tools/MiniBrowser/MBToolbarItem.h @@ -0,0 +1,27 @@ +/* + * 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. + */ + +@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 + +#if WK_API_ENABLED + +@interface MiniBrowserWebProcessPlugIn : NSObject + +@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 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 + +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("%s", 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, "", "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 +#include + +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 #include -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 #include #include #include @@ -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, "

%s (%s)

\n\n", title, totalDataSizeStr); + g_free(totalDataSizeStr); + } else + g_string_append_printf(result, "

%s

\n
\n", title); + if (dataPath) + g_string_append_printf(result, "\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, "", displayName, dataSizeStr); + g_free(dataSizeStr); + } else + g_string_append_printf(result, "", displayName); + g_string_append_printf(result, "\n", + pageID, types, index); + } + g_string_append_printf(result, "
Path: %s
%s (%s)
%s
\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( + "" + "\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, ""); + 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 = ); + 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 () { + if (/^Repository Root: (.+)/) { + $thisRoot = $1; + } + if (/^Repository UUID: (.+)/) { + $thisUUID = $1; + } + if ($thisRoot && $thisUUID) { + local $/ = undef; + ; # 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 () { + # 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; + ; + } + else { + # Files will have only one status returned. + $svnStatus = removeEOL() . "\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 + # and 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 + 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 = ; + close(DIFF); + rename($fileMine, "$fileMine.save"); + rename($fileOlder, "$fileOlder.save"); + } else { + open(DIFF, "diff -u -a --binary \"$fileOlder\" \"$fileMine\" |") or die $!; + $patch = ; + 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 () { + $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[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 = < \$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 + ¤tSVNRevision + &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 . +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 + # (). + 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 = ; + 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 = ; + 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 = ; + 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 .\n\n"; + print "Then follow step 2 in the Windows section of the \"Installing Developer\n"; + print "Tools\" instructions at .\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 = ); + 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 = ); + return $input ? $input : $default; +} + +sub appleApplicationSupportPath +{ + open 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 <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: 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: 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::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 +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 +#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 +#include #include #include @@ -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 +#include #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 #include -#include -#include +#include +#include #include 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 injectedBundlePath(AdoptWK, createInjectedBundlePath()); @@ -76,14 +78,16 @@ std::string toSTD(WKRetainPtr string) return toSTD(string.get()); } -std::string toSTD(const char* string) +WKRetainPtr toWK(const char* utf8String) { - return std::string(string); + return WKRetainPtr(AdoptWK, WKStringCreateWithUTF8CString(utf8String)); } -WKRetainPtr toWK(const char* utf8String) +#endif // WK_HAVE_C_SPI + +std::string toSTD(const char* string) { - return WKRetainPtr(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 +#ifndef BUILDING_JSCONLY__ +#include +#include +#endif + +#include "Utilities.h" #include -#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); -std::string toSTD(const char*); -#if PLATFORM(MAC) -std::string toSTD(NSString *); -#endif WKRetainPtr toWK(const char* utf8String); +#endif // WK_HAVE_C_SPI + template 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 #endif -#ifdef __APPLE__ +#if PLATFORM(MAC) +#include +#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 + namespace TestWebKitAPI { #define EXPECT_NOT_NULL(expression) \ @@ -40,6 +42,18 @@ namespace TestWebKitAPI { #define ASSERT_NULL(expression) \ ASSERT_TRUE(!(expression)) +template +static inline ::testing::AssertionResult assertStrongEnum(const char* expected_expression, const char* actual_expression, T expected, T actual) +{ + static_assert(std::is_enum::value, "T is not an enum type"); + typedef typename std::underlying_type::type UnderlyingStorageType; + return ::testing::internal::CmpHelperEQ(expected_expression, actual_expression, static_cast(expected), static_cast(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 -#include -#include - -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 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 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 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(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 +#include +#include + +namespace TestWebKitAPI { + +static Vector generateRandomHashes(size_t hashCount) +{ + Vector hashes; + for (unsigned i = 0; i < hashCount; ++i) + hashes.append(static_cast(randomNumber() * std::numeric_limits::max())); + return hashes; +} + +static Vector generateRandomDigests(size_t hashCount) +{ + Vector hashes; + SHA1 sha1; + for (unsigned i = 0; i < hashCount; ++i) { + double random = randomNumber(); + sha1.addBytes(reinterpret_cast(&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 +static void resetOverflow(Checked& value) +{ + value.reset(); + value = 100; + value *= std::numeric_limits::max(); +} + +#define CheckedArithmeticTest(type, Coercer, MixedSignednessTester) \ TEST(WTF, Checked_##type) \ { \ - Checked value; \ - EXPECT_EQ(coerceLiteral(0), value.unsafeGet()); \ - EXPECT_EQ(std::numeric_limits::max(), (value + std::numeric_limits::max()).unsafeGet()); \ - EXPECT_EQ(std::numeric_limits::max(), (std::numeric_limits::max() + value).unsafeGet()); \ - EXPECT_EQ(std::numeric_limits::min(), (value + std::numeric_limits::min()).unsafeGet()); \ - EXPECT_EQ(std::numeric_limits::min(), (std::numeric_limits::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::min(); \ - EXPECT_EQ(true, (Checked(value - coerceLiteral(1))).hasOverflowed()); \ - EXPECT_EQ(true, !((value--).hasOverflowed())); \ - EXPECT_EQ(true, value.hasOverflowed()); \ - value = std::numeric_limits::max(); \ - EXPECT_EQ(true, !value.hasOverflowed()); \ - EXPECT_EQ(true, (Checked(value + coerceLiteral(1))).hasOverflowed()); \ - EXPECT_EQ(true, !(value++).hasOverflowed()); \ - EXPECT_EQ(true, value.hasOverflowed()); \ - value = std::numeric_limits::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(0)).safeGet(_value)); \ - _value = 0; \ - EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked(0) * value).safeGet(_value)); \ - _value = 0; \ - EXPECT_EQ(true, CheckedState::DidOverflow == (value * Checked(std::numeric_limits::max())).safeGet(_value)); \ - _value = 0; \ - EXPECT_EQ(true, CheckedState::DidOverflow == (Checked(std::numeric_limits::max()) * value).safeGet(_value)); \ - value = 0; \ - _value = 0; \ - EXPECT_EQ(true, CheckedState::DidNotOverflow == (value * Checked(std::numeric_limits::max())).safeGet(_value)); \ - _value = 0; \ - EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked(std::numeric_limits::max()) * value).safeGet(_value)); \ - value = 1; \ - _value = 0; \ - EXPECT_EQ(true, CheckedState::DidNotOverflow == (value * Checked(std::numeric_limits::max())).safeGet(_value)); \ - _value = 0; \ - EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked(std::numeric_limits::max()) * value).safeGet(_value)); \ - _value = 0; \ - value = 0; \ - EXPECT_EQ(true, CheckedState::DidNotOverflow == (value * Checked(std::numeric_limits::max())).safeGet(_value)); \ - _value = 0; \ - EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked(std::numeric_limits::max()) * (type)0).safeGet(_value)); \ - _value = 0; \ - value = 1; \ - EXPECT_EQ(true, CheckedState::DidNotOverflow == (value * Checked(std::numeric_limits::max())).safeGet(_value)); \ - _value = 0; \ - EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked(std::numeric_limits::max()) * (type)1).safeGet(_value)); \ - _value = 0; \ - value = 2; \ - EXPECT_EQ(true, CheckedState::DidOverflow == (value * Checked(std::numeric_limits::max())).safeGet(_value)); \ - _value = 0; \ - EXPECT_EQ(true, CheckedState::DidOverflow == (Checked(std::numeric_limits::max()) * (type)2).safeGet(_value)); \ - value = 10; \ - EXPECT_EQ(true, (value * Checked(std::numeric_limits::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::min(); \ - MixedSignednessTest(EXPECT_EQ(true, (Checked(value - 1)).hasOverflowed())); \ - MixedSignednessTest(EXPECT_EQ(true, !(value--).hasOverflowed())); \ - MixedSignednessTest(EXPECT_EQ(true, value.hasOverflowed())); \ - value = std::numeric_limits::max(); \ - MixedSignednessTest(EXPECT_EQ(true, !value.hasOverflowed())); \ - MixedSignednessTest(EXPECT_EQ(true, (Checked(value + 1)).hasOverflowed())); \ - MixedSignednessTest(EXPECT_EQ(true, !(value++).hasOverflowed())); \ - MixedSignednessTest(EXPECT_EQ(true, value.hasOverflowed())); \ - value = std::numeric_limits::max(); \ - MixedSignednessTest(EXPECT_EQ(true, (value += 1).hasOverflowed())); \ - MixedSignednessTest(EXPECT_EQ(true, value.hasOverflowed())); \ - value = std::numeric_limits::min(); \ - MixedSignednessTest(EXPECT_EQ(true, (value - 1U).hasOverflowed())); \ - MixedSignednessTest(EXPECT_EQ(true, !(value--).hasOverflowed())); \ - MixedSignednessTest(EXPECT_EQ(true, value.hasOverflowed())); \ - value = std::numeric_limits::max(); \ - MixedSignednessTest(EXPECT_EQ(true, !value.hasOverflowed())); \ - MixedSignednessTest(EXPECT_EQ(true, (Checked(value + 1U)).hasOverflowed())); \ - MixedSignednessTest(EXPECT_EQ(true, !(value++).hasOverflowed())); \ - MixedSignednessTest(EXPECT_EQ(true, value.hasOverflowed())); \ - value = std::numeric_limits::max(); \ - MixedSignednessTest(EXPECT_EQ(true, (value += 1U).hasOverflowed())); \ - MixedSignednessTest(EXPECT_EQ(true, value.hasOverflowed())); \ + typedef Coercer CoercerType; \ + typedef MixedSignednessTester MixedSignednessTesterType; \ + CheckedArithmeticTester::run(); \ } + +#define coerceLiteral(x) Coercer::coerce(x) + +template +class CheckedArithmeticTester { +public: + static void run() + { + Checked value; + EXPECT_EQ(coerceLiteral(0), value.unsafeGet()); + EXPECT_EQ(std::numeric_limits::max(), (value + std::numeric_limits::max()).unsafeGet()); + EXPECT_EQ(std::numeric_limits::max(), (std::numeric_limits::max() + value).unsafeGet()); + EXPECT_EQ(std::numeric_limits::min(), (value + std::numeric_limits::min()).unsafeGet()); + EXPECT_EQ(std::numeric_limits::min(), (std::numeric_limits::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::min(); + EXPECT_EQ(true, (Checked(value - coerceLiteral(1))).hasOverflowed()); + EXPECT_EQ(true, !((value--).hasOverflowed())); + EXPECT_EQ(true, value.hasOverflowed()); + value = std::numeric_limits::max(); + EXPECT_EQ(true, !value.hasOverflowed()); + EXPECT_EQ(true, (Checked(value + coerceLiteral(1))).hasOverflowed()); + EXPECT_EQ(true, !(value++).hasOverflowed()); + EXPECT_EQ(true, value.hasOverflowed()); + value = std::numeric_limits::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(0)).safeGet(_value)); + _value = 0; + EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked(0) * value).safeGet(_value)); + _value = 0; + EXPECT_EQ(true, CheckedState::DidOverflow == (value * Checked(std::numeric_limits::max())).safeGet(_value)); + _value = 0; + EXPECT_EQ(true, CheckedState::DidOverflow == (Checked(std::numeric_limits::max()) * value).safeGet(_value)); + value = 0; + _value = 0; + EXPECT_EQ(true, CheckedState::DidNotOverflow == (value * Checked(std::numeric_limits::max())).safeGet(_value)); + _value = 0; + EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked(std::numeric_limits::max()) * value).safeGet(_value)); + value = 1; + _value = 0; + EXPECT_EQ(true, CheckedState::DidNotOverflow == (value * Checked(std::numeric_limits::max())).safeGet(_value)); + _value = 0; + EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked(std::numeric_limits::max()) * value).safeGet(_value)); + _value = 0; + value = 0; + EXPECT_EQ(true, CheckedState::DidNotOverflow == (value * Checked(std::numeric_limits::max())).safeGet(_value)); + _value = 0; + EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked(std::numeric_limits::max()) * (type)0).safeGet(_value)); + _value = 0; + value = 1; + EXPECT_EQ(true, CheckedState::DidNotOverflow == (value * Checked(std::numeric_limits::max())).safeGet(_value)); + _value = 0; + EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked(std::numeric_limits::max()) * (type)1).safeGet(_value)); + _value = 0; + value = 2; + EXPECT_EQ(true, CheckedState::DidOverflow == (value * Checked(std::numeric_limits::max())).safeGet(_value)); + _value = 0; + EXPECT_EQ(true, CheckedState::DidOverflow == (Checked(std::numeric_limits::max()) * (type)2).safeGet(_value)); + value = 10; + EXPECT_EQ(true, (value * Checked(std::numeric_limits::max())).hasOverflowed()); + + + Checked nvalue; // to hold a not overflowed value. + Checked 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(_value))); + EXPECT_EQ(false, (nvalue == value)); + EXPECT_EQ(true, (nvalue == _value)); + EXPECT_EQ(false, (nvalue == Checked(std::numeric_limits::max()))); + EXPECT_EQ(false, (nvalue == std::numeric_limits::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(_value))); + EXPECT_EQ(true, (nvalue != value)); + EXPECT_EQ(false, (nvalue != _value)); + EXPECT_EQ(true, (nvalue != Checked(std::numeric_limits::max()))); + EXPECT_EQ(true, (nvalue != std::numeric_limits::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(_largeValue))); + EXPECT_EQ(false, (nvalue < Checked(_value))); + EXPECT_EQ(false, (nvalue < Checked(_smallValue))); + EXPECT_EQ(true, (nvalue < _largeValue)); + EXPECT_EQ(false, (nvalue < _value)); + EXPECT_EQ(false, (nvalue < _smallValue)); + EXPECT_EQ(true, (nvalue < Checked(std::numeric_limits::max()))); + EXPECT_EQ(true, (nvalue < std::numeric_limits::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(_largeValue))); + EXPECT_EQ(true, (nvalue <= Checked(_value))); + EXPECT_EQ(false, (nvalue <= Checked(_smallValue))); + EXPECT_EQ(true, (nvalue <= _largeValue)); + EXPECT_EQ(true, (nvalue <= _value)); + EXPECT_EQ(false, (nvalue <= _smallValue)); + EXPECT_EQ(true, (nvalue <= Checked(std::numeric_limits::max()))); + EXPECT_EQ(true, (nvalue <= std::numeric_limits::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(_largeValue))); + EXPECT_EQ(false, (nvalue > Checked(_value))); + EXPECT_EQ(true, (nvalue > Checked(_smallValue))); + EXPECT_EQ(false, (nvalue > _largeValue)); + EXPECT_EQ(false, (nvalue > _value)); + EXPECT_EQ(true, (nvalue > _smallValue)); + EXPECT_EQ(false, (nvalue > Checked(std::numeric_limits::max()))); + EXPECT_EQ(false, (nvalue > std::numeric_limits::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(_largeValue))); + EXPECT_EQ(true, (nvalue >= Checked(_value))); + EXPECT_EQ(true, (nvalue >= Checked(_smallValue))); + EXPECT_EQ(false, (nvalue >= _largeValue)); + EXPECT_EQ(true, (nvalue >= _value)); + EXPECT_EQ(true, (nvalue >= _smallValue)); + EXPECT_EQ(false, (nvalue >= Checked(std::numeric_limits::max()))); + EXPECT_EQ(false, (nvalue >= std::numeric_limits::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(_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::max()), ovalue.didCrash())); + EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue == Checked(std::numeric_limits::max())), ovalue.didCrash())); + EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue == std::numeric_limits::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(_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::max()), ovalue.didCrash())); + EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue != Checked(std::numeric_limits::max())), ovalue.didCrash())); + EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue != std::numeric_limits::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(_largeValue)), ovalue.didCrash())); + EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < Checked(_value)), ovalue.didCrash())); + EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < Checked(_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(std::numeric_limits::max())), ovalue.didCrash())); + EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < std::numeric_limits::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(_largeValue)), ovalue.didCrash())); + EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= Checked(_value)), ovalue.didCrash())); + EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= Checked(_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(std::numeric_limits::max())), ovalue.didCrash())); + EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= std::numeric_limits::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(_largeValue)), ovalue.didCrash())); + EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > Checked(_value)), ovalue.didCrash())); + EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > Checked(_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(std::numeric_limits::max())), ovalue.didCrash())); + EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > std::numeric_limits::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(_largeValue)), ovalue.didCrash())); + EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= Checked(_value)), ovalue.didCrash())); + EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= Checked(_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(std::numeric_limits::max())), ovalue.didCrash())); + EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= std::numeric_limits::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 +class AllowMixedSignednessTest { +public: + static void run() + { + Checked 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::min(); + EXPECT_EQ(true, (Checked(value - 1)).hasOverflowed()); + EXPECT_EQ(true, !(value--).hasOverflowed()); + EXPECT_EQ(true, value.hasOverflowed()); + value = std::numeric_limits::max(); + EXPECT_EQ(true, !value.hasOverflowed()); + EXPECT_EQ(true, (Checked(value + 1)).hasOverflowed()); + EXPECT_EQ(true, !(value++).hasOverflowed()); + EXPECT_EQ(true, value.hasOverflowed()); + value = std::numeric_limits::max(); + EXPECT_EQ(true, (value += 1).hasOverflowed()); + EXPECT_EQ(true, value.hasOverflowed()); + value = std::numeric_limits::min(); + EXPECT_EQ(true, (value - 1U).hasOverflowed()); + EXPECT_EQ(true, !(value--).hasOverflowed()); + EXPECT_EQ(true, value.hasOverflowed()); + value = std::numeric_limits::max(); + EXPECT_EQ(true, !value.hasOverflowed()); + EXPECT_EQ(true, (Checked(value + 1U)).hasOverflowed()); + EXPECT_EQ(true, !(value++).hasOverflowed()); + EXPECT_EQ(true, value.hasOverflowed()); + value = std::numeric_limits::max(); + EXPECT_EQ(true, (value += 1U).hasOverflowed()); + EXPECT_EQ(true, value.hasOverflowed()); + } +}; + +template +class IgnoreMixedSignednessTest { +public: + static void run() { } +}; + +template class CoerceLiteralToUnsigned { +public: + static unsigned coerce(type x) { return static_cast(x); } +}; + +template 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(std::numeric_limits::max())); + EXPECT_TRUE(WTF::isInBounds(std::numeric_limits::min())); + + // bigger precision, unsigned, signed + EXPECT_TRUE(WTF::isInBounds(std::numeric_limits::max())); + EXPECT_FALSE(WTF::isInBounds(std::numeric_limits::min())); + + EXPECT_FALSE(WTF::isInBounds((int32_t)-1)); + EXPECT_FALSE(WTF::isInBounds((int32_t)-1)); + EXPECT_FALSE(WTF::isInBounds((int)-1)); + + EXPECT_TRUE(WTF::isInBounds((int32_t)1)); + EXPECT_TRUE(WTF::isInBounds((int16_t)1)); + EXPECT_TRUE(WTF::isInBounds((int)1)); + + EXPECT_TRUE(WTF::isInBounds((int32_t)0)); + EXPECT_TRUE(WTF::isInBounds((int32_t)0)); + EXPECT_TRUE(WTF::isInBounds((int16_t)0)); + EXPECT_TRUE(WTF::isInBounds((int)0)); + + EXPECT_TRUE(WTF::isInBounds(std::numeric_limits::max())); + EXPECT_TRUE(WTF::isInBounds(std::numeric_limits::max())); + EXPECT_TRUE(WTF::isInBounds(std::numeric_limits::max())); + + // bigger precision, signed, unsigned + EXPECT_TRUE(WTF::isInBounds(std::numeric_limits::max())); + EXPECT_FALSE(WTF::isInBounds(std::numeric_limits::max())); + EXPECT_TRUE(WTF::isInBounds((uint32_t)0)); + + // bigger precision, unsigned, unsigned + EXPECT_TRUE(WTF::isInBounds(std::numeric_limits::max())); + EXPECT_TRUE(WTF::isInBounds(std::numeric_limits::min())); + + // lower precision, signed signed + EXPECT_FALSE(WTF::isInBounds(std::numeric_limits::max())); + EXPECT_FALSE(WTF::isInBounds(std::numeric_limits::min())); + EXPECT_TRUE(WTF::isInBounds((int32_t)-1)); + EXPECT_TRUE(WTF::isInBounds((int32_t)0)); + EXPECT_TRUE(WTF::isInBounds((int32_t)1)); + // lower precision, unsigned, signed + EXPECT_FALSE(WTF::isInBounds(std::numeric_limits::max())); + EXPECT_FALSE(WTF::isInBounds(std::numeric_limits::min())); + EXPECT_FALSE(WTF::isInBounds((int32_t)-1)); + EXPECT_TRUE(WTF::isInBounds((int32_t)0)); + EXPECT_TRUE(WTF::isInBounds((int32_t)1)); + // lower precision, signed, unsigned + EXPECT_FALSE(WTF::isInBounds(std::numeric_limits::max())); + EXPECT_TRUE(WTF::isInBounds((uint32_t)0)); + EXPECT_TRUE(WTF::isInBounds((uint32_t)1)); + // lower precision, unsigned, unsigned + EXPECT_FALSE(WTF::isInBounds(std::numeric_limits::max())); + EXPECT_TRUE(WTF::isInBounds((uint32_t)0)); + EXPECT_TRUE(WTF::isInBounds((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 +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace WTF; + +namespace TestWebKitAPI { + +namespace { + +const bool verbose = false; + +enum NotifyStyle { + AlwaysNotifyOne, + TacticallyNotifyAll +}; + +template +void wait(Condition& condition, std::unique_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 queue; + bool shouldContinue = true; + Lock lock; + Condition emptyCondition; + Condition fullCondition; + + Vector consumerThreads; + Vector producerThreads; + + Vector received; + Lock receivedLock; + + for (unsigned i = numConsumers; i--;) { + ThreadIdentifier threadIdentifier = createThread( + "Consumer thread", + [&] () { + for (;;) { + unsigned result; + unsigned shouldNotify = false; + { + std::unique_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 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 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 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 +#include + +template +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 +#include +#include +#include + +namespace TestWebKitAPI { + +static size_t totalDestructorCalls; +static size_t totalIsolatedCopyCalls; + +static HashCountedSet defaultConstructorSet; +static HashCountedSet nameConstructorSet; +static HashCountedSet copyConstructorSet; +static HashCountedSet 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 { *"" }; + 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("-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("-1-0")); + ASSERT_EQ(1u, copyConstructorSet.count("-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("-2-1")); + ASSERT_EQ(1u, moveConstructorSet.count("-2-2")); + ASSERT_EQ(1u, moveConstructorSet.count("-1-1")); + ASSERT_EQ(1u, moveConstructorSet.count("-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 + +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 +#include + +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 : public GenericHashTraits { + static const bool emptyValueIsZero = true; + + static void constructDeletedValue(DeletedAddressOfOperator& slot) { slot = DeletedAddressOfOperator(std::numeric_limits::max()); } + static bool isDeletedValue(const DeletedAddressOfOperator& slot) { return slot.value() == std::numeric_limits::max(); } +}; + +template<> struct DefaultHash { + 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 + +namespace TestWebKitAPI { + +TEST(WTF_Deque, Iterator) +{ + Deque deque; + deque.append(11); + deque.prepend(10); + deque.append(12); + deque.append(13); + + Deque::iterator it = deque.begin(); + Deque::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 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 deque; + deque.append(11); + deque.prepend(10); + deque.append(12); + deque.append(13); + + Deque::reverse_iterator it = deque.rbegin(); + Deque::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 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 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 deque; + + for (unsigned i = 0; i < 10; ++i) + deque.append(MoveOnly(i)); + + EXPECT_EQ(10u, deque.size()); + + Deque 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 deque1; + + for (unsigned i = 0; i < 10; ++i) + deque1.append(MoveOnly(i)); + + EXPECT_EQ(10u, deque1.size()); + + Deque 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 + +enum class TestEnum { + A, + B, + C, +}; + +namespace WTF { +template<> struct EnumTraits { + using values = EnumValues; +}; +} + +namespace TestWebKitAPI { + +static_assert(WTF::isValidEnum(0), ""); +static_assert(!WTF::isValidEnum(-1), ""); +static_assert(!WTF::isValidEnum(3), ""); + +TEST(WTF_EnumTraits, IsValidEnum) +{ + EXPECT_TRUE(isValidEnum(0)); + EXPECT_FALSE(isValidEnum(-1)); + EXPECT_FALSE(isValidEnum(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 +#include + +#include +#include + +namespace WTF { + +template std::ostream& operator<<(std::ostream& os, const UnexpectedType& u) +{ + return os << u.value(); +} + +template std::ostream& operator<<(std::ostream& os, const Expected& e) +{ + if (e.hasValue()) + return os << e.value(); + return os << e.error(); +} + +template std::ostream& operator<<(std::ostream& os, const Expected& 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(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 E; + typedef Expected EV; + typedef Expected FooChar; + typedef Expected 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(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(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(message)); + FooString e1(makeUnexpected(message)); + FooString e2(makeUnexpected(std::string())); + EXPECT_EQ(e0.error(), std::string(message)); + EXPECT_EQ(e0, e1); + EXPECT_NE(e0, e2); + FooString* e4 = new FooString(makeUnexpected(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 E; + typedef Expected EV; + typedef Expected 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(oops); + EXPECT_FALSE(e.hasValue()); + EXPECT_EQ(e.error(), oops); + EXPECT_EQ(e.getUnexpected().value(), oops); + } + { + auto e = makeExpectedFromError(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(message)); + String e1(makeUnexpected(message)); + String e2(makeUnexpected(std::string())); + EXPECT_EQ(e0.error(), std::string(message)); + EXPECT_EQ(e0, e1); + EXPECT_NE(e0, e2); + String* e4 = new String(makeUnexpected(message)); + String* e5 = new String(*e4); + EXPECT_EQ(e0, *e4); + delete e4; + EXPECT_EQ(e0, *e5); + delete e5; + } +} + +TEST(WTF_Expected, comparison) +{ + typedef Expected Ex; + typedef Expected 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 NT; + typedef Expected TN; + typedef Expected NN; + typedef Expected 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 E; + std::unordered_map 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 E; + std::unordered_map 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, int> expected = Ref(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> expected = makeExpected, int>(Ref(a)); + EXPECT_TRUE(expected.hasValue()); + EXPECT_EQ(&a, expected.value().ptr()); + } + + ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); + + { + RefLogger a("a"); + Expected> expected = makeUnexpected(Ref(a)); + EXPECT_FALSE(expected.hasValue()); + EXPECT_EQ(&a, expected.error().ptr()); + } + + ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); + + { + RefLogger a("a"); + Expected> expected = makeUnexpected(Ref(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 -#include - -namespace TestWebKitAPI { - -static int returnFortyTwo() -{ - return 42; -} - -TEST(FunctionalTest, Basic) -{ - Function emptyFunction; - ASSERT_TRUE(emptyFunction.isNull()); - - Function 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 multiplyFourByTwoFunction = bind(multiplyByTwo, 4); - ASSERT_EQ(8, multiplyFourByTwoFunction()); - - Function 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 multiplyFourByTwoFunction = bind(multiply, 4, 2); - ASSERT_EQ(8, multiplyFourByTwoFunction()); - - Function 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 function1 = bind(&A::f, &a); - ASSERT_EQ(10, function1()); - - Function 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 function1 = bind(&B::f, &b); - function1(); - - Function 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 { -public: - static PassRefPtr 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 five = Number::create(5); - Function multiplyFiveByTwoFunction = bind(multiplyNumberByTwo, five); - ASSERT_EQ(10, multiplyFiveByTwoFunction()); - - Function multiplyFourByTwoFunction = bind(multiplyNumberByTwo, Number::create(4)); - ASSERT_EQ(8, multiplyFourByTwoFunction()); - - RefPtr six = Number::create(6); - Function multiplySixByTwoFunction = bind(multiplyNumberByTwo, six.release()); - ASSERT_FALSE(six); - ASSERT_EQ(12, multiplySixByTwoFunction()); -} - -namespace RefAndDerefTests { - - template struct RefCounted { - void ref(); - void deref(); - }; - struct Connection : RefCounted { }; - COMPILE_ASSERT(WTF::HasRefAndDeref::value, class_has_ref_and_deref); - - struct NoRefOrDeref { }; - COMPILE_ASSERT(!WTF::HasRefAndDeref::value, class_has_no_ref_or_deref); - - struct RefOnly { void ref(); }; - COMPILE_ASSERT(!WTF::HasRefAndDeref::value, class_has_ref_only); - - struct DerefOnly { void deref(); }; - COMPILE_ASSERT(!WTF::HasRefAndDeref::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 +#include +#include + +namespace TestWebKitAPI { + +typedef WTF::HashCountedSet 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 { + static const int minimumTableSize = 8; +}; + +typedef HashCountedSet::Hash, TestDoubleHashTraits> DoubleHashCountedSet; + +static int bucketForKey(double key) +{ + return DefaultHash::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 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 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 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 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> hashCountedSet; + + auto uniquePtr = std::make_unique(); + 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> hashCountedSet; + + auto uniquePtr = std::make_unique(); + 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::TestingScope deleterCounterScope; + + HashCountedSet>> hashCountedSet; + + std::unique_ptr> uniquePtr(new ConstructorDestructorCounter(), DeleterCounter()); + hashCountedSet.add(WTFMove(uniquePtr)); + + EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount); + EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount); + + EXPECT_EQ(0u, DeleterCounter::deleterCount()); + + hashCountedSet.clear(); + + EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount); + EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount); + + EXPECT_EQ(1u, DeleterCounter::deleterCount()); +} + +TEST(WTF_HashCountedSet, UniquePtrKey_FindUsingRawPointer) +{ + HashCountedSet> hashCountedSet; + + auto uniquePtr = std::make_unique(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> hashCountedSet; + + auto uniquePtr = std::make_unique(5); + int* ptr = uniquePtr.get(); + hashCountedSet.add(WTFMove(uniquePtr)); + + EXPECT_EQ(true, hashCountedSet.contains(ptr)); +} + +TEST(WTF_HashCountedSet, UniquePtrKey_GetUsingRawPointer) +{ + HashCountedSet> hashCountedSet; + + auto uniquePtr = std::make_unique(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> hashCountedSet; + + auto uniquePtr = std::make_unique(); + 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> hashCountedSet; + + DerivedRefLogger a("a"); + RefPtr 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> hashCountedSet; + + DerivedRefLogger a("a"); + RefPtr ptr(&a); + hashCountedSet.add(WTFMove(ptr)); + + EXPECT_STREQ("ref(a) ", takeLogStr().c_str()); +} + +TEST(WTF_HashCountedSet, RefPtrKey_AddUsingMove) +{ + HashCountedSet> hashCountedSet; + + DerivedRefLogger a("a"); + RefPtr ptr(&a); + hashCountedSet.add(WTFMove(ptr)); + + EXPECT_STREQ("ref(a) ", takeLogStr().c_str()); +} + +TEST(WTF_HashCountedSet, RefPtrKey_AddUsingRaw) +{ + HashCountedSet> hashCountedSet; + + DerivedRefLogger a("a"); + RefPtr 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> hashCountedSet; + + DerivedRefLogger a("a"); + + { + RefPtr ptr(&a); + hashCountedSet.add(ptr); + } + + EXPECT_STREQ("ref(a) ref(a) deref(a) ", takeLogStr().c_str()); + + { + RefPtr 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> hashCountedSet; + + DerivedRefLogger a("a"); + + { + RefPtr ptr(&a); + hashCountedSet.add(ptr); + } + + EXPECT_STREQ("ref(a) ref(a) deref(a) ", takeLogStr().c_str()); + + { + RefPtr 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> hashCountedSet; + + DerivedRefLogger a("a"); + + { + RefPtr ptr(&a); + hashCountedSet.add(ptr); + } + + EXPECT_STREQ("ref(a) ref(a) deref(a) ", takeLogStr().c_str()); + + { + RefPtr 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 #include +#include #include 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 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, int> map; + + auto uniquePtr = std::make_unique(); + 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::TestingScope deleterCounterScope; + + HashMap>, int> map; + + std::unique_ptr> uniquePtr(new ConstructorDestructorCounter(), DeleterCounter()); + map.add(WTFMove(uniquePtr), 2); + + EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount); + EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount); + + EXPECT_EQ(0u, DeleterCounter::deleterCount()); + + map.clear(); + + EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount); + EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount); + + EXPECT_EQ(1u, DeleterCounter::deleterCount()); +} + +TEST(WTF_HashMap, UniquePtrKey_FindUsingRawPointer) +{ + HashMap, int> map; + + auto uniquePtr = std::make_unique(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, int> map; + + auto uniquePtr = std::make_unique(5); + int* ptr = uniquePtr.get(); + map.add(WTFMove(uniquePtr), 2); + + EXPECT_EQ(true, map.contains(ptr)); +} + +TEST(WTF_HashMap, UniquePtrKey_GetUsingRawPointer) +{ + HashMap, int> map; + + auto uniquePtr = std::make_unique(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, int> map; + + auto uniquePtr = std::make_unique(); + 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, int> map; + + auto uniquePtr = std::make_unique(); + 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, int> map; + + DerivedRefLogger a("a"); + RefPtr ptr(&a); + map.add(ptr, 0); + + ASSERT_STREQ("ref(a) ref(a) ", takeLogStr().c_str()); +} + +TEST(WTF_HashMap, RefPtrKey_AddUsingRelease) +{ + HashMap, int> map; + + DerivedRefLogger a("a"); + RefPtr ptr(&a); + map.add(WTFMove(ptr), 0); + + EXPECT_STREQ("ref(a) ", takeLogStr().c_str()); +} + +TEST(WTF_HashMap, RefPtrKey_AddUsingMove) +{ + HashMap, int> map; + + DerivedRefLogger a("a"); + RefPtr ptr(&a); + map.add(WTFMove(ptr), 0); + + EXPECT_STREQ("ref(a) ", takeLogStr().c_str()); +} + +TEST(WTF_HashMap, RefPtrKey_AddUsingRaw) +{ + HashMap, int> map; + + DerivedRefLogger a("a"); + RefPtr ptr(&a); + map.add(ptr.get(), 0); + + EXPECT_STREQ("ref(a) ref(a) ", takeLogStr().c_str()); +} + +TEST(WTF_HashMap, RefPtrKey_AddKeyAlreadyPresent) +{ + HashMap, int> map; + + DerivedRefLogger a("a"); + + { + RefPtr ptr(&a); + map.add(ptr, 0); + } + + EXPECT_STREQ("ref(a) ref(a) deref(a) ", takeLogStr().c_str()); + + { + RefPtr 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, int> map; + + DerivedRefLogger a("a"); + + { + RefPtr ptr(&a); + map.add(ptr, 0); + } + + EXPECT_STREQ("ref(a) ref(a) deref(a) ", takeLogStr().c_str()); + + { + RefPtr 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, int> map; + + DerivedRefLogger a("a"); + + { + RefPtr ptr(&a); + map.add(ptr, 0); + } + + EXPECT_STREQ("ref(a) ref(a) deref(a) ", takeLogStr().c_str()); + + { + RefPtr 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, int> map; + + DerivedRefLogger a("a"); + RefPtr ptr(&a); + map.set(ptr, 0); + + ASSERT_STREQ("ref(a) ref(a) ", takeLogStr().c_str()); +} + +TEST(WTF_HashMap, RefPtrKey_SetUsingRelease) +{ + HashMap, int> map; + + DerivedRefLogger a("a"); + RefPtr ptr(&a); + map.set(WTFMove(ptr), 0); + + EXPECT_STREQ("ref(a) ", takeLogStr().c_str()); +} + + +TEST(WTF_HashMap, RefPtrKey_SetUsingMove) +{ + HashMap, int> map; + + DerivedRefLogger a("a"); + RefPtr ptr(&a); + map.set(WTFMove(ptr), 0); + + EXPECT_STREQ("ref(a) ", takeLogStr().c_str()); +} + +TEST(WTF_HashMap, RefPtrKey_SetUsingRaw) +{ + HashMap, int> map; + + DerivedRefLogger a("a"); + RefPtr ptr(&a); + map.set(ptr.get(), 0); + + EXPECT_STREQ("ref(a) ref(a) ", takeLogStr().c_str()); +} + +TEST(WTF_HashMap, RefPtrKey_SetKeyAlreadyPresent) +{ + HashMap, int> map; + + DerivedRefLogger a("a"); + + RefPtr ptr(&a); + map.set(ptr, 0); + + EXPECT_STREQ("ref(a) ref(a) ", takeLogStr().c_str()); + + { + RefPtr 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, int> map; + + DerivedRefLogger a("a"); + + RefPtr ptr(&a); + map.set(ptr, 0); + + EXPECT_STREQ("ref(a) ref(a) ", takeLogStr().c_str()); + + { + RefPtr 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, int> map; + + DerivedRefLogger a("a"); + + RefPtr ptr(&a); + map.set(ptr, 0); + + EXPECT_STREQ("ref(a) ref(a) ", takeLogStr().c_str()); + + { + RefPtr 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 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 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> map; + { + auto addResult = map.ensure(1, [] { return std::make_unique(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(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> map; + + { + DerivedRefLogger a("a"); + + map.ensure(1, [&] { return RefPtr(&a); }); + EXPECT_STREQ("ref(a) ", takeLogStr().c_str()); + + map.ensure(1, [&] { return RefPtr(&a); }); + EXPECT_STREQ("", takeLogStr().c_str()); + } +} + +class ObjectWithRefLogger { +public: + ObjectWithRefLogger(Ref&& logger) + : m_logger(WTFMove(logger)) + { + } + + Ref m_logger; +}; + + +void testMovingUsingEnsure(Ref&& logger) +{ + HashMap> map; + + map.ensure(1, [&] { return std::make_unique(WTFMove(logger)); }); +} + +void testMovingUsingAdd(Ref&& logger) +{ + HashMap> map; + + auto& slot = map.add(1, nullptr).iterator->value; + slot = std::make_unique(WTFMove(logger)); +} + +TEST(WTF_HashMap, Ensure_LambdasCapturingByReference) +{ + { + DerivedRefLogger a("a"); + Ref ref(a); + testMovingUsingEnsure(WTFMove(ref)); + + EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); + } + + { + DerivedRefLogger a("a"); + Ref 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 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* bucketAddress { nullptr }; + const DerefObserver* observedBucket { nullptr }; + }; + + auto observer = std::make_unique(); + + HashMap, 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::hashTableDeletedValue()); + EXPECT_EQ(observer->count, 0u); +} + +TEST(WTF_HashMap, Ref_Key) +{ + { + HashMap, int> map; + + RefLogger a("a"); + Ref ref(a); + map.add(WTFMove(ref), 1); + } + + ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); + + { + HashMap, int> map; + + RefLogger a("a"); + Ref ref(a); + map.set(WTFMove(ref), 1); + } + + ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); + + { + HashMap, int> map; + + RefLogger a("a"); + Ref refA(a); + map.add(WTFMove(refA), 1); + + Ref refA2(a); + map.set(WTFMove(refA2), 1); + } + + ASSERT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str()); + + { + HashMap, int> map; + + RefLogger a("a"); + Ref ref(a); + map.ensure(WTFMove(ref), []() { + return 1; + }); + } + + ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); + + { + HashMap, int> map; + + RefLogger a("a"); + Ref 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, int> map; + + RefLogger a("a"); + Ref ref(a); + map.add(WTFMove(ref), 1); + + map.remove(&a); + } + + ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); + + { + HashMap, int> map; + + RefLogger a("a"); + Ref 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, int> map; + for (int i = 0; i < 64; ++i) { + Ref 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> map; + + RefLogger a("a"); + Ref ref(a); + map.add(1, WTFMove(ref)); + } + + ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); + + { + HashMap> map; + + RefLogger a("a"); + Ref ref(a); + map.set(1, WTFMove(ref)); + } + + ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); + + { + HashMap> map; + + RefLogger a("a"); + Ref refA(a); + map.add(1, WTFMove(refA)); + + RefLogger b("b"); + Ref refB(b); + map.set(1, WTFMove(refB)); + } + + ASSERT_STREQ("ref(a) ref(b) deref(a) deref(b) ", takeLogStr().c_str()); + + { + HashMap> map; + + RefLogger a("a"); + Ref 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> map; + + auto emptyGet = map.get(1); + ASSERT_TRUE(emptyGet == nullptr); + } + + { + HashMap> map; + + RefLogger a("a"); + Ref ref(a); + map.add(1, WTFMove(ref)); + + auto aOut = map.take(1); + ASSERT_TRUE(static_cast(aOut)); + ASSERT_EQ(&a, aOut.value().ptr()); + } + + ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); + + { + HashMap> map; + + auto emptyTake = map.take(1); + ASSERT_FALSE(static_cast(emptyTake)); + } + + { + HashMap> map; + + RefLogger a("a"); + Ref ref(a); + map.add(1, WTFMove(ref)); + map.remove(1); + } + + ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); + + { + HashMap> map; + + RefLogger a("a"); + map.ensure(1, [&]() mutable { + Ref ref(a); + return ref; + }); + } + + ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); + + { + HashMap> map; + for (int i = 0; i < 64; ++i) { + Ref 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 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 - +#include namespace TestWebKitAPI { @@ -43,7 +46,7 @@ void testInitialCapacity() HashSet::Hash, InitialCapacityTestHashTraits > 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 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> set; + + auto uniquePtr = std::make_unique(); + 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> set; + + auto uniquePtr = std::make_unique(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> set; + + auto uniquePtr = std::make_unique(5); + int* ptr = uniquePtr.get(); + set.add(WTFMove(uniquePtr)); + + EXPECT_EQ(true, set.contains(ptr)); +} + +TEST(WTF_HashSet, UniquePtrKey_RemoveUsingRawPointer) +{ + ConstructorDestructorCounter::TestingScope scope; + + HashSet> set; + + auto uniquePtr = std::make_unique(); + 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> set; + + auto uniquePtr = std::make_unique(); + 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 foo; + HashSet bar(foo); + + EXPECT_EQ(0u, bar.capacity()); + EXPECT_EQ(0u, bar.size()); + } + { + HashSet foo({ 1, 5, 64, 42 }); + EXPECT_EQ(4u, foo.size()); + foo.remove(1); + foo.remove(5); + foo.remove(42); + foo.remove(64); + HashSet bar(foo); + + EXPECT_EQ(0u, bar.capacity()); + EXPECT_EQ(0u, bar.size()); + } +} + +TEST(WTF_HashSet, CopyAllocateAtLeastMinimumCapacity) +{ + HashSet foo({ 42 }); + EXPECT_EQ(1u, foo.size()); + HashSet 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 source; + for (unsigned i = 1; i < size + 1; ++i) + source.add(i); + + HashSet copy1(source); + HashSet copy2(source); + HashSet 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* bucketAddress { nullptr }; + const DerefObserver* observedBucket { nullptr }; + }; + + auto observer = std::make_unique(); + + HashSet> 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::hashTableDeletedValue()); + EXPECT_EQ(observer->count, 0u); +} + + +TEST(WTF_HashSet, UniquePtrNotZeroedBeforeDestructor) +{ + struct DestructorObserver { + ~DestructorObserver() + { + observe(); + } + std::function observe; + }; + + const std::unique_ptr* bucketAddress = nullptr; + const DestructorObserver* observedBucket = nullptr; + std::unique_ptr observer(new DestructorObserver { [&]() { + observedBucket = bucketAddress->get(); + }}); + + const DestructorObserver* observerAddress = observer.get(); + + HashSet> 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(-1)); +} + +TEST(WTF_HashSet, Ref) +{ + { + HashSet> set; + + RefLogger a("a"); + Ref ref(a); + set.add(WTFMove(ref)); + } + + ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); + + { + HashSet> set; + + RefLogger a("a"); + Ref ref(a); + set.add(ref.copyRef()); + } + + ASSERT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str()); + + { + HashSet> set; + + RefLogger a("a"); + Ref ref(a); + set.add(WTFMove(ref)); + set.remove(&a); + } + + ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); + + { + HashSet> set; + + RefLogger a("a"); + Ref ref(a); + set.add(WTFMove(ref)); + + auto aOut = set.take(&a); + ASSERT_TRUE(static_cast(aOut)); + ASSERT_EQ(&a, aOut.value().ptr()); + } + + ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); + + { + HashSet> set; + + RefLogger a("a"); + Ref ref(a); + set.add(WTFMove(ref)); + + auto aOut = set.takeAny(); + ASSERT_TRUE(static_cast(aOut)); + ASSERT_EQ(&a, aOut.value().ptr()); + } + + ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); + + { + HashSet> set; + auto emptyTake = set.takeAny(); + ASSERT_FALSE(static_cast(emptyTake)); + } + + { + HashSet> set; + + RefLogger a("a"); + Ref ref(a); + set.add(WTFMove(ref)); + + ASSERT_TRUE(set.contains(&a)); + } + + ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); + + { + HashSet> set; + for (int i = 0; i < 64; ++i) { + Ref 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 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 +#include + +namespace TestWebKitAPI { + +static void testUInt32LEBDecode(std::initializer_list data, size_t startOffset, bool expectedStatus, uint32_t expectedResult, size_t expectedOffset) +{ + Vector 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 data, size_t startOffset, bool expectedStatus, uint64_t expectedResult, size_t expectedOffset) +{ + Vector 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 data, size_t startOffset, bool expectedStatus, int32_t expectedResult, size_t expectedOffset) +{ + Vector 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 data, size_t startOffset, bool expectedStatus, int64_t expectedResult, size_t expectedOffset) +{ + Vector 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::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::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::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::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 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 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 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 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 +#include +#include +#include + +using namespace WTF; + +namespace TestWebKitAPI { + +struct LockInspector { + template + static bool isFullyReset(LockType& lock) + { + return lock.isFullyReset(); + } +}; + +template +void runLockTest(unsigned numThreadGroups, unsigned numThreadsPerGroup, unsigned workPerCriticalSection, unsigned numIterations) +{ + std::unique_ptr locks = std::make_unique(numThreadGroups); + std::unique_ptr words = std::make_unique(numThreadGroups); + std::unique_ptr threads = std::make_unique(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(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(1, 1, 1, 10000000); +} + +TEST(WTF_WordLock, UncontendedLongSection) +{ + runLockTest(1, 1, 10000, 1000); +} + +TEST(WTF_WordLock, ContendedShortSection) +{ + if (skipSlow()) + return; + runLockTest(1, 10, 1, 5000000); +} + +TEST(WTF_WordLock, ContendedLongSection) +{ + if (skipSlow()) + return; + runLockTest(1, 10, 10000, 10000); +} + +TEST(WTF_WordLock, ManyContendedShortSections) +{ + if (skipSlow()) + return; + runLockTest(10, 10, 1, 500000); +} + +TEST(WTF_WordLock, ManyContendedLongSections) +{ + if (skipSlow()) + return; + runLockTest(10, 10, 10000, 500); +} + +TEST(WTF_Lock, UncontendedShortSection) +{ + runLockTest(1, 1, 1, 10000000); +} + +TEST(WTF_Lock, UncontendedLongSection) +{ + runLockTest(1, 1, 10000, 1000); +} + +TEST(WTF_Lock, ContendedShortSection) +{ + if (skipSlow()) + return; + runLockTest(1, 10, 1, 10000000); +} + +TEST(WTF_Lock, ContendedLongSection) +{ + if (skipSlow()) + return; + runLockTest(1, 10, 10000, 10000); +} + +TEST(WTF_Lock, ManyContendedShortSections) +{ + if (skipSlow()) + return; + runLockTest(10, 10, 1, 500000); +} + +TEST(WTF_Lock, ManyContendedLongSections) +{ + if (skipSlow()) + return; + runLockTest(10, 10, 10000, 1000); +} + +TEST(WTF_Lock, ManyContendedLongerSections) +{ + if (skipSlow()) + return; + runLockTest(10, 10, 100000, 1); +} + +TEST(WTF_Lock, SectionAddressCollision) +{ + if (skipSlow()) + return; + runLockTest(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 +#include #include using namespace std; -#if COMPILER(MSVC) -// Work around Visual Studio 2008's lack of an INFINITY or NAN definition. -#include -#if !defined(INFINITY) -#define INFINITY (numeric_limits::infinity()) -#endif -#if !defined(NAN) -#define NAN (numeric_limits::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::infinity()), MediaTime::positiveInfiniteTime()); + EXPECT_EQ(MediaTime::createWithFloat(-std::numeric_limits::infinity()), MediaTime::negativeInfiniteTime()); + EXPECT_EQ(MediaTime::createWithFloat(std::numeric_limits::quiet_NaN()), MediaTime::invalidTime()); + + EXPECT_EQ(MediaTime::createWithDouble(std::numeric_limits::infinity()), MediaTime::positiveInfiniteTime()); + EXPECT_EQ(MediaTime::createWithDouble(-std::numeric_limits::infinity()), MediaTime::negativeInfiniteTime()); + EXPECT_EQ(MediaTime::createWithDouble(std::numeric_limits::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::max(), 2) + MediaTime(numeric_limits::max(), 2)).timeScale(), 1); - EXPECT_EQ((MediaTime(numeric_limits::min(), 2) - MediaTime(numeric_limits::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::max(), 2) + MediaTime(numeric_limits::max(), 2)).timeScale(), 1U); + EXPECT_EQ((MediaTime(numeric_limits::min(), 2) - MediaTime(numeric_limits::max(), 2)).timeScale(), 1U); EXPECT_EQ(MediaTime(numeric_limits::max(), 1) + MediaTime(numeric_limits::max(), 1), MediaTime::positiveInfiniteTime()); EXPECT_EQ(MediaTime(numeric_limits::min(), 1) + MediaTime(numeric_limits::min(), 1), MediaTime::negativeInfiniteTime()); EXPECT_EQ(MediaTime(numeric_limits::min(), 1) - MediaTime(numeric_limits::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 #include +#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 + +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 empty; + ASSERT_EQ(nullptr, empty.get()); + + { + NakedPtr ptr(&a); + ASSERT_EQ(&a, ptr.get()); + ASSERT_EQ(&a, &*ptr); + ASSERT_EQ(&a.name, &ptr->name); + } + + { + NakedPtr ptr = &a; + ASSERT_EQ(&a, ptr.get()); + } + + { + NakedPtr p1 = &a; + NakedPtr p2(p1); + ASSERT_EQ(&a, p1.get()); + ASSERT_EQ(&a, p2.get()); + } + + { + NakedPtr p1 = &a; + NakedPtr p2 = p1; + ASSERT_EQ(&a, p1.get()); + ASSERT_EQ(&a, p2.get()); + } + + { + NakedPtr p1 = &a; + NakedPtr p2 = WTFMove(p1); + ASSERT_EQ(&a, p1.get()); + ASSERT_EQ(&a, p2.get()); + } + + { + NakedPtr p1 = &a; + NakedPtr p2(WTFMove(p1)); + ASSERT_EQ(&a, p1.get()); + ASSERT_EQ(&a, p2.get()); + } + + { + NakedPtr p1 = &a; + NakedPtr p2 = p1; + ASSERT_EQ(&a, p1.get()); + ASSERT_EQ(&a, p2.get()); + } + + { + NakedPtr p1 = &a; + NakedPtr p2 = WTFMove(p1); + ASSERT_EQ(&a, p1.get()); + ASSERT_EQ(&a, p2.get()); + } + + { + NakedPtr 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 p1(&a); + NakedPtr 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 ptr(&a); + ASSERT_EQ(&a, ptr.get()); + ptr = &b; + ASSERT_EQ(&b, ptr.get()); + } + + { + NakedPtr ptr(&a); + ASSERT_EQ(&a, ptr.get()); + ptr = nullptr; + ASSERT_EQ(nullptr, ptr.get()); + } + + { + NakedPtr p1(&a); + NakedPtr 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 p1(&a); + NakedPtr 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 ptr(&a); + ASSERT_EQ(&a, ptr.get()); + ptr = &c; + ASSERT_EQ(&c, ptr.get()); + } + + { + NakedPtr p1(&a); + NakedPtr 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 ptr(&a); + ASSERT_EQ(&a, ptr.get()); + ptr = ptr; + ASSERT_EQ(&a, ptr.get()); + } + + { + NakedPtr 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 p1(&a); + NakedPtr 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 p1(&a); + NakedPtr 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 nakedPtrFoo(RefLogger& logger) +{ + return NakedPtr(&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 + +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 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 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 set { ExampleFlags::A, ExampleFlags::B }; + + EXPECT_TRUE((set == OptionSet { ExampleFlags::A, ExampleFlags::B })); + EXPECT_TRUE((set == OptionSet { ExampleFlags::B, ExampleFlags::A })); + EXPECT_FALSE(set == ExampleFlags::B); +} + +TEST(WTF_OptionSet, NotEqual) +{ + OptionSet set = ExampleFlags::A; + + EXPECT_TRUE(set != ExampleFlags::B); + EXPECT_FALSE(set != ExampleFlags::A); +} + +TEST(WTF_OptionSet, Minus) +{ + OptionSet set { ExampleFlags::A, ExampleFlags::B, ExampleFlags::C }; + + EXPECT_TRUE(((set - ExampleFlags::A) == OptionSet { ExampleFlags::B, ExampleFlags::C })); + EXPECT_TRUE(((set - ExampleFlags::D) == OptionSet { ExampleFlags::A, ExampleFlags::B, ExampleFlags::C })); + EXPECT_TRUE((set - set).isEmpty()); +} + +TEST(WTF_OptionSet, ContainsTwoFlags) +{ + OptionSet 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 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 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 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 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::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 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::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 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::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 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::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 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::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 set { ExampleFlags::C, ExampleFlags::B }; + OptionSet::iterator it1 = set.begin(); + OptionSet::iterator it2 = it1; + ++it1; + EXPECT_STRONG_ENUM_EQ(ExampleFlags::C, *it1); + EXPECT_STRONG_ENUM_EQ(ExampleFlags::B, *it2); +} + +TEST(WTF_OptionSet, IterateOverOptionSetThatContainsTwoFlags) +{ + OptionSet set { ExampleFlags::A, ExampleFlags::C }; + OptionSet::iterator it = set.begin(); + OptionSet::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 set { ExampleFlags::D, ExampleFlags::E }; + OptionSet::iterator it = set.begin(); + OptionSet::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 set { ThirtyTwoBitFlags::A }; + OptionSet::iterator it = set.begin(); + OptionSet::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 set { SixtyFourBitFlags::A }; + OptionSet::iterator it = set.begin(); + OptionSet::iterator end = set.end(); + EXPECT_TRUE(it != end); + ++it; + EXPECT_TRUE(it == end); +} + +TEST(WTF_OptionSet, IterationOrderTheSameRegardlessOfInsertionOrder) +{ + OptionSet set1 = ExampleFlags::C; + set1 |= ExampleFlags::A; + + OptionSet set2 = ExampleFlags::A; + set2 |= ExampleFlags::C; + + OptionSet::iterator it1 = set1.begin(); + OptionSet::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 + +namespace TestWebKitAPI { + +TEST(WTF_Optional, Disengaged) +{ + { + std::optional optional; + + EXPECT_FALSE(static_cast(optional)); + } + + { + std::optional optional { std::nullopt }; + + EXPECT_FALSE(static_cast(optional)); + } +} + +TEST(WTF_Optional, Engaged) +{ + std::optional optional { 10 }; + + EXPECT_TRUE(static_cast(optional)); + EXPECT_EQ(10, optional.value()); +} + +TEST(WTF_Optional, Destructor) +{ + static bool didCallDestructor = false; + struct A { + ~A() + { + EXPECT_FALSE(didCallDestructor); + didCallDestructor = true; + } + }; + + { + std::optional optional { std::in_place }; + + EXPECT_TRUE(static_cast(optional)); + } + + EXPECT_TRUE(didCallDestructor); +} + +TEST(WTF_Optional, Callback) +{ + bool called = false; + std::optional 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 unengaged1; + std::optional unengaged2; + + std::optional engaged1 { 1 }; + std::optional engaged2 { 2 }; + std::optional 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 unengaged1; + std::optional unengaged2; + + std::optional engaged1 { 1 }; + std::optional engaged2 { 2 }; + std::optional 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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 locker(lock); + awake.add(currentThread()); + lastAwoken = currentThread(); + condition.notify_one(); + })); + } + } + + void unparkOne(unsigned singleUnparkIndex) + { + EXPECT_EQ(0u, lastAwoken); + + unsigned numWaitingOnAddress = 0; + Vector 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 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 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 semaphore; + std::mutex lock; + std::condition_variable condition; + HashSet awake; + Vector threads; + ThreadIdentifier lastAwoken { 0 }; +}; + +void runParkingTest(unsigned numLatches, unsigned delay, unsigned numThreads, unsigned numSingleUnparks) +{ + std::unique_ptr tests = std::make_unique(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 #include #include @@ -38,14 +37,14 @@ TEST(WTF_Ref, Basic) { Ref 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 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 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 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 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 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 passWithPassRef(PassRef reference) +static Ref passWithRef(Ref&& reference) { - return reference; + return WTFMove(reference); } -RefPtr passWithPassRefPtr(PassRefPtr reference) +static RefPtr passWithPassRefPtr(PassRefPtr reference) { return reference; } @@ -115,32 +114,48 @@ TEST(WTF_Ref, ReturnValue) DerivedRefLogger c("c"); { - Ref ptr(passWithPassRef(a)); - ASSERT_EQ(&a, &ptr.get()); + Ref ptr(passWithRef(Ref(a))); + ASSERT_EQ(&a, ptr.ptr()); } ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); { Ref 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 ptr(passWithPassRef(a)); + RefPtr ptr(passWithRef(a)); ASSERT_EQ(&a, ptr.get()); } ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); { - RefPtr ptr(passWithPassRefPtr(passWithPassRef(a))); + RefPtr ptr(passWithPassRefPtr(passWithRef(a))); ASSERT_EQ(&a, ptr.get()); } ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); + + { + RefPtr ptr(&a); + RefPtr ptr2(WTFMove(ptr)); + ASSERT_EQ(nullptr, ptr.get()); + ASSERT_EQ(&a, ptr2.get()); + } + ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); + + { + Ref derivedReference(a); + Ref 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 +#include +#include + +namespace TestWebKitAPI { + +static const int IncrementExpected = 0xC0FFEE1; +static const int DecrementExpected = 0xC0FFEE2; +static const int CallbackNotExpected = 0xDECAF; + +enum TestCounterType { }; +typedef RefCounter TestCounter; +typedef TestCounter::Token TokenType; + +TEST(WTF, RefCounter) +{ + // RefCounter API is pretty simple, containing the following 4 methods to test: + // + // 1) RefCounter(std::function); + // 2) ~RefCounter(); + // 3) Ref 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(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(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(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(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(counter.value())); + // Testing (3k) - deref using a Ref rather than a RefPtr. + + callbackValue = DecrementExpected; + } + EXPECT_EQ(1, callbackValue); + EXPECT_EQ(1, static_cast(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(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(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(counter.value())); + // Testing (3h) - ref without callback + TokenType incTo1(counter.count()); + // Testing (4c) - value as read after the ref. + EXPECT_EQ(1, static_cast(counter.value())); + // Testing (3i) - deref without callback + incTo1 = nullptr; + // Testing (4c) - value as read after the deref. + EXPECT_EQ(0, static_cast(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 +#include #include namespace TestWebKitAPI { @@ -69,7 +71,7 @@ TEST(WTF_RefPtr, Basic) { RefPtr p1 = &a; - RefPtr p2 = std::move(p1); + RefPtr p2 = WTFMove(p1); ASSERT_EQ(nullptr, p1.get()); ASSERT_EQ(&a, p2.get()); } @@ -77,7 +79,7 @@ TEST(WTF_RefPtr, Basic) { RefPtr p1 = &a; - RefPtr p2(std::move(p1)); + RefPtr p2(WTFMove(p1)); ASSERT_EQ(nullptr, p1.get()); ASSERT_EQ(&a, p2.get()); } @@ -93,7 +95,7 @@ TEST(WTF_RefPtr, Basic) { RefPtr p1 = &a; - RefPtr p2 = std::move(p1); + RefPtr p2 = WTFMove(p1); ASSERT_EQ(nullptr, p1.get()); ASSERT_EQ(&a, p2.get()); } @@ -102,7 +104,7 @@ TEST(WTF_RefPtr, Basic) { RefPtr 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 passRef(a); - RefPtr ptr = std::move(passRef); + Ref passRef(a); + RefPtr 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 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 { + static Ref create() { return adoptRef(*new ConstRefCounted); } +}; + +const ConstRefCounted& returnConstRefCountedRef() +{ + static NeverDestroyed instance; + return instance.get(); +} +ConstRefCounted& returnRefCountedRef() +{ + static NeverDestroyed instance; + return instance.get(); +} + +TEST(WTF_RefPtr, Const) +{ + // This test passes if it compiles without an error. + auto a = ConstRefCounted::create(); + Ref b = WTFMove(a); + RefPtr c = b.ptr(); + Ref d = returnConstRefCountedRef(); + RefPtr e = &returnConstRefCountedRef(); + RefPtr f = ConstRefCounted::create(); + RefPtr g = f; + RefPtr h(f); + Ref 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 + +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(); + 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 { + public: + DerivedTimer(bool& testFinished) + : RunLoop::Timer(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 { + public: + DerivedTimer(bool& testFinished) + : RunLoop::Timer(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 + +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 +#include + +using namespace WTF; + +namespace TestWebKitAPI { + +// This test relies on this module being compiled with -fno-elide-constructors +TEST(WTF_ScopedLambda, NoRVOLivenessBug) +{ + Vector vector; + for (unsigned i = 0; i < 10; ++i) + vector.append(i); + + auto lambda = scopedLambda( + [=] (size_t i) -> int { + return vector[i]; + }); + + for (unsigned i = 0; i < 10; ++i) + EXPECT_EQ(i, static_cast(lambda(i))); +} + +} // namespace TestWebKitAPI + diff --git a/Tools/TestWebKitAPI/Tests/WTF/SetForScope.cpp b/Tools/TestWebKitAPI/Tests/WTF/SetForScope.cpp new file mode 100644 index 000000000..92e3494d6 --- /dev/null +++ b/Tools/TestWebKitAPI/Tests/WTF/SetForScope.cpp @@ -0,0 +1,47 @@ +/* + * 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 + +namespace TestWebKitAPI { + +TEST(WTF, SetForScopeNested) +{ + bool originallyFalse = false; + { + SetForScope change1OriginallyFalse(originallyFalse, true); + EXPECT_TRUE(originallyFalse); + { + SetForScope change2OriginallyFalse(originallyFalse, false); + EXPECT_FALSE(originallyFalse); + } + EXPECT_TRUE(originallyFalse); + } + EXPECT_FALSE(originallyFalse); +} + +} // namespace TestWebKitAPI 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 +#include + +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 +#include 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 +#include +#include #include namespace TestWebKitAPI { @@ -33,14 +34,14 @@ namespace TestWebKitAPI { TEST(WTF, StringImplCreationFromLiteral) { // Constructor using the template to determine the size. - RefPtr 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 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(programmaticString->characters8())); @@ -48,27 +49,16 @@ TEST(WTF, StringImplCreationFromLiteral) // Constructor without explicit size. const char* stringWithoutLengthLiteral = "No Size Literal"; - RefPtr 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(programmaticStringNoLength->characters8())); ASSERT_TRUE(programmaticStringNoLength->is8Bit()); } -TEST(WTF, StringImplFromLiteralLoop16BitConversion) -{ - RefPtr controlString = StringImpl::create("Template Literal"); - for (size_t i = 0; i < 10; ++i) { - RefPtr 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 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("")); + 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("")); + auto b = StringImpl::create(reinterpret_cast("")); + ASSERT_TRUE(equalIgnoringASCIICase(a.ptr(), b.ptr())); + ASSERT_TRUE(equalIgnoringASCIICase(b.ptr(), a.ptr())); +} + +static Ref 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(0), referenceA->findIgnoringASCIICase(referenceA.ptr())); + EXPECT_EQ(static_cast(0), referenceB->findIgnoringASCIICase(referenceB.ptr())); + + // A and B are distinct by the non-ascii character é/É. + EXPECT_EQ(static_cast(notFound), referenceA->findIgnoringASCIICase(referenceB.ptr())); + EXPECT_EQ(static_cast(notFound), referenceB->findIgnoringASCIICase(referenceA.ptr())); + + // Find the prefix. + EXPECT_EQ(static_cast(0), referenceA->findIgnoringASCIICase(StringImpl::createFromLiteral("a").ptr())); + EXPECT_EQ(static_cast(0), referenceA->findIgnoringASCIICase(stringFromUTF8("abcé").ptr())); + EXPECT_EQ(static_cast(0), referenceA->findIgnoringASCIICase(StringImpl::createFromLiteral("A").ptr())); + EXPECT_EQ(static_cast(0), referenceA->findIgnoringASCIICase(stringFromUTF8("ABCé").ptr())); + EXPECT_EQ(static_cast(0), referenceB->findIgnoringASCIICase(StringImpl::createFromLiteral("a").ptr())); + EXPECT_EQ(static_cast(0), referenceB->findIgnoringASCIICase(stringFromUTF8("abcÉ").ptr())); + EXPECT_EQ(static_cast(0), referenceB->findIgnoringASCIICase(StringImpl::createFromLiteral("A").ptr())); + EXPECT_EQ(static_cast(0), referenceB->findIgnoringASCIICase(stringFromUTF8("ABCÉ").ptr())); + + // Not a prefix. + EXPECT_EQ(static_cast(WTF::notFound), referenceA->findIgnoringASCIICase(StringImpl::createFromLiteral("x").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("accé").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("abcÉ").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceA->findIgnoringASCIICase(StringImpl::createFromLiteral("X").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("ABDé").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("ABCÉ").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceB->findIgnoringASCIICase(StringImpl::createFromLiteral("y").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("accÉ").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("abcé").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceB->findIgnoringASCIICase(StringImpl::createFromLiteral("Y").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("ABdÉ").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("ABCé").ptr())); + + // Find the infix. + EXPECT_EQ(static_cast(2), referenceA->findIgnoringASCIICase(stringFromUTF8("cée").ptr())); + EXPECT_EQ(static_cast(3), referenceA->findIgnoringASCIICase(stringFromUTF8("ée").ptr())); + EXPECT_EQ(static_cast(2), referenceA->findIgnoringASCIICase(stringFromUTF8("cé").ptr())); + EXPECT_EQ(static_cast(2), referenceA->findIgnoringASCIICase(stringFromUTF8("c").ptr())); + EXPECT_EQ(static_cast(3), referenceA->findIgnoringASCIICase(stringFromUTF8("é").ptr())); + EXPECT_EQ(static_cast(2), referenceA->findIgnoringASCIICase(stringFromUTF8("Cée").ptr())); + EXPECT_EQ(static_cast(3), referenceA->findIgnoringASCIICase(stringFromUTF8("éE").ptr())); + EXPECT_EQ(static_cast(2), referenceA->findIgnoringASCIICase(stringFromUTF8("Cé").ptr())); + EXPECT_EQ(static_cast(2), referenceA->findIgnoringASCIICase(stringFromUTF8("C").ptr())); + + EXPECT_EQ(static_cast(2), referenceB->findIgnoringASCIICase(stringFromUTF8("cÉe").ptr())); + EXPECT_EQ(static_cast(3), referenceB->findIgnoringASCIICase(stringFromUTF8("Ée").ptr())); + EXPECT_EQ(static_cast(2), referenceB->findIgnoringASCIICase(stringFromUTF8("cÉ").ptr())); + EXPECT_EQ(static_cast(2), referenceB->findIgnoringASCIICase(stringFromUTF8("c").ptr())); + EXPECT_EQ(static_cast(3), referenceB->findIgnoringASCIICase(stringFromUTF8("É").ptr())); + EXPECT_EQ(static_cast(2), referenceB->findIgnoringASCIICase(stringFromUTF8("CÉe").ptr())); + EXPECT_EQ(static_cast(3), referenceB->findIgnoringASCIICase(stringFromUTF8("ÉE").ptr())); + EXPECT_EQ(static_cast(2), referenceB->findIgnoringASCIICase(stringFromUTF8("CÉ").ptr())); + EXPECT_EQ(static_cast(2), referenceB->findIgnoringASCIICase(stringFromUTF8("C").ptr())); + + // Not an infix. + EXPECT_EQ(static_cast(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("céd").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("Ée").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("bé").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("x").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("É").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("CÉe").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("éd").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("CÉ").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("Y").ptr())); + + EXPECT_EQ(static_cast(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("cée").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("Éc").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("cé").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("W").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("é").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("bÉe").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("éE").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("BÉ").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("z").ptr())); + + // Find the suffix. + EXPECT_EQ(static_cast(6), referenceA->findIgnoringASCIICase(StringImpl::createFromLiteral("g").ptr())); + EXPECT_EQ(static_cast(4), referenceA->findIgnoringASCIICase(stringFromUTF8("efg").ptr())); + EXPECT_EQ(static_cast(3), referenceA->findIgnoringASCIICase(stringFromUTF8("éefg").ptr())); + EXPECT_EQ(static_cast(6), referenceA->findIgnoringASCIICase(StringImpl::createFromLiteral("G").ptr())); + EXPECT_EQ(static_cast(4), referenceA->findIgnoringASCIICase(stringFromUTF8("EFG").ptr())); + EXPECT_EQ(static_cast(3), referenceA->findIgnoringASCIICase(stringFromUTF8("éEFG").ptr())); + + EXPECT_EQ(static_cast(6), referenceB->findIgnoringASCIICase(StringImpl::createFromLiteral("g").ptr())); + EXPECT_EQ(static_cast(4), referenceB->findIgnoringASCIICase(stringFromUTF8("efg").ptr())); + EXPECT_EQ(static_cast(3), referenceB->findIgnoringASCIICase(stringFromUTF8("Éefg").ptr())); + EXPECT_EQ(static_cast(6), referenceB->findIgnoringASCIICase(StringImpl::createFromLiteral("G").ptr())); + EXPECT_EQ(static_cast(4), referenceB->findIgnoringASCIICase(stringFromUTF8("EFG").ptr())); + EXPECT_EQ(static_cast(3), referenceB->findIgnoringASCIICase(stringFromUTF8("ÉEFG").ptr())); + + // Not a suffix. + EXPECT_EQ(static_cast(WTF::notFound), referenceA->findIgnoringASCIICase(StringImpl::createFromLiteral("X").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("edg").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("Éefg").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceA->findIgnoringASCIICase(StringImpl::createFromLiteral("w").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("dFG").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("ÉEFG").ptr())); + + EXPECT_EQ(static_cast(WTF::notFound), referenceB->findIgnoringASCIICase(StringImpl::createFromLiteral("Z").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("ffg").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("éefg").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceB->findIgnoringASCIICase(StringImpl::createFromLiteral("r").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("EgG").ptr())); + EXPECT_EQ(static_cast(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("éEFG").ptr())); +} + +TEST(WTF, StringImplFindIgnoringASCIICaseWithValidOffset) +{ + auto reference = stringFromUTF8("ABCÉEFGaBcéeFG"); + EXPECT_EQ(static_cast(0), reference->findIgnoringASCIICase(stringFromUTF8("ABC").ptr(), 0)); + EXPECT_EQ(static_cast(7), reference->findIgnoringASCIICase(stringFromUTF8("ABC").ptr(), 1)); + EXPECT_EQ(static_cast(0), reference->findIgnoringASCIICase(stringFromUTF8("ABCÉ").ptr(), 0)); + EXPECT_EQ(static_cast(WTF::notFound), reference->findIgnoringASCIICase(stringFromUTF8("ABCÉ").ptr(), 1)); + EXPECT_EQ(static_cast(7), reference->findIgnoringASCIICase(stringFromUTF8("ABCé").ptr(), 0)); + EXPECT_EQ(static_cast(7), reference->findIgnoringASCIICase(stringFromUTF8("ABCé").ptr(), 1)); +} + +TEST(WTF, StringImplFindIgnoringASCIICaseWithInvalidOffset) +{ + auto reference = stringFromUTF8("ABCÉEFGaBcéeFG"); + EXPECT_EQ(static_cast(WTF::notFound), reference->findIgnoringASCIICase(stringFromUTF8("ABC").ptr(), 15)); + EXPECT_EQ(static_cast(WTF::notFound), reference->findIgnoringASCIICase(stringFromUTF8("ABC").ptr(), 16)); + EXPECT_EQ(static_cast(WTF::notFound), reference->findIgnoringASCIICase(stringFromUTF8("ABCÉ").ptr(), 17)); + EXPECT_EQ(static_cast(WTF::notFound), reference->findIgnoringASCIICase(stringFromUTF8("ABCÉ").ptr(), 42)); + EXPECT_EQ(static_cast(WTF::notFound), reference->findIgnoringASCIICase(stringFromUTF8("ABCÉ").ptr(), std::numeric_limits::max())); +} + +TEST(WTF, StringImplFindIgnoringASCIICaseOnNull) +{ + auto reference = stringFromUTF8("ABCÉEFG"); + EXPECT_EQ(static_cast(WTF::notFound), reference->findIgnoringASCIICase(nullptr)); + EXPECT_EQ(static_cast(WTF::notFound), reference->findIgnoringASCIICase(nullptr, 0)); + EXPECT_EQ(static_cast(WTF::notFound), reference->findIgnoringASCIICase(nullptr, 3)); + EXPECT_EQ(static_cast(WTF::notFound), reference->findIgnoringASCIICase(nullptr, 7)); + EXPECT_EQ(static_cast(WTF::notFound), reference->findIgnoringASCIICase(nullptr, 8)); + EXPECT_EQ(static_cast(WTF::notFound), reference->findIgnoringASCIICase(nullptr, 42)); + EXPECT_EQ(static_cast(WTF::notFound), reference->findIgnoringASCIICase(nullptr, std::numeric_limits::max())); +} + +TEST(WTF, StringImplFindIgnoringASCIICaseOnEmpty) +{ + auto reference = stringFromUTF8("ABCÉEFG"); + auto empty = StringImpl::create(reinterpret_cast("")); + EXPECT_EQ(static_cast(0), reference->findIgnoringASCIICase(empty.ptr())); + EXPECT_EQ(static_cast(0), reference->findIgnoringASCIICase(empty.ptr(), 0)); + EXPECT_EQ(static_cast(3), reference->findIgnoringASCIICase(empty.ptr(), 3)); + EXPECT_EQ(static_cast(7), reference->findIgnoringASCIICase(empty.ptr(), 7)); + EXPECT_EQ(static_cast(7), reference->findIgnoringASCIICase(empty.ptr(), 8)); + EXPECT_EQ(static_cast(7), reference->findIgnoringASCIICase(empty.ptr(), 42)); + EXPECT_EQ(static_cast(7), reference->findIgnoringASCIICase(empty.ptr(), std::numeric_limits::max())); +} + +TEST(WTF, StringImplFindIgnoringASCIICaseWithPatternLongerThanReference) +{ + auto reference = stringFromUTF8("ABCÉEFG"); + auto pattern = stringFromUTF8("XABCÉEFG"); + EXPECT_EQ(static_cast(WTF::notFound), reference->findIgnoringASCIICase(pattern.ptr())); + EXPECT_EQ(static_cast(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("")); + ASSERT_FALSE(empty->startsWithIgnoringASCIICase(nullptr)); +} + +TEST(WTF, StringImplStartsWithIgnoringASCIICaseWithEmpty) +{ + auto reference = StringImpl::createFromLiteral("aBcDeFG"); + auto empty = StringImpl::create(reinterpret_cast("")); + 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("")); + ASSERT_FALSE(empty->endsWithIgnoringASCIICase(nullptr)); +} + +TEST(WTF, StringImplEndsWithIgnoringASCIICaseWithEmpty) +{ + auto reference = StringImpl::createFromLiteral("aBcDeFG"); + auto empty = StringImpl::create(reinterpret_cast("")); + 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(0), emptyString.length()); + + UChar ucharArray[] = { 't', 'e', 's', 't', '\0' }; + String concatenation16 = ucharArray + emptyString; + ASSERT_EQ(static_cast(4), concatenation16.length()); + ASSERT_TRUE(concatenation16 == String(ucharArray)); + + LChar lcharArray[] = { 't', 'e', 's', 't', '\0' }; + String concatenation8 = lcharArray + emptyString; + ASSERT_EQ(static_cast(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 +#include + +namespace TestWebKitAPI { + +StringView stringViewFromLiteral(const char* characters) +{ + return StringView(reinterpret_cast(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 expected) +{ + std::vector actual; + for (auto graphemeCluster : graphemeClusters) + actual.push_back(graphemeCluster); + return actual == expected; +} + +bool compareLoopIterations(StringView::CodePoints codePoints, std::vector expected) +{ + std::vector actual; + for (auto codePoint : codePoints) + actual.push_back(codePoint); + return actual == expected; +} + +static bool compareLoopIterations(StringView::CodeUnits codeUnits, std::vector expected) +{ + std::vector actual; + for (auto codeUnit : codeUnits) + actual.push_back(codeUnit); + return actual == expected; +} + +static void build(StringBuilder& builder, std::vector 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 vectorFromSplitResult(const StringView::SplitResult& substrings) +{ + Vector 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 actual = vectorFromSplitResult(a.split('T')); + Vector 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 actual = vectorFromSplitResult(a.split(' ')); + Vector 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 a = StringImpl::createFromLiteral("aBcDeFG"); + RefPtr b = StringImpl::createFromLiteral("ABCDEFG"); + RefPtr c = StringImpl::createFromLiteral("abcdefg"); + const char d[] = "aBcDeFG"; + RefPtr empty = StringImpl::create(reinterpret_cast("")); + RefPtr shorter = StringImpl::createFromLiteral("abcdef"); + RefPtr 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 a = StringImpl::create(reinterpret_cast("")); + RefPtr b = StringImpl::create(reinterpret_cast("")); + StringView stringViewA(*a.get()); + StringView stringViewB(*b.get()); + ASSERT_TRUE(equalIgnoringASCIICase(stringViewA, stringViewB)); + ASSERT_TRUE(equalIgnoringASCIICase(stringViewB, stringViewA)); +} + +TEST(WTF, StringViewEqualIgnoringASCIICaseWithLatin1Characters) +{ + RefPtr a = StringImpl::create(reinterpret_cast("aBcéeFG")); + RefPtr b = StringImpl::create(reinterpret_cast("ABCÉEFG")); + RefPtr c = StringImpl::create(reinterpret_cast("ABCéEFG")); + RefPtr d = StringImpl::create(reinterpret_cast("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(0), referenceA.findIgnoringASCIICase(referenceA)); + EXPECT_EQ(static_cast(0), referenceB.findIgnoringASCIICase(referenceB)); + + // A and B are distinct by the non-ascii character é/É. + EXPECT_EQ(static_cast(notFound), referenceA.findIgnoringASCIICase(referenceB)); + EXPECT_EQ(static_cast(notFound), referenceB.findIgnoringASCIICase(referenceA)); + + String tempStringHolder; + // Find the prefix. + EXPECT_EQ(static_cast(0), referenceA.findIgnoringASCIICase(stringViewFromLiteral("a"))); + EXPECT_EQ(static_cast(0), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "abcé"))); + EXPECT_EQ(static_cast(0), referenceA.findIgnoringASCIICase(stringViewFromLiteral("A"))); + EXPECT_EQ(static_cast(0), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCé"))); + EXPECT_EQ(static_cast(0), referenceB.findIgnoringASCIICase(stringViewFromLiteral("a"))); + EXPECT_EQ(static_cast(0), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "abcÉ"))); + EXPECT_EQ(static_cast(0), referenceB.findIgnoringASCIICase(stringViewFromLiteral("A"))); + EXPECT_EQ(static_cast(0), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCÉ"))); + + // Not a prefix. + EXPECT_EQ(static_cast(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromLiteral("x"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "accé"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "abcÉ"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromLiteral("X"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABDé"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCÉ"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromLiteral("y"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "accÉ"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "abcé"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromLiteral("Y"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABdÉ"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCé"))); + + // Find the infix. + EXPECT_EQ(static_cast(2), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "cée"))); + EXPECT_EQ(static_cast(3), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ée"))); + EXPECT_EQ(static_cast(2), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "cé"))); + EXPECT_EQ(static_cast(2), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "c"))); + EXPECT_EQ(static_cast(3), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "é"))); + EXPECT_EQ(static_cast(2), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "Cée"))); + EXPECT_EQ(static_cast(3), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "éE"))); + EXPECT_EQ(static_cast(2), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "Cé"))); + EXPECT_EQ(static_cast(2), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "C"))); + + EXPECT_EQ(static_cast(2), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "cÉe"))); + EXPECT_EQ(static_cast(3), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "Ée"))); + EXPECT_EQ(static_cast(2), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "cÉ"))); + EXPECT_EQ(static_cast(2), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "c"))); + EXPECT_EQ(static_cast(3), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "É"))); + EXPECT_EQ(static_cast(2), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "CÉe"))); + EXPECT_EQ(static_cast(3), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ÉE"))); + EXPECT_EQ(static_cast(2), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "CÉ"))); + EXPECT_EQ(static_cast(2), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "C"))); + + // Not an infix. + EXPECT_EQ(static_cast(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "céd"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "Ée"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "bé"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "x"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "É"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "CÉe"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "éd"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "CÉ"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "Y"))); + + EXPECT_EQ(static_cast(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "cée"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "Éc"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "cé"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "W"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "é"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "bÉe"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "éE"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "BÉ"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "z"))); + + // Find the suffix. + EXPECT_EQ(static_cast(6), referenceA.findIgnoringASCIICase(stringViewFromLiteral("g"))); + EXPECT_EQ(static_cast(4), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "efg"))); + EXPECT_EQ(static_cast(3), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "éefg"))); + EXPECT_EQ(static_cast(6), referenceA.findIgnoringASCIICase(stringViewFromLiteral("G"))); + EXPECT_EQ(static_cast(4), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "EFG"))); + EXPECT_EQ(static_cast(3), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "éEFG"))); + + EXPECT_EQ(static_cast(6), referenceB.findIgnoringASCIICase(stringViewFromLiteral("g"))); + EXPECT_EQ(static_cast(4), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "efg"))); + EXPECT_EQ(static_cast(3), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "Éefg"))); + EXPECT_EQ(static_cast(6), referenceB.findIgnoringASCIICase(stringViewFromLiteral("G"))); + EXPECT_EQ(static_cast(4), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "EFG"))); + EXPECT_EQ(static_cast(3), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ÉEFG"))); + + // Not a suffix. + EXPECT_EQ(static_cast(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromLiteral("X"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "edg"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "Éefg"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromLiteral("w"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "dFG"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ÉEFG"))); + + EXPECT_EQ(static_cast(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromLiteral("Z"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ffg"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "éefg"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromLiteral("r"))); + EXPECT_EQ(static_cast(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "EgG"))); + EXPECT_EQ(static_cast(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(0), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABC"), 0)); + EXPECT_EQ(static_cast(7), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABC"), 1)); + EXPECT_EQ(static_cast(0), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCÉ"), 0)); + EXPECT_EQ(static_cast(WTF::notFound), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCÉ"), 1)); + EXPECT_EQ(static_cast(7), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCé"), 0)); + EXPECT_EQ(static_cast(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(WTF::notFound), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABC"), 15)); + EXPECT_EQ(static_cast(WTF::notFound), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABC"), 16)); + EXPECT_EQ(static_cast(WTF::notFound), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCÉ"), 17)); + EXPECT_EQ(static_cast(WTF::notFound), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCÉ"), 42)); + EXPECT_EQ(static_cast(WTF::notFound), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCÉ"), std::numeric_limits::max())); +} + +TEST(WTF, StringViewFindIgnoringASCIICaseOnEmpty) +{ + String referenceHolder; + StringView reference = stringViewFromUTF8(referenceHolder, "ABCÉEFG"); + StringView empty = stringViewFromLiteral(""); + EXPECT_EQ(static_cast(0), reference.findIgnoringASCIICase(empty)); + EXPECT_EQ(static_cast(0), reference.findIgnoringASCIICase(empty, 0)); + EXPECT_EQ(static_cast(3), reference.findIgnoringASCIICase(empty, 3)); + EXPECT_EQ(static_cast(7), reference.findIgnoringASCIICase(empty, 7)); + EXPECT_EQ(static_cast(7), reference.findIgnoringASCIICase(empty, 8)); + EXPECT_EQ(static_cast(7), reference.findIgnoringASCIICase(empty, 42)); + EXPECT_EQ(static_cast(7), reference.findIgnoringASCIICase(empty, std::numeric_limits::max())); +} + +TEST(WTF, StringViewFindIgnoringASCIICaseWithPatternLongerThanReference) +{ + String referenceHolder; + StringView reference = stringViewFromUTF8(referenceHolder, "ABCÉEFG"); + String patternHolder; + StringView pattern = stringViewFromUTF8(patternHolder, "ABCÉEFGA"); + + EXPECT_EQ(static_cast(WTF::notFound), reference.findIgnoringASCIICase(pattern)); + EXPECT_EQ(static_cast(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 +#include + +#include +#include +#include +#include +#include + +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 +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 m_lowerQueue; + SynchronizedFixedQueue m_upperQueue; + RefPtr m_produceQueue; + RefPtr 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/TemporaryChange.cpp b/Tools/TestWebKitAPI/Tests/WTF/TemporaryChange.cpp deleted file mode 100644 index 3ba0f15bd..000000000 --- a/Tools/TestWebKitAPI/Tests/WTF/TemporaryChange.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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 - -namespace TestWebKitAPI { - -TEST(WTF, TemporaryChangeNested) -{ - bool originallyFalse = false; - { - TemporaryChange change1OriginallyFalse(originallyFalse, true); - EXPECT_TRUE(originallyFalse); - { - TemporaryChange change2OriginallyFalse(originallyFalse, false); - EXPECT_FALSE(originallyFalse); - } - EXPECT_TRUE(originallyFalse); - } - EXPECT_FALSE(originallyFalse); -} - -} // namespace TestWebKitAPI 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 + +namespace TestWebKitAPI { + +static String makeUTF16(std::vector input) +{ + return { input.data(), static_cast(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 +#include +#include +#include +#include +#include + +namespace WTF { + +std::basic_ostream& operator<<(std::basic_ostream& out, Seconds value) +{ + out << toCString(value).data(); + return out; +} + +std::basic_ostream& operator<<(std::basic_ostream& out, WallTime value) +{ + out << toCString(value).data(); + return out; +} + +std::basic_ostream& operator<<(std::basic_ostream& out, MonotonicTime value) +{ + out << toCString(value).data(); + return out; +} + +std::basic_ostream& operator<<(std::basic_ostream& 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 +#include + +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(WTFMove(a)) + { } + UniqueRef a; +}; +class D : public A { }; + +void function(const UniqueRef a) +{ + const A& b = a.get(); + const A* c = &a; + UNUSED_PARAM(b); + UNUSED_PARAM(c); +} + +TEST(WTF, UniqueRef) +{ + UniqueRef a = makeUniqueRef(); + UniqueRef b = makeUniqueRef(1, 2, 3); + B& c = b.get(); + const B& d = b.get(); + B* e = &b; + const B* f = &b; + UniqueRef j = WTFMove(a); + + Vector> v; + v.append(makeUniqueRef(4, 5, 6)); + v.append(makeUniqueRef(7, 8, 9)); + UniqueRef g = v.takeLast(); + ASSERT_EQ(g->b, 8); + ASSERT_EQ(v.last()->b, 5); + + C h(makeUniqueRef()); + C i(makeUniqueRef()); + + 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 +#include +#include +#include +#include + +namespace TestWebKitAPI { + +TEST(WTF_Variant, Initial) +{ + Variant v1; + EXPECT_TRUE(v1.index() == 0); + EXPECT_TRUE(WTF::get(v1) == 0); + + struct T { + T() : value(15) { } + int value; + }; + + Variant v2; + EXPECT_TRUE(v2.index() == 0); + EXPECT_TRUE(WTF::get(v2).value == 15); +} + +TEST(WTF_Variant, Basic) +{ + Variant variant = 1; + EXPECT_TRUE(variant.index() == 0); + EXPECT_TRUE(WTF::get(variant) == 1); + EXPECT_TRUE(*WTF::get_if(variant) == 1); + EXPECT_TRUE(WTF::get_if(variant) == nullptr); + EXPECT_TRUE(WTF::holds_alternative(variant)); + EXPECT_FALSE(WTF::holds_alternative(variant)); + + variant = 1.0; + EXPECT_TRUE(variant.index() == 1); + EXPECT_TRUE(WTF::get(variant) == 1); + EXPECT_TRUE(*WTF::get_if(variant) == 1.0); + EXPECT_TRUE(WTF::get_if(variant) == nullptr); + EXPECT_TRUE(WTF::holds_alternative(variant)); + EXPECT_FALSE(WTF::holds_alternative(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 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 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 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(); + Variant, 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 ref(&a); + Variant, int> v = ref; + } + + ASSERT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str()); + + { + RefLogger a("a"); + RefPtr ref(&a); + Variant, int> v = WTFMove(ref); + } + + ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); +} + +TEST(WTF_Variant, Ref) +{ + { + RefLogger a("a"); + Ref ref(a); + Variant, 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 +#include namespace TestWebKitAPI { @@ -34,8 +35,8 @@ TEST(WTF_Vector, Basic) { Vector 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 vector; @@ -94,6 +95,103 @@ TEST(WTF_Vector, InitializerList) EXPECT_EQ(4, vector[3]); } +TEST(WTF_Vector, InitializeFromOtherInitialCapacity) +{ + Vector vector = { 1, 3, 2, 4 }; + Vector 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 vector = { 1, 3, 2, 4 }; + Vector 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 vector = { 4, 3, 2, 1 }; + Vector 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 vector = { 4, 3, 2, 1 }; + Vector 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 vector = { 3, 4, 2, 1 }; + Vector 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 vector = { 3, 4, 2, 1 }; + Vector 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 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 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 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, 1>, 1> a; + Vector, 1>, 1> b; + Vector, 1>, 1> c; + + EXPECT_EQ(0U, a.size()); + EXPECT_EQ(0U, b.size()); + EXPECT_EQ(0U, c.size()); + + Vector x; + x.append(42); + + EXPECT_EQ(1U, x.size()); + EXPECT_EQ(42, x[0]); + + Vector, 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 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({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({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::canMoveWithMemcpy, "Should use a memcpy-able type"); + Vector 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({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({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({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({3, 2, 4, 2, 2, 2, 4, 4, 3})); + + // Using a non memcpy-able type. + static_assert(!VectorTraits::canMoveWithMemcpy, "Should use a non memcpy-able type"); + Vector vExpected; + Vector 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 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({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({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({2, 1, 2, 1, 2, 2, 1, 1, 1})); +} + +TEST(WTF_Vector, RemoveAllMatching) +{ + Vector 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({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({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 +#include +#include +#include + +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 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 + +namespace TestWebKitAPI { + +TEST(WTF_WeakPtr, Basic) +{ + int dummy = 5; + WeakPtrFactory* factory = new WeakPtrFactory(&dummy); + WeakPtr weakPtr1 = factory->createWeakPtr(); + WeakPtr weakPtr2 = factory->createWeakPtr(); + WeakPtr 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 weakPtr; + { + WeakPtrFactory 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* factory1 = new WeakPtrFactory(&dummy1); + WeakPtrFactory* factory2 = new WeakPtrFactory(&dummy2); + WeakPtr weakPtr1 = factory1->createWeakPtr(); + WeakPtr 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 factory(&dummy); + WeakPtr weakPtr1 = factory.createWeakPtr(); + WeakPtr weakPtr2 = factory.createWeakPtr(); + WeakPtr 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 factory(nullptr); + WeakPtr weakPtr = factory.createWeakPtr(); + EXPECT_NULL(weakPtr.get()); + factory.revokeAll(); + EXPECT_NULL(weakPtr.get()); +} + +struct Foo { + void bar() { }; +}; + +TEST(WTF_WeakPtr, Dereference) +{ + Foo f; + WeakPtrFactory factory(&f); + WeakPtr weakPtr = factory.createWeakPtr(); + weakPtr->bar(); +} + +TEST(WTF_WeakPtr, Forget) +{ + int dummy = 5; + int dummy2 = 7; + + WeakPtrFactory outerFactory(&dummy2); + WeakPtr weakPtr1, weakPtr2, weakPtr3, weakPtr4; + { + WeakPtrFactory 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 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 weakPtr5 = weakPtr4; + EXPECT_EQ(weakPtr4.get(), &dummy2); + EXPECT_EQ(weakPtr5.get(), &dummy2); + weakPtr5.clear(); + EXPECT_NULL(weakPtr5.get()); + WeakPtr weakPtr6 = weakPtr5; + EXPECT_NULL(weakPtr6.get()); + EXPECT_EQ(weakPtr5.get(), weakPtr6.get()); + + WeakPtr 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 +#include +#include +#include +#include +#include + +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 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(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 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(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 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(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 + +#include +#include + +namespace TestWebKitAPI { + +TEST(OSObjectPtr, AdoptOSObject) +{ + OSObjectPtr 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 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/glib/GUniquePtr.cpp b/Tools/TestWebKitAPI/Tests/WTF/glib/GUniquePtr.cpp new file mode 100644 index 000000000..11f02c7b0 --- /dev/null +++ b/Tools/TestWebKitAPI/Tests/WTF/glib/GUniquePtr.cpp @@ -0,0 +1,195 @@ +/* + * 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 + +inline std::ostringstream& log() +{ + static std::ostringstream log; + return log; +} + +inline std::string takeLogStr() +{ + std::string string = log().str(); + log().str(""); + return string; +} + +static void (* _g_free)(void*) = g_free; +#define g_free(x) \ + log() << "g_free(" << ptr << ");"; \ + _g_free(x); + +static void (* _g_error_free)(GError*) = g_error_free; +#define g_error_free(x) \ + log() << "g_error_free(" << ptr << ");"; \ + _g_error_free(x); + +static void (* _g_list_free)(GList*) = g_list_free; +#define g_list_free(x) \ + log() << "g_list_free(" << ptr << ");"; \ + _g_list_free(x); + +static void (* _g_slist_free)(GSList*) = g_slist_free; +#define g_slist_free(x) \ + log() << "g_slist_free(" << ptr << ");"; \ + _g_slist_free(x); + +static void (* _g_pattern_spec_free)(GPatternSpec*) = g_pattern_spec_free; +#define g_pattern_spec_free(x) \ + log() << "g_pattern_spec_free(" << ptr << ");"; \ + _g_pattern_spec_free(x); + +static void (* _g_dir_close)(GDir*) = g_dir_close; +#define g_dir_close(x) \ + log() << "g_dir_close(" << ptr << ");"; \ + _g_dir_close(x); + +static void (* _g_timer_destroy)(GTimer*) = g_timer_destroy; +#define g_timer_destroy(x) \ + log() << "g_timer_destroy(" << ptr << ");"; \ + _g_timer_destroy(x); + +static void (* _g_key_file_free)(GKeyFile*) = g_key_file_free; +#define g_key_file_free(x) \ + log() << "g_key_file_free(" << ptr << ");"; \ + _g_key_file_free(x); + +#include + +namespace TestWebKitAPI { + +TEST(WTF_GUniquePtr, Basic) +{ + std::ostringstream actual; + + { + GUniquePtr a(g_strdup("a")); + actual << "g_free(" << a.get() << ");"; + } + ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); + actual.str(""); + + { + GUniquePtr a(g_error_new_literal(G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "a")); + actual << "g_error_free(" << a.get() << ");"; + } + ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); + actual.str(""); + + { + GUniquePtr a(g_list_prepend(nullptr, g_strdup("a"))); + actual << "g_list_free(" << a.get() << ");"; + } + ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); + actual.str(""); + + { + GUniquePtr a(g_slist_prepend(nullptr, g_strdup("a"))); + actual << "g_slist_free(" << a.get() << ");"; + } + ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); + actual.str(""); + + { + GUniquePtr a(g_pattern_spec_new("a")); + actual << "g_pattern_spec_free(" << a.get() << ");"; + } + ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); + actual.str(""); + + { + GUniquePtr a(g_dir_open("/tmp", 0, nullptr)); + actual << "g_dir_close(" << a.get() << ");"; + } + ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); + actual.str(""); + + { + GUniquePtr a(g_timer_new()); + actual << "g_timer_destroy(" << a.get() << ");"; + } + ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); + actual.str(""); + + { + GUniquePtr a(g_key_file_new()); + actual << "g_key_file_free(" << a.get() << ");"; + } + ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); + actual.str(""); +} + +static void returnOutChar(char** outChar) +{ + *outChar = g_strdup("a"); +} + +TEST(WTF_GUniquePtr, OutPtr) +{ + std::ostringstream actual; + + { + GUniqueOutPtr a; + ASSERT_EQ(nullptr, a.get()); + } + ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); + actual.str(""); + + { + GUniqueOutPtr a; + returnOutChar(&a.outPtr()); + actual << "g_free(" << a.get() << ");"; + } + ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); + actual.str(""); + + { + GUniqueOutPtr a; + returnOutChar(&a.outPtr()); + actual << "g_free(" << a.get() << ");"; + returnOutChar(&a.outPtr()); + ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); + actual.str(""); + actual << "g_free(" << a.get() << ");"; + } + ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); + actual.str(""); + + { + GUniqueOutPtr a; + returnOutChar(&a.outPtr()); + GUniquePtr b = a.release(); + ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); + actual << "g_free(" << b.get() << ");"; + } + ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); + actual.str(""); +} + +} // 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 +#include +#include +#include +#include +#include +#include + +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 currentDirectory(g_get_current_dir()); + GRefPtr 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(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/WTF/gobject/GUniquePtr.cpp b/Tools/TestWebKitAPI/Tests/WTF/gobject/GUniquePtr.cpp deleted file mode 100644 index 8942f8657..000000000 --- a/Tools/TestWebKitAPI/Tests/WTF/gobject/GUniquePtr.cpp +++ /dev/null @@ -1,195 +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 - -inline std::ostringstream& log() -{ - static std::ostringstream log; - return log; -} - -inline std::string takeLogStr() -{ - std::string string = log().str(); - log().str(""); - return string; -} - -static void (* _g_free)(void*) = g_free; -#define g_free(x) \ - log() << "g_free(" << ptr << ");"; \ - _g_free(x); - -static void (* _g_error_free)(GError*) = g_error_free; -#define g_error_free(x) \ - log() << "g_error_free(" << ptr << ");"; \ - _g_error_free(x); - -static void (* _g_list_free)(GList*) = g_list_free; -#define g_list_free(x) \ - log() << "g_list_free(" << ptr << ");"; \ - _g_list_free(x); - -static void (* _g_slist_free)(GSList*) = g_slist_free; -#define g_slist_free(x) \ - log() << "g_slist_free(" << ptr << ");"; \ - _g_slist_free(x); - -static void (* _g_pattern_spec_free)(GPatternSpec*) = g_pattern_spec_free; -#define g_pattern_spec_free(x) \ - log() << "g_pattern_spec_free(" << ptr << ");"; \ - _g_pattern_spec_free(x); - -static void (* _g_dir_close)(GDir*) = g_dir_close; -#define g_dir_close(x) \ - log() << "g_dir_close(" << ptr << ");"; \ - _g_dir_close(x); - -static void (* _g_timer_destroy)(GTimer*) = g_timer_destroy; -#define g_timer_destroy(x) \ - log() << "g_timer_destroy(" << ptr << ");"; \ - _g_timer_destroy(x); - -static void (* _g_key_file_free)(GKeyFile*) = g_key_file_free; -#define g_key_file_free(x) \ - log() << "g_key_file_free(" << ptr << ");"; \ - _g_key_file_free(x); - -#include - -namespace TestWebKitAPI { - -TEST(WTF_GUniquePtr, Basic) -{ - std::ostringstream actual; - - { - GUniquePtr a(g_strdup("a")); - actual << "g_free(" << a.get() << ");"; - } - ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); - actual.str(""); - - { - GUniquePtr a(g_error_new_literal(G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "a")); - actual << "g_error_free(" << a.get() << ");"; - } - ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); - actual.str(""); - - { - GUniquePtr a(g_list_prepend(nullptr, g_strdup("a"))); - actual << "g_list_free(" << a.get() << ");"; - } - ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); - actual.str(""); - - { - GUniquePtr a(g_slist_prepend(nullptr, g_strdup("a"))); - actual << "g_slist_free(" << a.get() << ");"; - } - ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); - actual.str(""); - - { - GUniquePtr a(g_pattern_spec_new("a")); - actual << "g_pattern_spec_free(" << a.get() << ");"; - } - ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); - actual.str(""); - - { - GUniquePtr a(g_dir_open("/tmp", 0, nullptr)); - actual << "g_dir_close(" << a.get() << ");"; - } - ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); - actual.str(""); - - { - GUniquePtr a(g_timer_new()); - actual << "g_timer_destroy(" << a.get() << ");"; - } - ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); - actual.str(""); - - { - GUniquePtr a(g_key_file_new()); - actual << "g_key_file_free(" << a.get() << ");"; - } - ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); - actual.str(""); -} - -static void returnOutChar(char** outChar) -{ - *outChar = g_strdup("a"); -} - -TEST(WTF_GUniquePtr, OutPtr) -{ - std::ostringstream actual; - - { - GUniqueOutPtr a; - ASSERT_EQ(nullptr, a.get()); - } - ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); - actual.str(""); - - { - GUniqueOutPtr a; - returnOutChar(&a.outPtr()); - actual << "g_free(" << a.get() << ");"; - } - ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); - actual.str(""); - - { - GUniqueOutPtr a; - returnOutChar(&a.outPtr()); - actual << "g_free(" << a.get() << ");"; - returnOutChar(&a.outPtr()); - ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); - actual.str(""); - actual << "g_free(" << a.get() << ");"; - } - ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); - actual.str(""); - - { - GUniqueOutPtr a; - returnOutChar(&a.outPtr()); - GUniquePtr b = a.release(); - ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); - actual << "g_free(" << b.get() << ");"; - } - ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str()); - actual.str(""); -} - -} // 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#if USE(CG) +#include +#endif + +#if PLATFORM(WIN) +#include +#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 +#include + +using namespace WebCore; + +namespace TestWebKitAPI { + +class CARingBufferTest : public testing::Test { +public: + + virtual void SetUp() + { + WTF::initializeMainThread(); + m_ringBuffer = std::make_unique(); + } + + // 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(1, m_description.numberOfChannelStreams())); + m_bufferList = std::unique_ptr(static_cast(::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(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 m_bufferList; + std::unique_ptr 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(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(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 +class MixingTest { +public: + static void run(CARingBufferTest& test) + { + const int sampleCount = 64; + + CAAudioStreamDescription::PCMFormat format; + if (std::is_same::value) + format = CAAudioStreamDescription::PCMFormat::Float32; + else if (std::is_same::value) + format = CAAudioStreamDescription::PCMFormat::Float64; + else if (std::is_same::value) + format = CAAudioStreamDescription::PCMFormat::Int32; + else if (std::is_same::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(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(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::run(*this); +} + +TEST_F(CARingBufferTest, DoubleMixing) +{ + MixingTest::run(*this); +} + +TEST_F(CARingBufferTest, Int32Mixing) +{ + MixingTest::run(*this); +} + +TEST_F(CARingBufferTest, Int16Mixing) +{ + MixingTest::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 +#include +#include + +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 value = properties->getPropertyCSSValue(testCase.propertyID); + + ASSERT_TRUE(value->isValueList()); + EXPECT_EQ(computeNumberOfTracks(*downcast(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 + +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 createTestValue() +{ + auto node = std::make_unique(); + return WebCore::CalculationValue::create(WTFMove(node), WebCore::ValueRangeAll); +} + +TEST(CalculationValue, LengthConstruction) +{ + RefPtr 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 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 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 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 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 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 + +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 +#include +#include +#include +#include + +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 advances = { FloatSize(), FloatSize(21.640625, 0.0), FloatSize(42.3046875, 0.0), FloatSize(55.8984375, 0.0), FloatSize(22.34375, 0.0) }; + Vector origins = { FloatPoint(-15.15625, 18.046875), FloatPoint(), FloatPoint(), FloatPoint(), FloatPoint() }; +#else + Vector 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 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> 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 advances = { FloatSize(), FloatSize(21.640625, 0.0), FloatSize(42.3046875, 0.0), FloatSize(55.8984375, 0.0), FloatSize(22.34375, 0.0) }; + Vector origins = { FloatPoint(-15.15625, 18.046875), FloatPoint(), FloatPoint(), FloatPoint(), FloatPoint() }; +#else + Vector 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 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> 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 advances = { FloatSize(76.347656, 0.000000), FloatSize(0.000000, 0.000000) }; + Vector origins = { FloatPoint(), FloatPoint(-23.281250, -8.398438) }; +#else + Vector advances = { FloatSize(53.066406, -8.398438), FloatSize(23.281250, 8.398438) }; + Vector 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> 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 advances = { FloatSize(76.347656, 0.000000), FloatSize(0.000000, 0.000000) }; + Vector origins = { FloatPoint(), FloatPoint(-23.281250, -8.398438) }; +#else + Vector advances = { FloatSize(53.066406, -8.398438), FloatSize(23.281250, 8.398438) }; + Vector 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> 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> 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> 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> 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 advances = { FloatSize(1, 0), FloatSize(2, 0), FloatSize(4, 0), FloatSize(8, 0), FloatSize(16, 0) }; +#if USE_LAYOUT_SPECIFIC_ADVANCES + Vector origins = { FloatPoint(), FloatPoint(), FloatPoint(), FloatPoint(), FloatPoint() }; +#else + Vector 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> 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 actions; + Vector filtersWithoutDomains; + Vector filtersWithDomains; + Vector 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&& 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&& 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&& bytecode) override + { + EXPECT_FALSE(finalized); + EXPECT_EQ(m_data.domainFilters.size(), 0ull); + m_data.filtersWithDomains.appendVector(bytecode); + } + + void writeDomainFiltersBytecode(Vector&& 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 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 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 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 createNFAs(ContentExtensions::CombinedURLFilters& combinedURLFilters) +{ + Vector nfas; + + combinedURLFilters.processNFAs(std::numeric_limits::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& 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 nfas = createNFAs(combinedURLFilters); + EXPECT_EQ(1ul, nfas.size()); + EXPECT_EQ(12ul, nfas.first().nodes.size()); + + ContentExtensions::DFA dfa = ContentExtensions::NFAToDFA::convert(nfas.first()); + Vector 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 nfas = createNFAs(combinedURLFilters); + + EXPECT_EQ(1ul, nfas.size()); + EXPECT_EQ(17ul, nfas.first().nodes.size()); + + ContentExtensions::DFA dfa = ContentExtensions::NFAToDFA::convert(nfas.first()); + Vector 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 nfas = createNFAs(combinedURLFilters); + EXPECT_EQ(1ul, nfas.size()); + EXPECT_EQ(7ul, nfas.first().nodes.size()); + + ContentExtensions::DFA dfa = ContentExtensions::NFAToDFA::convert(nfas.first()); + Vector 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 nfas; + combinedURLFilters.processNFAs(std::numeric_limits::max(), [&](ContentExtensions::NFA&& nfa) { + nfas.append(WTFMove(nfa)); + }); + EXPECT_EQ(nfas.size(), 1ull); + + Vector dfas; + for (auto& nfa : nfas) + dfas.append(ContentExtensions::NFAToDFA::convert(nfa)); + EXPECT_EQ(dfas.size(), 1ull); + + Vector combinedBytecode; + for (const auto& dfa : dfas) { + Vector 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 nfas; + combinedURLFilters.processNFAs(i, [&](ContentExtensions::NFA&& nfa) { + nfas.append(WTFMove(nfa)); + }); + EXPECT_EQ(nfas.size(), expectedNFACounts[i]); + + Vector dfas; + for (auto& nfa : nfas) + dfas.append(ContentExtensions::NFAToDFA::convert(nfa)); + + Vector combinedBytecode; + for (const auto& dfa : dfas) { + Vector 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 +#include + +using namespace WebCore; +using namespace ContentExtensions; + +namespace TestWebKitAPI { + +class DFACombinerTest : public testing::Test { +public: + virtual void SetUp() + { + WTF::initializeMainThread(); + } +}; + +Vector combine(Vector dfas, unsigned minimumSize) +{ + DFACombiner combiner; + for (DFA& dfa : dfas) + combiner.addDFA(WTFMove(dfa)); + + Vector output; + combiner.combineDFAs(minimumSize, [&output](DFA&& dfa) { + output.append(dfa); + }); + return output; +} + +TEST_F(DFACombinerTest, Basic) +{ + Vector dfas = { buildDFAFromPatterns({ "foo"}), buildDFAFromPatterns({ "bar"}) }; + Vector combinedDFAs = combine(dfas, 10000); + EXPECT_EQ(static_cast(1), combinedDFAs.size()); + + DFA reference = buildDFAFromPatterns({ "foo", "bar"}); + reference.minimize(); + EXPECT_EQ(countLiveNodes(reference), countLiveNodes(combinedDFAs.first())); +} + + +TEST_F(DFACombinerTest, IdenticalDFAs) +{ + Vector dfas = { buildDFAFromPatterns({ "foo"}), buildDFAFromPatterns({ "foo"}) }; + Vector combinedDFAs = combine(dfas, 10000); + EXPECT_EQ(static_cast(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(0), counter); +} + +TEST_F(DFACombinerTest, SingleInput) +{ + Vector dfas = { buildDFAFromPatterns({ "WebKit"}) }; + Vector combinedDFAs = combine(dfas, 10000); + EXPECT_EQ(static_cast(1), combinedDFAs.size()); + + DFA reference = buildDFAFromPatterns({ "WebKit"}); + reference.minimize(); + EXPECT_EQ(countLiveNodes(reference), countLiveNodes(combinedDFAs.first())); +} + +TEST_F(DFACombinerTest, InputTooLargeForMinimumSize) +{ + Vector dfas = { buildDFAFromPatterns({ "foo"}), buildDFAFromPatterns({ "bar"}) }; + Vector combinedDFAs = combine(dfas, 2); + EXPECT_EQ(static_cast(2), combinedDFAs.size()); + EXPECT_EQ(static_cast(4), countLiveNodes(combinedDFAs[0])); + EXPECT_EQ(static_cast(4), countLiveNodes(combinedDFAs[1])); +} + +TEST_F(DFACombinerTest, CombinedInputReachesMinimumSize) +{ + Vector dfas = { buildDFAFromPatterns({ "foo"}), buildDFAFromPatterns({ "bar"}), buildDFAFromPatterns({ "WebKit"}) }; + Vector combinedDFAs = combine(dfas, 5); + EXPECT_EQ(static_cast(2), combinedDFAs.size()); + EXPECT_EQ(static_cast(7), countLiveNodes(combinedDFAs[0])); + EXPECT_EQ(static_cast(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 +#include +#include +#include + +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 createNFAs(ContentExtensions::CombinedURLFilters& combinedURLFilters) +{ + Vector nfas; + + combinedURLFilters.processNFAs(std::numeric_limits::max(), [&](ContentExtensions::NFA&& nfa) { + nfas.append(WTFMove(nfa)); + }); + + return nfas; +} + +static ContentExtensions::DFA buildDFAFromPatterns(Vector patterns) +{ + ContentExtensions::CombinedURLFilters combinedURLFilters; + ContentExtensions::URLFilterParser parser(combinedURLFilters); + + for (const char* pattern : patterns) + parser.addPattern(pattern, false, 0); + Vector 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 + +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(8), countLiveNodes(dfa)); + dfa.minimize(); + EXPECT_EQ(static_cast(7), countLiveNodes(dfa)); +} + +TEST_F(DFAMinimizerTest, MergeSuffixes) +{ + ContentExtensions::DFA dfa = buildDFAFromPatterns({ ".*aaa", ".*aab", ".*aba", ".*abb", ".*baa", ".*bab", ".*bba", ".*bbb"}); + EXPECT_EQ(static_cast(12), countLiveNodes(dfa)); + dfa.minimize(); + EXPECT_EQ(static_cast(4), countLiveNodes(dfa)); +} + +TEST_F(DFAMinimizerTest, MergeInfixes) +{ + ContentExtensions::DFA dfa = buildDFAFromPatterns({ ".*aaakit", ".*aabkit", ".*abakit", ".*abbkit", ".*baakit", ".*babkit", ".*bbakit", ".*bbbkit"}); + EXPECT_EQ(static_cast(15), countLiveNodes(dfa)); + dfa.minimize(); + EXPECT_EQ(static_cast(7), countLiveNodes(dfa)); +} + +TEST_F(DFAMinimizerTest, FallbackTransitionsWithDifferentiatorDoNotMerge1) +{ + ContentExtensions::DFA dfa = buildDFAFromPatterns({ "^a.a", "^b.a", "^bac", "^bbc", "^BCC"}); + EXPECT_EQ(static_cast(6), countLiveNodes(dfa)); + dfa.minimize(); + EXPECT_EQ(static_cast(6), countLiveNodes(dfa)); +} + +TEST_F(DFAMinimizerTest, FallbackTransitionsWithDifferentiatorDoNotMerge2) +{ + ContentExtensions::DFA dfa = buildDFAFromPatterns({ "^bbc", "^BCC", "^a.a", "^b.a"}); + EXPECT_EQ(static_cast(6), countLiveNodes(dfa)); + dfa.minimize(); + EXPECT_EQ(static_cast(6), countLiveNodes(dfa)); +} + +TEST_F(DFAMinimizerTest, FallbackTransitionsWithDifferentiatorDoNotMerge3) +{ + ContentExtensions::DFA dfa = buildDFAFromPatterns({ "^a.c", "^b.c", "^baa", "^bba", "^BCA"}); + EXPECT_EQ(static_cast(6), countLiveNodes(dfa)); + dfa.minimize(); + EXPECT_EQ(static_cast(6), countLiveNodes(dfa)); +} + +TEST_F(DFAMinimizerTest, FallbackTransitionsWithDifferentiatorDoNotMerge4) +{ + ContentExtensions::DFA dfa = buildDFAFromPatterns({ "^baa", "^bba", "^BCA", "^a.c", "^b.c"}); + EXPECT_EQ(static_cast(6), countLiveNodes(dfa)); + dfa.minimize(); + EXPECT_EQ(static_cast(6), countLiveNodes(dfa)); +} + +TEST_F(DFAMinimizerTest, FallbackTransitionsToOtherNodeInSameGroupDoesNotDifferentiateGroup) +{ + ContentExtensions::DFA dfa = buildDFAFromPatterns({ "^aac", "^a.c", "^b.c"}); + EXPECT_EQ(static_cast(5), countLiveNodes(dfa)); + dfa.minimize(); + EXPECT_EQ(static_cast(4), countLiveNodes(dfa)); +} + +TEST_F(DFAMinimizerTest, SimpleFallBackTransitionDifferentiator1) +{ + ContentExtensions::DFA dfa = buildDFAFromPatterns({ "^a.bc.de", "^a.bd.ef"}); + EXPECT_EQ(static_cast(11), countLiveNodes(dfa)); + dfa.minimize(); + EXPECT_EQ(static_cast(11), countLiveNodes(dfa)); +} + +TEST_F(DFAMinimizerTest, SimpleFallBackTransitionDifferentiator2) +{ + ContentExtensions::DFA dfa = buildDFAFromPatterns({ "^cb.", "^db.b"}); + EXPECT_EQ(static_cast(7), countLiveNodes(dfa)); + dfa.minimize(); + EXPECT_EQ(static_cast(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 + +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 +#include +#include + +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(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 +#include +#include +#include +#include +#include + +#if USE(CG) +#include +#endif + +#if PLATFORM(WIN) +#include +#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 +#include +#include +#include + +#if USE(CG) +#include +#endif + +#if PLATFORM(WIN) +#include +#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::max() / 2, infinite.x()); + EXPECT_FLOAT_EQ(-std::numeric_limits::max() / 2, infinite.y()); + EXPECT_FLOAT_EQ(std::numeric_limits::max(), infinite.width()); + EXPECT_FLOAT_EQ(std::numeric_limits::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::max() / 2, cgInfiniteRect.origin.x); + EXPECT_FLOAT_EQ(-std::numeric_limits::max() / 2, cgInfiniteRect.origin.y); + EXPECT_FLOAT_EQ(std::numeric_limits::max(), cgInfiniteRect.size.width); + EXPECT_FLOAT_EQ(std::numeric_limits::max(), cgInfiniteRect.size.height); +#else + EXPECT_FLOAT_EQ(-std::numeric_limits::max(), cgInfiniteRect.origin.x); + EXPECT_FLOAT_EQ(-std::numeric_limits::max(), cgInfiniteRect.origin.y); + EXPECT_FLOAT_EQ(std::numeric_limits::max(), cgInfiniteRect.origin.x + cgInfiniteRect.size.width); + EXPECT_FLOAT_EQ(std::numeric_limits::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::max(), d2dInfiniteRect.left); + EXPECT_FLOAT_EQ(-std::numeric_limits::max(), d2dInfiniteRect.top); + EXPECT_FLOAT_EQ(std::numeric_limits::max(), d2dInfiniteRect.right); + EXPECT_FLOAT_EQ(std::numeric_limits::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 +#include +#include + +#if USE(CG) +#include +#endif + +#if PLATFORM(WIN) +#include +#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 + +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 +#include + +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 +#include +#include + +#if USE(CG) +#include +#endif + +#if PLATFORM(WIN) +#include +#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 +#include +#include +#include + +#if USE(CG) +#include +#endif + +#if PLATFORM(WIN) +#include +#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 +#include + +#if USE(CG) +#include +#endif + +#if PLATFORM(WIN) +#include +#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 @@ -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 +#include + +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 +#include + +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 +#include + +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 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> divide(const MediaTime& presentationTime) final { return { }; } + Ref createNonDisplayingCopy() const final { + return create(m_presentationTime, m_decodeTime, m_duration, static_cast(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 +#include +#include +#include + +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 o1 = SecurityOrigin::create("http", "example.com", std::optional(80)); + Ref o2 = SecurityOrigin::create("http", "example.com", std::optional()); + Ref o3 = SecurityOrigin::createFromString("http://example.com"); + Ref o4 = SecurityOrigin::createFromString("http://example.com:80"); + Ref o5 = SecurityOrigin::create(URL(URL(), "http://example.com")); + Ref 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 +#include +#include + +using namespace WebCore; + +namespace TestWebKitAPI { + +TEST_F(SharedBufferTest, createWithContentsOfMissingFile) +{ + RefPtr buffer = SharedBuffer::createWithContentsOfFile(String("not_existing_file")); + ASSERT_NULL(buffer); +} + +TEST_F(SharedBufferTest, createWithContentsOfExistingFile) +{ + RefPtr 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 buffer = SharedBuffer::createWithContentsOfFile(tempEmptyFilePath()); + ASSERT_NOT_NULL(buffer); + EXPECT_TRUE(buffer->isEmpty()); +} + +TEST_F(SharedBufferTest, copyBufferCreatedWithContentsOfExistingFile) +{ + RefPtr buffer = SharedBuffer::createWithContentsOfFile(tempFilePath()); + ASSERT_NOT_NULL(buffer); + RefPtr 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 buffer = SharedBuffer::createWithContentsOfFile(tempFilePath()); + ASSERT_NOT_NULL(buffer); + buffer->clear(); + EXPECT_TRUE(!buffer->size()); + EXPECT_TRUE(!buffer->data()); +} + +TEST_F(SharedBufferTest, appendBufferCreatedWithContentsOfExistingFile) +{ + RefPtr 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::create(testData0, strlen(testData0)); + sharedBuffer->append(testData1, strlen(testData1)); + sharedBuffer->append(testData2, strlen(testData2)); + RefPtr 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 vector0(0x4000, 'a'); + Vector vector1(0x4000, 'b'); + Vector vector2(0x4000, 'c'); + + RefPtr sharedBuffer = SharedBuffer::adoptVector(vector0); + sharedBuffer->append(vector1); + sharedBuffer->append(vector2); + RefPtr 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(arrayBuffer->data())[position]); + ++position; + } + for (int i = 0; i < 0x4000; ++i) { + EXPECT_EQ('b', static_cast(arrayBuffer->data())[position]); + ++position; + } + for (int i = 0; i < 0x4000; ++i) { + EXPECT_EQ('c', static_cast(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::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 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 +#include + +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 + +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 + +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 rangeA = TimeRanges::create(); + RefPtr 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 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 ranges = TimeRanges::create(0, 2); + + ASSERT_RANGE("{ [0,2) }", ranges); + + ranges->intersectWith(*ranges.get()); + + ASSERT_RANGE("{ [0,2) }", ranges); +} + +TEST(TimeRanges, IntersectWith_IdenticalRange) +{ + RefPtr rangesA = TimeRanges::create(0, 2); + RefPtr 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 rangesA = TimeRanges::create(0, 2); + RefPtr 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 rangesA = TimeRanges::create(); + RefPtr 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 rangesA = TimeRanges::create(); + RefPtr 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 rangesA = TimeRanges::create(); + RefPtr 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 rangesA = TimeRanges::create(); + RefPtr 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 rangesA = TimeRanges::create(); + RefPtr 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 rangesA = TimeRanges::create(); + RefPtr 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 rangesA = TimeRanges::create(); + RefPtr 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 +#include +#include +#include +#include +#include +#include + +#if USE(CG) +#include +#endif + +#if USE(CA) +#include +#endif + +#if PLATFORM(WIN) +#include +#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 +#include #include 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 +#include +#include + +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({'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 +#include + +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 +#include +#include + +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 -#include - -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 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 Binary files /dev/null and b/Tools/TestWebKitAPI/Tests/WebKit2/Ahem.ttf 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 +#include 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 +#include 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 + +namespace TestWebKitAPI { + +static bool testDone; +static std::unique_ptr 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(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 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 preferences(AdoptWK, WKPreferencesCreate()); + WKPageGroupRef pageGroup = WKPageGetPageGroup(webView.page()); + WKPreferencesSetUniversalAccessFromFileURLsAllowed(preferences.get(), true); + WKPageGroupSetPreferences(pageGroup, preferences.get()); + + WKRetainPtr 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 -#include +#include +#include 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 +#include +#include +#include + +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 context = adoptWK(WKContextCreate()); + WKRetainPtr 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 context = adoptWK(Util::createContextForInjectedBundleTest("WKViewIsActiveSetIsActiveTest")); + WKRetainPtr 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 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 + +#include + +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 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 +#include +#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 context(AdoptWK, WKContextCreate()); + PlatformWebView webView(context.get()); + WKRetainPtr 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 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 context(AdoptWK, WKContextCreate()); + WKRetainPtr configuration(AdoptWK, WKPageConfigurationCreate()); + WKPageConfigurationSetContext(configuration.get(), context.get()); + + WKRetainPtr 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 @@ + + +
+ + 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 @@ + 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 +#include #include 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 -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -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 -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -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 -#include +#include +#include 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 registrar("DidAssociateFormControlsTest"); @@ -54,7 +57,7 @@ static void didAssociateFormControls(WKBundlePageRef page, WKArrayRef elementHan WKRetainPtr 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 +#include 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 + +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 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 + +namespace TestWebKitAPI { + +class DidRemoveFrameFromHiearchyInPageCacheTest : public InjectedBundleTest { +public: + DidRemoveFrameFromHiearchyInPageCacheTest(const std::string& identifier); + + virtual void didCreatePage(WKBundleRef, WKBundlePageRef); +}; + +static InjectedBundleTest::Register registrar("DidRemoveFrameFromHiearchyInPageCache"); + +static unsigned didRemoveFrameFromHierarchyCount; + +void didRemoveFrameFromHierarchyCallback(WKBundlePageRef page, WKBundleFrameRef, WKTypeRef*, const void*) +{ + didRemoveFrameFromHierarchyCount++; + + WKRetainPtr 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 +#include 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 -#include -#include -#include +#include +#include +#include +#include #include namespace TestWebKitAPI { @@ -53,3 +56,5 @@ public: static InjectedBundleTest::Register 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 +#include 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 +#include +#include +#include +#include +#include + +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 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 +#include + +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 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 -#include +#include +#include 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 context = adoptWK(WKContextCreate()); + + PlatformWebView webView(context.get()); + setClients(webView.page()); + + WKRetainPtr 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 +#include 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 +#include 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 +#include 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 +#include +#include + +namespace TestWebKitAPI { + +static bool done; + +static void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo) +{ + done = true; +} + +TEST(WebKit2, FrameHandle) +{ + WKRetainPtr 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 +#include 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 +#include 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 +#include +#include #include #include @@ -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 context(AdoptWK, WKContextCreate()); + WKContextSetMaximumNumberOfProcesses(context.get(), 1); GeolocationTransitionToHighAccuracyStateTracker stateTracker; setupGeolocationProvider(context.get(), &stateTracker); @@ -257,19 +265,20 @@ TEST(WebKit2, GeolocationTransitionToHighAccuracy) setupView(highAccuracyWebView); WKRetainPtr highAccuracyURL(AdoptWK, Util::createURLForResource("geolocationWatchPositionWithHighAccuracy", "html")); WKPageLoadURL(highAccuracyWebView.page(), highAccuracyURL.get()); + Util::run(&stateTracker.enabledHighAccuracy); + + WKRetainPtr 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 context(AdoptWK, WKContextCreate()); + WKContextSetMaximumNumberOfProcesses(context.get(), 1); GeolocationTransitionToLowAccuracyStateTracker stateTracker; setupGeolocationProvider(context.get(), &stateTracker); @@ -331,7 +346,11 @@ TEST(WebKit2, GeolocationTransitionToLowAccuracy) WKRetainPtr 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 +#include 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 +#include namespace TestWebKitAPI { @@ -46,3 +49,5 @@ public: static InjectedBundleTest::Register 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 +#include 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 -#include -#include +#include +#include +#include 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 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 +#include 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 +#include namespace TestWebKitAPI { @@ -47,3 +50,5 @@ public: static InjectedBundleTest::Register 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 +#include 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 -#include -#include -#include -#include +#include +#include +#include +#include +#include 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 +#include 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 +#include namespace TestWebKitAPI { @@ -46,3 +49,5 @@ public: static InjectedBundleTest::Register 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 + +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 pageGroup(AdoptWK, WKPageGroupCreateWithIdentifier(WKStringCreateWithUTF8CString("InjectedBundleMakeAllShadowRootOpenTestPageGroup"))); + + WKRetainPtr 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 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 +#include +#include +#include +#include + +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(userData); + + auto world = WKBundleScriptWorldCreateWorld(); + WKBundleScriptWorldMakeAllShadowRootsOpen(world); + + WKRetainPtr 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 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 -#include +#include +#include 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 + +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 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 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 -#include -#include +#include +#include +#include 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 context(AdoptWK, WKContextCreate()); PlatformWebView webView(context.get()); @@ -53,14 +57,29 @@ TEST(WebKit2, LoadAlternateHTMLStringWithNonDirectoryURL) loaderClient.didFinishLoadForFrame = didFinishLoadForFrame; WKPageSetPageLoaderClient(webView.page(), &loaderClient.base); - WKRetainPtr fileURL(AdoptWK, Util::createURLForResource("simple", "html")); WKRetainPtr alternateHTMLString(AdoptWK, WKStringCreateWithUTF8CString("")); - - // 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 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 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 -#include -#include +#include +#include +#include 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 -#include -#include +#include +#include +#include #include @@ -70,3 +73,5 @@ public: static InjectedBundleTest::Register 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 +#include 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 context(AdoptWK, WKContextCreate()); + PlatformWebView webView(context.get()); + setPageLoaderClient(webView.page()); + + WKRetainPtr 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 +#include +#include + +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 url = adoptWK(WKFrameCopyURL(frame)); + WKRetainPtr urlString = adoptWK(WKURLCopyString(url.get())); + EXPECT_WK_STREQ("about:blank", urlString.get()); + + WKRetainPtr protocol = adoptWK(WKSecurityOriginCopyProtocol(securityOrigin)); + EXPECT_WK_STREQ("file", protocol.get()); + + WKRetainPtr 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 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(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 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 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 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 +#include 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 -#include +#include +#include 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 -#include +#include +#include namespace TestWebKitAPI { @@ -49,3 +52,5 @@ public: static InjectedBundleTest::Register 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 +#include 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 -#include +#include +#include namespace TestWebKitAPI { @@ -49,3 +52,5 @@ public: static InjectedBundleTest::Register 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 -#include +#include +#include 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 -#include +#include +#include namespace TestWebKitAPI { @@ -49,3 +52,5 @@ public: static InjectedBundleTest::Register 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 -#include +#include +#include namespace TestWebKitAPI { @@ -49,3 +52,5 @@ public: static InjectedBundleTest::Register 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 + +#if WK_HAVE_C_SPI + +#import "PlatformUtilities.h" +#import "PlatformWebView.h" +#import "Test.h" +#import +#import +#import + +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 +#include namespace TestWebKitAPI { @@ -151,4 +154,26 @@ TEST(WebKit2, PageLoadBasic) Util::run(&test1Done); } +TEST(WebKit2, PageReload) +{ + WKRetainPtr context(AdoptWK, WKContextCreate()); + PlatformWebView webView(context.get()); + + // Reload test before url loading. + WKPageReload(webView.page()); + WKPageReload(webView.page()); + + WKRetainPtr url(AdoptWK, Util::createURLForResource("simple", "html")); + WKPageLoadURL(webView.page(), url.get()); + + // Reload test after url loading. + WKPageReload(webView.page()); + + WKRetainPtr 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 +#include 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 +#include 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 -#include -#include +#include +#include +#include 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 +#include +#include +#include + +namespace TestWebKitAPI { + +class PasteboardNotificationsTest : public InjectedBundleTest { +public: + PasteboardNotificationsTest(const std::string& identifier); + + virtual void didCreatePage(WKBundleRef, WKBundlePageRef); +}; + +static InjectedBundleTest::Register 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 + +namespace TestWebKitAPI { + +static bool done; + +TEST(WebKit2, PendingAPIRequestURL) +{ + WKRetainPtr 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 activeURL = adoptWK(WKPageCopyActiveURL(webView.page())); + EXPECT_NULL(activeURL.get()); + + WKRetainPtr 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 htmlString = Util::toWK("Hello, World"); + WKRetainPtr 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 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 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 -#include -#include +#include +#include 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 +#include 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 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 +#include +#include + +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 committedURL = adoptWK(WKFrameCopyURL(frame)); + ASSERT_NOT_NULL(committedURL.get()); + WKRetainPtr 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(userData))); + + WKRetainPtr url(AdoptWK, Util::createURLForResource("simple2", "html")); + EXPECT_TRUE(WKURLIsEqual(committedURL.get(), url.get())); + + committedLoad = true; +} + +TEST(WebKit2, ProvisionalURLAfterWillSendRequestCallback) +{ + WKRetainPtr 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 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 +#include +#include + +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 newRequest = request; + return newRequest.leakRef(); + } + + // Change the main frame URL. + WKRetainPtr 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 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 +#include 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 -#include -#include -#include +#include +#include +#include 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 +#include 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 namespace TestWebKitAPI { @@ -49,7 +53,7 @@ static void setPageLoaderClient(WKPageRef page) WKPageSetPageLoaderClient(page, &loaderClient.base); } -static WKRetainPtr createSessionStateContainingFormData(WKContextRef context) +static WKRetainPtr createSessionStateDataContainingFormData(WKContextRef context) { PlatformWebView webView(context); setPageLoaderClient(webView.page()); @@ -62,7 +66,8 @@ static WKRetainPtr createSessionStateContainingFormData(WKContextRef Util::run(&didFinishLoad); didFinishLoad = false; - return adoptWK(WKPageCopySessionState(webView.page(), 0, 0)); + auto sessionState = adoptWK(static_cast(WKPageCopySessionState(webView.page(), reinterpret_cast(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 data = createSessionStateContainingFormData(context.get()); + WKRetainPtr 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 +#include + +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 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(WKPageCopySessionState(webView.page(), reinterpret_cast(1), nullptr))); + return adoptWK(WKSessionStateCopyData(sessionState.get())); +} + +TEST(WebKit2, RestoreSessionStateWithoutNavigation) +{ + WKRetainPtr context(AdoptWK, WKContextCreate()); + + PlatformWebView webView(context.get()); + setPageLoaderClient(webView.page()); + + WKRetainPtr data = createSessionStateData(context.get()); + EXPECT_NOT_NULL(data); + + auto sessionState = adoptWK(WKSessionStateCreateFromData(data.get())); + WKPageRestoreFromSessionStateWithoutNavigation(webView.page(), sessionState.get()); + + Util::run(&didChangeBackForwardList); + + WKRetainPtr 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 -#include -#include -#include -#include +#include +#include +#include +#include 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 +#include 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 -#include +#include +#include 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 url = adoptWK(WKBackForwardListItemCopyURL(item)); + WKRetainPtr 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 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 -#include +#include +#include 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 + +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 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 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 +#include +#include +#include + +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 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 + +namespace TestWebKitAPI { + +struct WebKit2TextFieldBeginAndEditEditingTest : public ::testing::Test { + std::unique_ptr webView; + + WKRetainPtr messageName; + + bool didFinishLoad { false }; + bool didReceiveMessage { false }; + + static void didReceiveMessageFromInjectedBundle(WKContextRef, WKStringRef messageName, WKTypeRef, const void* clientInfo) + { + WebKit2TextFieldBeginAndEditEditingTest& client = *static_cast(const_cast(clientInfo)); + client.messageName = messageName; + client.didReceiveMessage = true; + } + + static void didFinishLoadForFrame(WKPageRef, WKFrameRef, WKTypeRef, const void* clientInfo) + { + WebKit2TextFieldBeginAndEditEditingTest& client = *static_cast(const_cast(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 context = adoptWK(Util::createContextForInjectedBundleTest("TextFieldDidBeginAndEndEditingEventsTest")); + setInjectedBundleClient(context.get(), this); + + webView = std::make_unique(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 + +namespace TestWebKitAPI { + +class TextFieldDidBeginAndEndEditingEventsTest : public InjectedBundleTest { +public: + TextFieldDidBeginAndEndEditingEventsTest(const std::string& identifier); + + virtual void didCreatePage(WKBundleRef, WKBundlePageRef); +}; + +static InjectedBundleTest::Register 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 +#include +#include + +namespace TestWebKitAPI { + +static bool done; + +void decidePolicyForUserMediaPermissionRequestCallBack(WKPageRef, WKFrameRef, WKSecurityOriginRef, WKSecurityOriginRef, WKUserMediaPermissionRequestRef permissionRequest, const void* /* clientInfo */) +{ + WKRetainPtr audioDeviceUIDs = WKUserMediaPermissionRequestAudioDeviceUIDs(permissionRequest); + WKRetainPtr videoDeviceUIDs = WKUserMediaPermissionRequestVideoDeviceUIDs(permissionRequest); + + if (WKArrayGetSize(videoDeviceUIDs.get()) || WKArrayGetSize(audioDeviceUIDs.get())) { + WKRetainPtr videoDeviceUID; + if (WKArrayGetSize(videoDeviceUIDs.get())) + videoDeviceUID = reinterpret_cast(WKArrayGetItemAtIndex(videoDeviceUIDs.get(), 0)); + else + videoDeviceUID = WKStringCreateWithUTF8CString(""); + + WKRetainPtr audioDeviceUID; + if (WKArrayGetSize(audioDeviceUIDs.get())) + audioDeviceUID = reinterpret_cast(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 -#include namespace TestWebKitAPI { @@ -42,7 +43,7 @@ public: } WKRetainPtr context; - OwnPtr webView; + std::unique_ptr webView; WKRetainPtr 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(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 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 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 +#include +#include +#include + +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 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 + +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 + +namespace TestWebKitAPI { + +TEST(WebKit2, WKPageConfigurationEmpty) +{ + WKRetainPtr 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 configuration = adoptWK(WKPageConfigurationCreate()); + WKRetainPtr context = adoptWK(WKContextCreate()); + WKPageConfigurationSetContext(configuration.get(), context.get()); + + PlatformWebView webView(configuration.get()); + setPageLoaderClient(webView.page()); + + WKRetainPtr copiedConfiguration = adoptWK(WKPageCopyPageConfiguration(webView.page())); + ASSERT_EQ(context.get(), WKPageConfigurationGetContext(copiedConfiguration.get())); + + WKRetainPtr url = adoptWK(Util::createURLForResource("simple", "html")); + WKPageLoadURL(webView.page(), url.get()); + + didFinishLoad = false; + Util::run(&didFinishLoad); +} + +TEST(WebKit2, WKPageConfigurationBasicWithDataStore) +{ + WKRetainPtr configuration = adoptWK(WKPageConfigurationCreate()); + WKRetainPtr context = adoptWK(WKContextCreate()); + WKPageConfigurationSetContext(configuration.get(), context.get()); + WKRetainPtr websiteDataStore = WKWebsiteDataStoreGetDefaultDataStore(); + WKPageConfigurationSetWebsiteDataStore(configuration.get(), websiteDataStore.get()); + + PlatformWebView webView(configuration.get()); + setPageLoaderClient(webView.page()); + + WKRetainPtr copiedConfiguration = adoptWK(WKPageCopyPageConfiguration(webView.page())); + ASSERT_EQ(context.get(), WKPageConfigurationGetContext(copiedConfiguration.get())); + ASSERT_EQ(WKWebsiteDataStoreGetDefaultDataStore(), WKPageConfigurationGetWebsiteDataStore(copiedConfiguration.get())); + + WKRetainPtr url = adoptWK(Util::createURLForResource("simple", "html")); + WKPageLoadURL(webView.page(), url.get()); + + didFinishLoad = false; + Util::run(&didFinishLoad); +} + +TEST(WebKit2, WKPageConfigurationBasicWithNonPersistentDataStore) +{ + WKRetainPtr configuration = adoptWK(WKPageConfigurationCreate()); + WKRetainPtr context = adoptWK(WKContextCreate()); + WKPageConfigurationSetContext(configuration.get(), context.get()); + WKRetainPtr websiteDataStore = adoptWK(WKWebsiteDataStoreCreateNonPersistentDataStore()); + WKPageConfigurationSetWebsiteDataStore(configuration.get(), websiteDataStore.get()); + + PlatformWebView webView(configuration.get()); + setPageLoaderClient(webView.page()); + + WKRetainPtr copiedConfiguration = adoptWK(WKPageCopyPageConfiguration(webView.page())); + ASSERT_EQ(context.get(), WKPageConfigurationGetContext(copiedConfiguration.get())); + ASSERT_EQ(websiteDataStore.get(), WKPageConfigurationGetWebsiteDataStore(copiedConfiguration.get())); + + WKRetainPtr 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 sessionStateWithFirstItemRemoved; +static WKRetainPtr 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(value); + + WKRetainPtr url = adoptWK(WKBackForwardListItemCopyURL(backForwardListItem)); + WKRetainPtr 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(WKPageCopySessionState(webView.page(), reinterpret_cast(1), filterFirstItemCallback))); + sessionStateWithAllItemsRemoved = adoptWK(static_cast(WKPageCopySessionState(webView.page(), reinterpret_cast(1), filterAllItemsCallback))); +} + +TEST(WebKit2, WKPageCopySessionStateWithFiltering) +{ + WKRetainPtr 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 createSessionState(WKContextRef context) +static WKRetainPtr createSessionState(WKContextRef context) { PlatformWebView webView(context); setPageLoaderClient(webView.page()); @@ -57,7 +60,7 @@ static WKRetainPtr createSessionState(WKContextRef context) Util::run(&didFinishLoad); didFinishLoad = false; - return adoptWK(WKPageCopySessionState(webView.page(), 0, 0)); + return adoptWK(static_cast(WKPageCopySessionState(webView.page(), reinterpret_cast(1), nullptr))); } TEST(WebKit2, WKPageGetScaleFactorNotZero) @@ -67,13 +70,15 @@ TEST(WebKit2, WKPageGetScaleFactorNotZero) PlatformWebView webView(context.get()); setPageLoaderClient(webView.page()); - WKRetainPtr 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 +#include +#include +#include +#include +#include + +// 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 context = adoptWK(WKContextCreate()); + + PlatformWebView webView(context.get()); + setUpClients(webView.page()); + + WKRetainPtr 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 context = adoptWK(WKContextCreate()); + + WKRetainPtr 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 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 -#include +#include +#include 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/TestWebKitAPI/Tests/WebKit2/WKRetainPtr.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/WKRetainPtr.cpp new file mode 100644 index 000000000..860d7d48d --- /dev/null +++ b/Tools/TestWebKitAPI/Tests/WebKit2/WKRetainPtr.cpp @@ -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. + */ + +#include "config.h" + +#if WK_HAVE_C_SPI + +#include "PlatformUtilities.h" +#include + +namespace TestWebKitAPI { + +TEST(WebKit2, WKRetainPtr) +{ + WKRetainPtr string1 = adoptWK(WKStringCreateWithUTF8CString("a")); + WKRetainPtr string2 = adoptWK(WKStringCreateWithUTF8CString("a")); + WKRetainPtr string3 = adoptWK(WKStringCreateWithUTF8CString("a")); + WKRetainPtr string4 = adoptWK(WKStringCreateWithUTF8CString("a")); + + HashMap, int> map; + + map.set(string2, 2); + map.set(string1, 1); + + 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 + +#if WK_HAVE_C_SPI + +#include #include 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 +#include +#include +#include + +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(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 data = adoptCF(CFDataCreate(0, bytes, size)); + RetainPtr 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 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 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/TestWebKitAPI/Tests/WebKit2/WebArchive_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/WebArchive_Bundle.cpp new file mode 100644 index 000000000..11109fee0 --- /dev/null +++ b/Tools/TestWebKitAPI/Tests/WebKit2/WebArchive_Bundle.cpp @@ -0,0 +1,69 @@ +/* + * 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 "InjectedBundleTest.h" + +#include "PlatformUtilities.h" +#include +#include + +namespace TestWebKitAPI { + +class WebArchiveTest : public InjectedBundleTest { +public: + WebArchiveTest(const std::string& identifier); + +private: + virtual void didReceiveMessage(WKBundleRef, WKStringRef messageName, WKTypeRef messageBody); +}; + +static InjectedBundleTest::Register registrar("WebArchiveTest"); + +WebArchiveTest::WebArchiveTest(const std::string& identifier) + : InjectedBundleTest(identifier) +{ +} + +void WebArchiveTest::didReceiveMessage(WKBundleRef bundle, WKStringRef messageName, WKTypeRef body) +{ + if (!WKStringIsEqualToUTF8CString(messageName, "GetWebArchive")) + return; + + if (WKGetTypeID(body) != WKBundlePageGetTypeID()) + return; + + WKBundleFrameRef frame = WKBundlePageGetMainFrame(static_cast(body)); + if (!frame) + return; + WKBundlePostMessage(bundle, Util::toWK("DidGetWebArchive").get(), adoptWK(WKBundleFrameCopyWebArchive(frame)).get()); +} + +} // 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 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 -#include namespace TestWebKitAPI { @@ -41,7 +42,7 @@ public: } WKRetainPtr context; - OwnPtr webView; + std::unique_ptr webView; WKRetainPtr messageName; WKRetainPtr 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(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 -#include +#include +#include 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 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 +#include namespace TestWebKitAPI { @@ -42,7 +45,7 @@ static InjectedBundleTest::Register 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 @@ + 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 @@ + + + + + + + + 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 @@ + + + + + +
+ + + + +
+ + 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 @@ + + + + + +
Link to anchor
+ In between.
+ Anchor
+ After the anchor.
+ + 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 @@ + + + + + + +

+ +

+

+ +

+ + 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 @@ + + + + + +

+ +

+

+ +

+ + 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 @@ + + + Test search. Hello Hello Hello! + + 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 @@ + +Test search. Hello world, Hello crazy world, Hello! + + 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 @@ + 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 @@ + 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 @@ + 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 @@ + 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 @@ + diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/gtk/InputMethodFilter.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/gtk/InputMethodFilter.cpp new file mode 100644 index 000000000..4a0e684d6 --- /dev/null +++ b/Tools/TestWebKitAPI/Tests/WebKit2/gtk/InputMethodFilter.cpp @@ -0,0 +1,258 @@ +/* + * 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 "config.h" + +#include "WTFStringUtilities.h" +#include +#include +#include +#include +#include +#include + +using namespace WebKit; + +namespace TestWebKitAPI { + +class TestInputMethodFilter : public InputMethodFilter { +public: + TestInputMethodFilter() + : m_testWindow(gtk_window_new(GTK_WINDOW_POPUP)) + { + setTestingMode(true); + + gtk_widget_show(m_testWindow); + gtk_im_context_set_client_window(context(), gtk_widget_get_window(m_testWindow)); + + setEnabled(true); + } + + ~TestInputMethodFilter() + { + gtk_widget_destroy(m_testWindow); + } + + 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); + 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 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; + + filterKeyEvent(&event->key); + gdk_event_free(event); + } + + void sendPressAndReleaseKeyEventPairToFilter(unsigned gdkKeyValue, unsigned modifiers = 0) + { + sendKeyEventToFilter(gdkKeyValue, GDK_KEY_PRESS, modifiers); + sendKeyEventToFilter(gdkKeyValue, GDK_KEY_RELEASE, modifiers); + } + +private: + GtkWidget* m_testWindow; +}; + +TEST(WebKit2, InputMethodFilterSimple) +{ + TestInputMethodFilter inputMethodFilter; + inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_g); + inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_t); + inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_k); + + const Vector& events = inputMethodFilter.events(); + + ASSERT_EQ(6, events.size()); + ASSERT_EQ(String("sendSimpleKeyEvent type=press keycode=67 text='g'"), events[0]); + ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=67"), events[1]); + ASSERT_EQ(String("sendSimpleKeyEvent type=press keycode=74 text='t'"), events[2]); + ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=74"), events[3]); + ASSERT_EQ(String("sendSimpleKeyEvent type=press keycode=6b text='k'"), events[4]); + ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=6b"), events[5]); +} + +TEST(WebKit2, InputMethodFilterUnicodeSequence) +{ + TestInputMethodFilter inputMethodFilter; + + // This is simple unicode hex entry of the characters, u, 0, 0, f, 4 pressed with + // the shift and controls keys held down. In reality, these values are not typical + // of an actual hex entry, because they'd be transformed by the shift modifier according + // to the keyboard layout. For instance, on a US keyboard a 0 with the shift key pressed + // is a right parenthesis. Using these values prevents having to work out what the + // transformed characters are based on the current keyboard layout. + inputMethodFilter.sendKeyEventToFilter(GDK_KEY_Control_L, GDK_KEY_PRESS); + inputMethodFilter.sendKeyEventToFilter(GDK_KEY_Shift_L, GDK_KEY_PRESS, GDK_CONTROL_MASK); + + inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_U, GDK_SHIFT_MASK | GDK_CONTROL_MASK); + inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_0, GDK_SHIFT_MASK | GDK_CONTROL_MASK); + inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_0, GDK_SHIFT_MASK | GDK_CONTROL_MASK); + inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_F, GDK_SHIFT_MASK | GDK_CONTROL_MASK); + inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_4, GDK_SHIFT_MASK | GDK_CONTROL_MASK); + + inputMethodFilter.sendKeyEventToFilter(GDK_KEY_Shift_L, GDK_KEY_RELEASE, GDK_CONTROL_MASK | GDK_SHIFT_MASK); + inputMethodFilter.sendKeyEventToFilter(GDK_KEY_Control_L, GDK_KEY_RELEASE, GDK_CONTROL_MASK); + + const Vector& events = inputMethodFilter.events(); + ASSERT_EQ(21, events.size()); + ASSERT_EQ(String("sendSimpleKeyEvent type=press keycode=ffe3"), events[0]); + ASSERT_EQ(String("sendSimpleKeyEvent type=press keycode=ffe1"), events[1]); + ASSERT_EQ(String("sendKeyEventWithCompositionResults type=press keycode=85"), events[2]); + ASSERT_EQ(String("setPreedit text='u' cursorOffset=1"), events[3]); + ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=55"), events[4]); + ASSERT_EQ(String("sendKeyEventWithCompositionResults type=press keycode=48"), events[5]); + ASSERT_EQ(String("setPreedit text='u0' cursorOffset=2"), events[6]); + ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=30"), events[7]); + ASSERT_EQ(String("sendKeyEventWithCompositionResults type=press keycode=48"), events[8]); + ASSERT_EQ(String("setPreedit text='u00' cursorOffset=3"), events[9]); + ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=30"), events[10]); + ASSERT_EQ(String("sendKeyEventWithCompositionResults type=press keycode=70"), events[11]); + ASSERT_EQ(String("setPreedit text='u00F' cursorOffset=4"), events[12]); + ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=46"), events[13]); + ASSERT_EQ(String("sendKeyEventWithCompositionResults type=press keycode=52"), events[14]); + ASSERT_EQ(String("setPreedit text='u00F4' cursorOffset=5"), events[15]); + ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=34"), events[16]); + ASSERT_EQ(String("confirmComposition 'ô'"), events[17]); + ASSERT_EQ(String("setPreedit text='' cursorOffset=0"), events[18]); + ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=ffe1"), events[19]); + ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=ffe3"), events[20]); +} + +TEST(WebKit2, InputMethodFilterComposeKey) +{ + TestInputMethodFilter inputMethodFilter; + + inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_Multi_key); + inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_apostrophe); + inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_o); + + const Vector& events = inputMethodFilter.events(); + ASSERT_EQ(5, events.size()); + ASSERT_EQ(String("sendKeyEventWithCompositionResults type=press keycode=39"), events[0]); + ASSERT_EQ(String("setPreedit text='' cursorOffset=0"), events[1]); + ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=27"), events[2]); + ASSERT_EQ(String("sendSimpleKeyEvent type=press keycode=6f text='ó'"), events[3]); + ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=6f"), events[4]); +} + +typedef void (*GetPreeditStringCallback) (GtkIMContext*, gchar**, PangoAttrList**, int*); +static void temporaryGetPreeditStringOverride(GtkIMContext*, char** string, PangoAttrList** attrs, int* cursorPosition) +{ + *string = g_strdup("preedit of doom, bringer of cheese"); + *cursorPosition = 3; +} + +TEST(WebKit2, InputMethodFilterContextEventsWithoutKeyEvents) +{ + TestInputMethodFilter inputMethodFilter; + + // This is a bit of a hack to avoid mocking out the entire InputMethodContext, by + // simply replacing the get_preedit_string virtual method for the length of this test. + GtkIMContext* context = inputMethodFilter.context(); + GtkIMContextClass* contextClass = GTK_IM_CONTEXT_GET_CLASS(context); + GetPreeditStringCallback previousCallback = contextClass->get_preedit_string; + contextClass->get_preedit_string = temporaryGetPreeditStringOverride; + + g_signal_emit_by_name(context, "preedit-changed"); + g_signal_emit_by_name(context, "commit", "commit text"); + + contextClass->get_preedit_string = previousCallback; + + const Vector& events = inputMethodFilter.events(); + ASSERT_EQ(6, events.size()); + ASSERT_EQ(String("sendKeyEventWithCompositionResults type=press keycode=16777215 (faked)"), events[0]); + ASSERT_EQ(String("setPreedit text='preedit of doom, bringer of cheese' cursorOffset=3"), events[1]); + ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=ffffff (faked)"), events[2]); + ASSERT_EQ(String("sendKeyEventWithCompositionResults type=press keycode=16777215 (faked)"), events[3]); + ASSERT_EQ(String("confirmComposition 'commit text'"), events[4]); + ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=ffffff (faked)"), events[5]); +} + +static bool gSawContextReset = false; +typedef void (*ResetCallback) (GtkIMContext*); +static void temporaryResetOverride(GtkIMContext*) +{ + gSawContextReset = true; +} + +static void verifyCanceledComposition(const Vector& events) +{ + ASSERT_EQ(3, events.size()); + ASSERT_EQ(String("sendKeyEventWithCompositionResults type=press keycode=39"), events[0]); + ASSERT_EQ(String("setPreedit text='' cursorOffset=0"), events[1]); + ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=27"), events[2]); + ASSERT(gSawContextReset); +} + +TEST(WebKit2, InputMethodFilterContextFocusOutDuringOngoingComposition) +{ + TestInputMethodFilter inputMethodFilter; + + // See comment above about this technique. + GtkIMContext* context = inputMethodFilter.context(); + GtkIMContextClass* contextClass = GTK_IM_CONTEXT_GET_CLASS(context); + ResetCallback previousCallback = contextClass->reset; + contextClass->reset = temporaryResetOverride; + + gSawContextReset = false; + inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_Multi_key); + inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_apostrophe); + inputMethodFilter.notifyFocusedOut(); + + verifyCanceledComposition(inputMethodFilter.events()); + + contextClass->reset = previousCallback; +} + +TEST(WebKit2, InputMethodFilterContextMouseClickDuringOngoingComposition) +{ + TestInputMethodFilter inputMethodFilter; + + // See comment above about this technique. + GtkIMContext* context = inputMethodFilter.context(); + GtkIMContextClass* contextClass = GTK_IM_CONTEXT_GET_CLASS(context); + ResetCallback previousCallback = contextClass->reset; + contextClass->reset = temporaryResetOverride; + + gSawContextReset = false; + inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_Multi_key); + inputMethodFilter.sendPressAndReleaseKeyEventPairToFilter(GDK_KEY_apostrophe); + inputMethodFilter.notifyMouseButtonPress(); + + verifyCanceledComposition(inputMethodFilter.events()); + + contextClass->reset = previousCallback; +} + +} // namespace TestWebKitAPI diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/icon.png b/Tools/TestWebKitAPI/Tests/WebKit2/icon.png new file mode 100644 index 000000000..79e459894 Binary files /dev/null and b/Tools/TestWebKitAPI/Tests/WebKit2/icon.png 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 @@ + + + +
+ + + + + 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 @@ + + + + + + +