diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Tools/WebKitTestRunner | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Tools/WebKitTestRunner')
73 files changed, 7241 insertions, 2075 deletions
diff --git a/Tools/WebKitTestRunner/CMakeLists.txt b/Tools/WebKitTestRunner/CMakeLists.txt new file mode 100644 index 000000000..fb7d52339 --- /dev/null +++ b/Tools/WebKitTestRunner/CMakeLists.txt @@ -0,0 +1,121 @@ +set(WEBKIT_TESTRUNNER_DIR "${TOOLS_DIR}/WebKitTestRunner") +set(WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR "${TOOLS_DIR}/WebKitTestRunner/InjectedBundle") +set(WEBKIT_TESTRUNNER_SHARED_DIR "${TOOLS_DIR}/TestRunnerShared/") +set(WEBKIT_TESTRUNNER_UISCRIPTCONTEXT_DIR "${WEBKIT_TESTRUNNER_SHARED_DIR}/UIScriptContext") +set(WEBKIT_TESTRUNNER_BINDINGS_DIR "${WEBKIT_TESTRUNNER_SHARED_DIR}/Bindings") + +file(MAKE_DIRECTORY ${DERIVED_SOURCES_DIR}/InjectedBundle) +file(MAKE_DIRECTORY ${DERIVED_SOURCES_DIR}/UIScriptContext) + +set(WebKitTestRunner_SOURCES + ${WEBKIT_TESTRUNNER_DIR}/CyclicRedundancyCheck.cpp + ${WEBKIT_TESTRUNNER_DIR}/GeolocationProviderMock.cpp + ${WEBKIT_TESTRUNNER_DIR}/Options.cpp + ${WEBKIT_TESTRUNNER_DIR}/PixelDumpSupport.cpp + ${WEBKIT_TESTRUNNER_DIR}/TestController.cpp + ${WEBKIT_TESTRUNNER_DIR}/TestInvocation.cpp + ${WEBKIT_TESTRUNNER_DIR}/TestOptions.cpp + ${WEBKIT_TESTRUNNER_DIR}/WebNotificationProvider.cpp + ${WEBKIT_TESTRUNNER_DIR}/WorkQueueManager.cpp + ${WEBKIT_TESTRUNNER_UISCRIPTCONTEXT_DIR}/UIScriptContext.cpp + ${WEBKIT_TESTRUNNER_UISCRIPTCONTEXT_DIR}/UIScriptController.cpp + ${WEBKIT_TESTRUNNER_BINDINGS_DIR}/JSWrapper.cpp +) + +set(WebKitTestRunner_LIBRARIES + JavaScriptCore + WebCoreTestSupport + WebKit2 +) + +set(WebKitTestRunner_INCLUDE_DIRECTORIES + ${WEBKIT_TESTRUNNER_DIR} + ${WEBKIT_TESTRUNNER_DIR}/InjectedBundle + ${WEBKIT_TESTRUNNER_DIR}/InjectedBundle/Bindings + ${WEBKIT_TESTRUNNER_DIR}/InjectedBundle/atk + ${WEBKIT_TESTRUNNER_UISCRIPTCONTEXT_DIR} + ${WEBKIT_TESTRUNNER_BINDINGS_DIR} + ${WEBCORE_DIR}/testing/js + ${WEBKIT2_DIR}/Platform/IPC + ${WEBKIT2_DIR}/Shared + ${WEBKIT2_DIR}/Shared/API/c + ${WEBKIT2_DIR}/Shared/Plugins + ${WEBKIT2_DIR}/UIProcess + ${WEBKIT2_DIR}/UIProcess/API/C/soup + ${WEBKIT2_DIR}/WebProcess/InjectedBundle + ${WEBKIT2_DIR}/WebProcess/InjectedBundle/API/c + ${DERIVED_SOURCES_DIR}/InjectedBundle + ${DERIVED_SOURCES_DIR}/UIScriptContext + ${CMAKE_SOURCE_DIR}/Source +) + +set(WebKitTestRunner_SYSTEM_INCLUDE_DIRECTORIES + ${LIBSOUP_INCLUDE_DIRS} + ${ICU_INCLUDE_DIRS} +) + +set(WebKitTestRunnerInjectedBundle_SOURCES + ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/AccessibilityController.cpp + ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/AccessibilityTextMarker.cpp + ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/AccessibilityTextMarkerRange.cpp + ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/AccessibilityUIElement.cpp + ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/EventSendingController.cpp + ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/GCController.cpp + ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/InjectedBundle.cpp + ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/InjectedBundleMain.cpp + ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/InjectedBundlePage.cpp + ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/TestRunner.cpp + ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/TextInputController.cpp + + ${WEBKIT_TESTRUNNER_BINDINGS_DIR}/JSWrapper.cpp +) + +set(WebKitTestRunnerInjectedBundle_IDL_FILES + "${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/Bindings/AccessibilityController.idl" + "${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/Bindings/AccessibilityTextMarker.idl" + "${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/Bindings/AccessibilityTextMarkerRange.idl" + "${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/Bindings/AccessibilityUIElement.idl" + "${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/Bindings/EventSendingController.idl" + "${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/Bindings/GCController.idl" + "${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/Bindings/TestRunner.idl" + "${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/Bindings/TextInputController.idl" +) + +set(WebKitTestRunner_IDL_FILES + "${WEBKIT_TESTRUNNER_UISCRIPTCONTEXT_DIR}/Bindings/UIScriptController.idl" +) + +GENERATE_BINDINGS(WebKitTestRunnerInjectedBundleBindings + OUTPUT_SOURCE WebKitTestRunnerInjectedBundle_SOURCES + INPUT_FILES ${WebKitTestRunnerInjectedBundle_IDL_FILES} + BASE_DIR ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/Bindings + IDL_INCLUDES ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/Bindings + FEATURES ${FEATURE_DEFINES_WITH_SPACE_SEPARATOR} + DESTINATION ${DERIVED_SOURCES_DIR}/InjectedBundle + GENERATOR TestRunner) + +GENERATE_BINDINGS(WebKitTestRunnerBindings + OUTPUT_SOURCE WebKitTestRunner_SOURCES + INPUT_FILES ${WebKitTestRunner_IDL_FILES} + BASE_DIR ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/Bindings + IDL_INCLUDES ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/Bindings + FEATURES ${FEATURE_DEFINES_WITH_SPACE_SEPARATOR} + DESTINATION ${DERIVED_SOURCES_DIR}/UIScriptContext + GENERATOR TestRunner) + +WEBKIT_INCLUDE_CONFIG_FILES_IF_EXISTS() + +include_directories(${WebKitTestRunner_INCLUDE_DIRECTORIES}) +include_directories(SYSTEM ${WebKitTestRunner_SYSTEM_INCLUDE_DIRECTORIES}) + +add_library(TestRunnerInjectedBundle SHARED ${WebKitTestRunnerInjectedBundle_SOURCES}) +target_link_libraries(TestRunnerInjectedBundle ${WebKitTestRunner_LIBRARIES}) +add_dependencies(TestRunnerInjectedBundle WebKitTestRunnerInjectedBundleBindings) + +add_executable(WebKitTestRunner ${WebKitTestRunner_SOURCES}) +target_link_libraries(WebKitTestRunner ${WebKitTestRunner_LIBRARIES}) +add_dependencies(WebKitTestRunner WebKitTestRunnerBindings) + +if (NOT APPLE) + add_dependencies(WebKit2 ${ForwardingHeadersForWebKitTestRunner_NAME}) +endif ()
\ No newline at end of file diff --git a/Tools/WebKitTestRunner/DerivedSources.make b/Tools/WebKitTestRunner/DerivedSources.make new file mode 100644 index 000000000..4a2b1790f --- /dev/null +++ b/Tools/WebKitTestRunner/DerivedSources.make @@ -0,0 +1,62 @@ +# Copyright (C) 2010 Apple Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + +VPATH = \ + $(WebKitTestRunner)/InjectedBundle/Bindings \ + $(WebKitTestRunner)/../TestRunnerShared/UIScriptContext/Bindings \ +# + +INJECTED_BUNDLE_INTERFACES = \ + AccessibilityController \ + AccessibilityTextMarker \ + AccessibilityTextMarkerRange \ + AccessibilityUIElement \ + EventSendingController \ + GCController \ + TestRunner \ + TextInputController \ +# + +UICONTEXT_INTERFACES = \ + UIScriptController \ +# + +SCRIPTS = \ + $(WebCoreScripts)/CodeGenerator.pm \ + $(WebKitTestRunner)/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm \ + $(WebCoreScripts)/IDLParser.pm \ + $(WebCoreScripts)/generate-bindings.pl \ +# + +.PHONY : all + +JS%.h JS%.cpp : %.idl $(SCRIPTS) + @echo Generating bindings for $*... + @perl -I $(WebCoreScripts) -I $(WebKitTestRunner)/InjectedBundle/Bindings -I $(WebKitTestRunner)/UIScriptContext/Bindings $(WebCoreScripts)/generate-bindings.pl --defines "" --include InjectedBundle/Bindings --include UIScriptContext/Bindings --outputDir . --generator TestRunner $< + +all : \ + $(INJECTED_BUNDLE_INTERFACES:%=JS%.h) \ + $(INJECTED_BUNDLE_INTERFACES:%=JS%.cpp) \ + $(UICONTEXT_INTERFACES:%=JS%.h) \ + $(UICONTEXT_INTERFACES:%=JS%.cpp) \ +# diff --git a/Tools/WebKitTestRunner/EventSenderProxy.h b/Tools/WebKitTestRunner/EventSenderProxy.h index db2c58b0d..70d94014c 100644 --- a/Tools/WebKitTestRunner/EventSenderProxy.h +++ b/Tools/WebKitTestRunner/EventSenderProxy.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2014 Apple Inc. All rights reserved. * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * * Redistribution and use in source and binary forms, with or without @@ -29,6 +29,7 @@ #include <wtf/Deque.h> #include <wtf/HashMap.h> +#include <wtf/RetainPtr.h> #include <wtf/Vector.h> #if PLATFORM(GTK) @@ -36,7 +37,11 @@ #include <gdk/gdk.h> #include <wtf/HashSet.h> #elif PLATFORM(EFL) -#include <WebKit2/EWebKit2.h> +#include "EWebKit2.h" +#endif + +#if PLATFORM(COCOA) +OBJC_CLASS NSEvent; #endif namespace WTR { @@ -58,8 +63,15 @@ public: void mouseDown(unsigned button, WKEventModifiers); void mouseUp(unsigned button, WKEventModifiers); + void mouseForceDown(); + void mouseForceUp(); + void mouseForceChanged(float); + void mouseForceClick(); + void startAndCancelMouseForceClick(); void mouseMoveTo(double x, double y); void mouseScrollBy(int x, int y); + void mouseScrollByWithWheelAndMomentumPhases(int x, int y, int phase, int momentum); + void swipeGestureWithWheelAndMomentumPhases(int x, int y, int phase, int momentum); void continuousMouseScrollBy(int x, int y, bool paged); void leapForward(int milliseconds); @@ -91,8 +103,17 @@ private: void replaySavedEvents(); #endif + void sendMouseDownToStartPressureEvents(); +#if PLATFORM(COCOA) + enum class PressureChangeDirection { Increasing, Decreasing }; + RetainPtr<NSEvent> beginPressureEvent(int stage); + RetainPtr<NSEvent> pressureChangeEvent(int stage, PressureChangeDirection); + RetainPtr<NSEvent> pressureChangeEvent(int stage, float pressure, PressureChangeDirection); +#endif + #if PLATFORM(GTK) void sendOrQueueEvent(GdkEvent*); + void dispatchEvent(GdkEvent*); GdkEvent* createMouseButtonEvent(GdkEventType, unsigned button, WKEventModifiers); GUniquePtr<GdkEvent> createTouchEvent(GdkEventType, int id); void sendUpdatedTouchEvents(); @@ -111,7 +132,7 @@ private: double m_clickTime; WKPoint m_clickPosition; WKEventMouseButton m_clickButton; -#if PLATFORM(MAC) +#if PLATFORM(COCOA) int eventNumber; #elif PLATFORM(GTK) Deque<WTREventQueueItem> m_eventQueue; diff --git a/Tools/WebKitTestRunner/FontWithFeatures.otf b/Tools/WebKitTestRunner/FontWithFeatures.otf Binary files differnew file mode 100644 index 000000000..3e5069995 --- /dev/null +++ b/Tools/WebKitTestRunner/FontWithFeatures.otf diff --git a/Tools/WebKitTestRunner/FontWithFeatures.ttf b/Tools/WebKitTestRunner/FontWithFeatures.ttf Binary files differnew file mode 100644 index 000000000..42c332a13 --- /dev/null +++ b/Tools/WebKitTestRunner/FontWithFeatures.ttf diff --git a/Tools/WebKitTestRunner/GNUmakefile.am b/Tools/WebKitTestRunner/GNUmakefile.am deleted file mode 100644 index 28a2d5747..000000000 --- a/Tools/WebKitTestRunner/GNUmakefile.am +++ /dev/null @@ -1,175 +0,0 @@ - -stamp-webkittestrunner-forwarding-headers: $(WebKit2)/Scripts/generate-forwarding-headers.pl $(Programs_WebKitTestRunner_SOURCES) $(Libraries_libTestRunnerInjectedBundle_la_SOURCES) - $(AM_V_GEN)$(PERL) $< $(srcdir)/Tools/WebKitTestRunner $(GENSOURCES_WEBKIT2)/include gtk \ - && echo timestamp > $(@F) - -BUILT_SOURCES += $(top_builddir)/stamp-webkittestrunner-forwarding-headers - -if ENABLE_WEBKIT2 -noinst_PROGRAMS += \ - Programs/WebKitTestRunner -endif - -Programs_WebKitTestRunner_SOURCES = \ - Tools/WebKitTestRunner/EventSenderProxy.h \ - Tools/WebKitTestRunner/gtk/main.cpp \ - Tools/WebKitTestRunner/gtk/EventSenderProxyGtk.cpp \ - Tools/WebKitTestRunner/gtk/PlatformWebViewGtk.cpp \ - Tools/WebKitTestRunner/gtk/TestControllerGtk.cpp \ - Tools/WebKitTestRunner/cairo/TestInvocationCairo.cpp \ - Tools/WebKitTestRunner/CyclicRedundancyCheck.cpp \ - Tools/WebKitTestRunner/CyclicRedundancyCheck.h \ - Tools/WebKitTestRunner/GeolocationProviderMock.cpp \ - Tools/WebKitTestRunner/GeolocationProviderMock.h \ - Tools/WebKitTestRunner/Options.cpp \ - Tools/WebKitTestRunner/Options.h \ - Tools/WebKitTestRunner/PixelDumpSupport.cpp \ - Tools/WebKitTestRunner/PixelDumpSupport.h \ - Tools/WebKitTestRunner/PlatformWebView.h \ - Tools/WebKitTestRunner/StringFunctions.h \ - Tools/WebKitTestRunner/TestController.cpp \ - Tools/WebKitTestRunner/TestController.h \ - Tools/WebKitTestRunner/TestInvocation.cpp \ - Tools/WebKitTestRunner/TestInvocation.h \ - Tools/WebKitTestRunner/WebNotificationProvider.cpp \ - Tools/WebKitTestRunner/WebNotificationProvider.h \ - Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h \ - Tools/WebKitTestRunner/WorkQueueManager.cpp \ - Tools/WebKitTestRunner/WorkQueueManager.h - -Programs_WebKitTestRunner_CPPFLAGS = \ - -include Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h \ - -I$(srcdir)/Tools/WebKitTestRunner \ - -I$(srcdir)/Source/WebCore/platform/gtk \ - -I$(top_builddir)/DerivedSources/WebKit2/include \ - $(global_cppflags) \ - $(javascriptcore_cppflags) \ - $(webcore_cppflags) \ - $(CAIRO_CFLAGS) \ - $(GTK_CFLAGS) \ - $(LIBSOUP_CFLAGS) -Programs_WebKitTestRunner_CXXFLAGS = $(global_cxxflags) -Programs_WebKitTestRunner_CFLAGS = $(global_cflags) - -Programs_WebKitTestRunner_LDADD = \ - libjavascriptcoregtk-@WEBKITGTK_API_MAJOR_VERSION@.@WEBKITGTK_API_MINOR_VERSION@.la \ - libwebkit2gtk-@WEBKITGTK_API_MAJOR_VERSION@.@WEBKITGTK_API_MINOR_VERSION@.la \ - $(CAIRO_LIBS) \ - $(GTK_LIBS) \ - $(GLIB_LIBS) \ - $(LIBSOUP_LIBS) \ - $(FREETYPE_LIBS) \ - $(WINMM_LIBS) \ - $(XRENDER_LIBS) \ - $(XT_LIBS) - -Programs_WebKitTestRunner_LDFLAGS = \ - -no-install - -# The InjectedBundle library allows the render process to load harness code. -if ENABLE_WEBKIT2 -noinst_LTLIBRARIES += Libraries/libTestRunnerInjectedBundle.la -endif - -webkittestrunner_built_sources += \ - DerivedSources/InjectedBundle/JSAccessibilityController.cpp \ - DerivedSources/InjectedBundle/JSAccessibilityTextMarker.cpp \ - DerivedSources/InjectedBundle/JSAccessibilityTextMarkerRange.cpp \ - DerivedSources/InjectedBundle/JSAccessibilityUIElement.cpp \ - DerivedSources/InjectedBundle/JSEventSendingController.cpp \ - DerivedSources/InjectedBundle/JSGCController.cpp \ - DerivedSources/InjectedBundle/JSTestRunner.cpp \ - DerivedSources/InjectedBundle/JSTextInputController.cpp -nodist_Libraries_libTestRunnerInjectedBundle_la_SOURCES = $(webkittestrunner_built_sources) -BUILT_SOURCES += $(webkittestrunner_built_sources) - -Libraries_libTestRunnerInjectedBundle_la_SOURCES = \ - Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.cpp \ - Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.h \ - Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarker.cpp \ - Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarker.h \ - Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarkerRange.cpp \ - Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarkerRange.h \ - Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp \ - Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h \ - Tools/WebKitTestRunner/InjectedBundle/ActivateFonts.h \ - Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityControllerAtk.cpp \ - Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.cpp \ - Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.h \ - Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp \ - Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrappable.h \ - Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.cpp \ - Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.h \ - Tools/WebKitTestRunner/InjectedBundle/EventSendingController.cpp \ - Tools/WebKitTestRunner/InjectedBundle/EventSendingController.h \ - Tools/WebKitTestRunner/InjectedBundle/GCController.cpp \ - Tools/WebKitTestRunner/InjectedBundle/GCController.h \ - Tools/WebKitTestRunner/InjectedBundle/gtk/ActivateFontsGtk.cpp \ - Tools/WebKitTestRunner/InjectedBundle/gtk/InjectedBundleGtk.cpp \ - Tools/WebKitTestRunner/InjectedBundle/gtk/InjectedBundleUtilities.cpp \ - Tools/WebKitTestRunner/InjectedBundle/gtk/InjectedBundleUtilities.h \ - Tools/WebKitTestRunner/InjectedBundle/gtk/TestRunnerGtk.cpp \ - Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp \ - Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h \ - Tools/WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp \ - Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp \ - Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h \ - Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp \ - Tools/WebKitTestRunner/InjectedBundle/TestRunner.h \ - Tools/WebKitTestRunner/InjectedBundle/TextInputController.cpp \ - Tools/WebKitTestRunner/InjectedBundle/TextInputController.h - -Libraries_libTestRunnerInjectedBundle_la_LIBADD = \ - libWebCoreInternals.la - -Libraries_libTestRunnerInjectedBundle_la_LDFLAGS = \ - -rpath ${shell pwd}/$(top_builddir)/../unix/TestNetscapePlugin/.libs \ - $(no_undefined) \ - -avoid-version \ - -module - -Libraries_libTestRunnerInjectedBundle_la_CPPFLAGS = \ - -DFONTS_CONF_DIR=\"${shell pwd}/${srcdir}/Tools/DumpRenderTree/gtk/fonts\" \ - -DTOP_LEVEL_DIR=\"${shell pwd}/${srcdir}\" \ - -include Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h \ - -I$(srcdir)/Tools/WebKitTestRunner \ - -I$(srcdir)/Tools/WebKitTestRunner/InjectedBundle \ - -I$(srcdir)/Tools/WebKitTestRunner/InjectedBundle/Bindings \ - -I$(srcdir)/Tools/WebKitTestRunner/InjectedBundle/atk \ - -I$(srcdir)/Source/WebCore/testing/js \ - -I$(top_builddir)/DerivedSources/InjectedBundle \ - -I$(top_builddir)/DerivedSources/WebKit2/include \ - $(global_cppflags) \ - $(javascriptcore_cppflags) \ - $(webcore_cppflags) \ - $(CAIRO_CFLAGS) \ - $(GLIB_CFLAGS) \ - $(GTK_CFLAGS) \ - $(LIBSOUP_CFLAGS) -Libraries_libTestRunnerInjectedBundle_la_CXXFLAGS = $(global_cxxflags) -Libraries_libTestRunnerInjectedBundle_la_CFLAGS = $(global_cflags) - -code_generation_dependencies = \ - Tools/WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm \ - Source/WebCore/bindings/scripts/CodeGenerator.pm \ - Source/WebCore/bindings/scripts/IDLParser.pm \ - Source/WebCore/bindings/scripts/InFilesParser.pm \ - Source/WebCore/bindings/scripts/generate-bindings.pl - -DerivedSources/InjectedBundle/JS%.cpp: Tools/WebKitTestRunner/InjectedBundle/Bindings/%.idl $(code_generation_dependencies) - $(AM_V_GEN)$(PERL) \ - -I $(srcdir)/Source/WebCore/bindings/scripts \ - -I $(srcdir)/Tools/WebKitTestRunner/InjectedBundle/Bindings \ - $(srcdir)/Source/WebCore/bindings/scripts/generate-bindings.pl \ - --defines "$(feature_defines)" --generator TestRunner \ - --include $(srcdir)/Tools/InjectedBundle/Bindings \ - --outputDir $(top_builddir)/DerivedSources/InjectedBundle \ - $< - -EXTRA_DIST += \ - $(srcdir)/Tools/WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm \ - $(srcdir)/Source/WebCore/bindings/scripts/CodeGenerator.pm \ - $(srcdir)/Source/WebCore/bindings/scripts/IDLParser.pm \ - $(srcdir)/Source/WebCore/bindings/scripts/InFilesParser.pm \ - $(srcdir)/Source/WebCore/bindings/scripts/generate-bindings.pl \ - $(shell ls $(srcdir)/Tools/WebKitTestRunner/InjectedBundle/Bindings/*.idl) diff --git a/Tools/WebKitTestRunner/GeolocationProviderMock.cpp b/Tools/WebKitTestRunner/GeolocationProviderMock.cpp index 9120258c7..ad4164966 100644 --- a/Tools/WebKitTestRunner/GeolocationProviderMock.cpp +++ b/Tools/WebKitTestRunner/GeolocationProviderMock.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "GeolocationProviderMock.h" -#include <WebKit2/WKGeolocationManager.h> +#include <WebKit/WKGeolocationManager.h> #include <string.h> #include <wtf/Assertions.h> #include <wtf/CurrentTime.h> @@ -52,7 +52,7 @@ GeolocationProviderMock::GeolocationProviderMock(WKContextRef context) m_geolocationManager = WKContextGetGeolocationManager(context); WKGeolocationProviderV1 providerCallback; - memset(&providerCallback, 0, sizeof(WKGeolocationProvider)); + memset(&providerCallback, 0, sizeof(WKGeolocationProviderV1)); providerCallback.base.version = 1; providerCallback.base.clientInfo = this; providerCallback.startUpdating = startUpdatingCallback; diff --git a/Tools/WebKitTestRunner/GeolocationProviderMock.h b/Tools/WebKitTestRunner/GeolocationProviderMock.h index ff5537e46..802223ec3 100644 --- a/Tools/WebKitTestRunner/GeolocationProviderMock.h +++ b/Tools/WebKitTestRunner/GeolocationProviderMock.h @@ -26,7 +26,7 @@ #ifndef GeolocationProviderMock_h #define GeolocationProviderMock_h -#include <WebKit2/WKRetainPtr.h> +#include <WebKit/WKRetainPtr.h> namespace WTR { @@ -41,6 +41,8 @@ public: void startUpdating(WKGeolocationManagerRef); void stopUpdating(WKGeolocationManagerRef); + bool isActive() const { return m_isActive; } + private: void sendPositionIfNeeded(); void sendErrorIfNeeded(); diff --git a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.cpp b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.cpp index f5d1bd58b..0a130d4e8 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.cpp @@ -32,15 +32,15 @@ #include "JSAccessibilityController.h" #include <JavaScriptCore/JSRetainPtr.h> -#include <WebKit2/WKBundle.h> -#include <WebKit2/WKBundlePage.h> -#include <WebKit2/WKBundlePagePrivate.h> +#include <WebKit/WKBundle.h> +#include <WebKit/WKBundlePage.h> +#include <WebKit/WKBundlePagePrivate.h> namespace WTR { -PassRefPtr<AccessibilityController> AccessibilityController::create() +Ref<AccessibilityController> AccessibilityController::create() { - return adoptRef(new AccessibilityController); + return adoptRef(*new AccessibilityController); } AccessibilityController::AccessibilityController() @@ -61,44 +61,43 @@ JSClassRef AccessibilityController::wrapperClass() return JSAccessibilityController::accessibilityControllerClass(); } +void AccessibilityController::enableEnhancedAccessibility(bool enable) +{ + WKAccessibilityEnableEnhancedAccessibility(enable); +} + +bool AccessibilityController::enhancedAccessibilityEnabled() +{ + return WKAccessibilityEnhancedAccessibilityEnabled(); +} + #if !PLATFORM(GTK) && !PLATFORM(EFL) -PassRefPtr<AccessibilityUIElement> AccessibilityController::rootElement() +Ref<AccessibilityUIElement> AccessibilityController::rootElement() { - WKBundlePageRef page = InjectedBundle::shared().page()->page(); + WKBundlePageRef page = InjectedBundle::singleton().page()->page(); void* root = WKAccessibilityRootObject(page); return AccessibilityUIElement::create(static_cast<PlatformUIElement>(root)); } -PassRefPtr<AccessibilityUIElement> AccessibilityController::focusedElement() +Ref<AccessibilityUIElement> AccessibilityController::focusedElement() { - WKBundlePageRef page = InjectedBundle::shared().page()->page(); + WKBundlePageRef page = InjectedBundle::singleton().page()->page(); void* root = WKAccessibilityFocusedObject(page); return AccessibilityUIElement::create(static_cast<PlatformUIElement>(root)); } #endif -PassRefPtr<AccessibilityUIElement> AccessibilityController::elementAtPoint(int x, int y) +RefPtr<AccessibilityUIElement> AccessibilityController::elementAtPoint(int x, int y) { - RefPtr<AccessibilityUIElement> uiElement = rootElement(); + Ref<AccessibilityUIElement> uiElement = rootElement(); return uiElement->elementAtPoint(x, y); } -// Unsupported methods on various platforms. -// As they're implemented on other platforms this list should be modified. -#if (!PLATFORM(GTK) && !PLATFORM(MAC) && !PLATFORM(EFL)) || !HAVE(ACCESSIBILITY) -bool AccessibilityController::addNotificationListener(JSValueRef) { return false; } -bool AccessibilityController::removeNotificationListener() { return false; } -PassRefPtr<AccessibilityUIElement> AccessibilityController::accessibleElementById(JSStringRef attribute) { return nullptr; } -void AccessibilityController::logAccessibilityEvents() { } -void AccessibilityController::resetToConsistentState() { } -JSRetainPtr<JSStringRef> AccessibilityController::platformName() { return JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString("")); } -#endif - #if !HAVE(ACCESSIBILITY) && (PLATFORM(GTK) || PLATFORM(EFL)) -PassRefPtr<AccessibilityUIElement> AccessibilityController::rootElement() { return nullptr; } -PassRefPtr<AccessibilityUIElement> AccessibilityController::focusedElement() { return nullptr; } +RefPtr<AccessibilityUIElement> AccessibilityController::rootElement() { return nullptr; } +RefPtr<AccessibilityUIElement> AccessibilityController::focusedElement() { return nullptr; } #endif } // namespace WTR diff --git a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.h b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.h index 7ce1a45c3..5cf0d739c 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.h +++ b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityController.h @@ -23,14 +23,15 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef AccessibilityController_h -#define AccessibilityController_h +#pragma once + +#if HAVE(ACCESSIBILITY) #include "AccessibilityUIElement.h" #include "JSWrappable.h" #include <JavaScriptCore/JSObjectRef.h> #include <wtf/Platform.h> -#if HAVE(ACCESSIBILITY) && (PLATFORM(GTK) || PLATFORM(EFL)) +#if PLATFORM(GTK) || PLATFORM(EFL) #include "AccessibilityNotificationHandlerAtk.h" #endif @@ -38,19 +39,23 @@ namespace WTR { class AccessibilityController : public JSWrappable { public: - static PassRefPtr<AccessibilityController> create(); + static Ref<AccessibilityController> create(); ~AccessibilityController(); void makeWindowObject(JSContextRef, JSObjectRef windowObject, JSValueRef* exception); virtual JSClassRef wrapperClass(); + // Enhanced accessibility. + void enableEnhancedAccessibility(bool); + bool enhancedAccessibilityEnabled(); + JSRetainPtr<JSStringRef> platformName(); // Controller Methods - platform-independent implementations. - PassRefPtr<AccessibilityUIElement> rootElement(); - PassRefPtr<AccessibilityUIElement> focusedElement(); - PassRefPtr<AccessibilityUIElement> elementAtPoint(int x, int y); - PassRefPtr<AccessibilityUIElement> accessibleElementById(JSStringRef idAttribute); + Ref<AccessibilityUIElement> rootElement(); + Ref<AccessibilityUIElement> focusedElement(); + RefPtr<AccessibilityUIElement> elementAtPoint(int x, int y); + RefPtr<AccessibilityUIElement> accessibleElementById(JSStringRef idAttribute); bool addNotificationListener(JSValueRef functionCallback); bool removeNotificationListener(); @@ -59,22 +64,20 @@ public: void logFocusEvents() { } void logValueChangeEvents() { } void logScrollingStartEvents() { } - void logAccessibilityEvents(); + void logAccessibilityEvents() { }; void resetToConsistentState(); private: AccessibilityController(); -#if PLATFORM(MAC) +#if PLATFORM(COCOA) RetainPtr<NotificationHandler> m_globalNotificationHandler; -#endif - -#if HAVE(ACCESSIBILITY) && (PLATFORM(GTK) || PLATFORM(EFL)) +#else RefPtr<AccessibilityNotificationHandler> m_globalNotificationHandler; #endif }; } // namespace WTR -#endif // AccessibilityController_h +#endif // HAVE(ACCESSIBILITY) diff --git a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarker.cpp b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarker.cpp index a7a4b7def..7e99fbb12 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarker.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarker.cpp @@ -33,14 +33,14 @@ namespace WTR { -PassRefPtr<AccessibilityTextMarker> AccessibilityTextMarker::create(PlatformTextMarker marker) +Ref<AccessibilityTextMarker> AccessibilityTextMarker::create(PlatformTextMarker marker) { - return adoptRef(new AccessibilityTextMarker(marker)); + return adoptRef(*new AccessibilityTextMarker(marker)); } -PassRefPtr<AccessibilityTextMarker> AccessibilityTextMarker::create(const AccessibilityTextMarker& marker) +Ref<AccessibilityTextMarker> AccessibilityTextMarker::create(const AccessibilityTextMarker& marker) { - return adoptRef(new AccessibilityTextMarker(marker)); + return adoptRef(*new AccessibilityTextMarker(marker)); } AccessibilityTextMarker::AccessibilityTextMarker(PlatformTextMarker marker) @@ -60,7 +60,7 @@ AccessibilityTextMarker::~AccessibilityTextMarker() PlatformTextMarker AccessibilityTextMarker::platformTextMarker() const { -#if PLATFORM(MAC) +#if PLATFORM(COCOA) return m_textMarker.get(); #else return m_textMarker; diff --git a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarker.h b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarker.h index c4d4d0481..041f81bc7 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarker.h +++ b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarker.h @@ -23,15 +23,14 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef AccessibilityTextMarker_h -#define AccessibilityTextMarker_h +#pragma once #include "JSWrappable.h" #include <JavaScriptCore/JSObjectRef.h> -#include <wtf/PassRefPtr.h> #include <wtf/Platform.h> +#include <wtf/Ref.h> -#if PLATFORM(MAC) +#if PLATFORM(COCOA) #include <wtf/RetainPtr.h> typedef CFTypeRef PlatformTextMarker; #else @@ -44,8 +43,8 @@ class AccessibilityUIElement; class AccessibilityTextMarker : public JSWrappable { public: - static PassRefPtr<AccessibilityTextMarker> create(PlatformTextMarker); - static PassRefPtr<AccessibilityTextMarker> create(const AccessibilityTextMarker&); + static Ref<AccessibilityTextMarker> create(PlatformTextMarker); + static Ref<AccessibilityTextMarker> create(const AccessibilityTextMarker&); ~AccessibilityTextMarker(); @@ -59,17 +58,15 @@ private: AccessibilityTextMarker(PlatformTextMarker); AccessibilityTextMarker(const AccessibilityTextMarker&); -#if PLATFORM(MAC) +#if PLATFORM(COCOA) RetainPtr<PlatformTextMarker> m_textMarker; #else PlatformTextMarker m_textMarker; #endif }; -#if !PLATFORM(MAC) +#if !PLATFORM(COCOA) inline bool AccessibilityTextMarker::isEqual(AccessibilityTextMarker*) { return false; } #endif } // namespace WTR - -#endif // AccessibilityTextMarker_h diff --git a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarkerRange.cpp b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarkerRange.cpp index 3613f3728..7444f3522 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarkerRange.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarkerRange.cpp @@ -33,14 +33,14 @@ namespace WTR { -PassRefPtr<AccessibilityTextMarkerRange> AccessibilityTextMarkerRange::create(PlatformTextMarkerRange markerRange) +Ref<AccessibilityTextMarkerRange> AccessibilityTextMarkerRange::create(PlatformTextMarkerRange markerRange) { - return adoptRef(new AccessibilityTextMarkerRange(markerRange)); + return adoptRef(*new AccessibilityTextMarkerRange(markerRange)); } -PassRefPtr<AccessibilityTextMarkerRange> AccessibilityTextMarkerRange::create(const AccessibilityTextMarkerRange& markerRange) +Ref<AccessibilityTextMarkerRange> AccessibilityTextMarkerRange::create(const AccessibilityTextMarkerRange& markerRange) { - return adoptRef(new AccessibilityTextMarkerRange(markerRange)); + return adoptRef(*new AccessibilityTextMarkerRange(markerRange)); } AccessibilityTextMarkerRange::AccessibilityTextMarkerRange(PlatformTextMarkerRange markerRange) @@ -60,7 +60,7 @@ AccessibilityTextMarkerRange::~AccessibilityTextMarkerRange() PlatformTextMarkerRange AccessibilityTextMarkerRange::platformTextMarkerRange() const { -#if PLATFORM(MAC) +#if PLATFORM(COCOA) return m_textMarkerRange.get(); #else return m_textMarkerRange; diff --git a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarkerRange.h b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarkerRange.h index e57a29cd7..18c18d48e 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarkerRange.h +++ b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityTextMarkerRange.h @@ -23,15 +23,14 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef AccessibilityTextMarkerRange_h -#define AccessibilityTextMarkerRange_h +#pragma once #include "JSWrappable.h" #include <JavaScriptCore/JSObjectRef.h> -#include <wtf/PassRefPtr.h> #include <wtf/Platform.h> +#include <wtf/Ref.h> -#if PLATFORM(MAC) +#if PLATFORM(COCOA) #include <wtf/RetainPtr.h> typedef CFTypeRef PlatformTextMarkerRange; #else @@ -42,8 +41,8 @@ namespace WTR { class AccessibilityTextMarkerRange : public JSWrappable { public: - static PassRefPtr<AccessibilityTextMarkerRange> create(PlatformTextMarkerRange); - static PassRefPtr<AccessibilityTextMarkerRange> create(const AccessibilityTextMarkerRange&); + static Ref<AccessibilityTextMarkerRange> create(PlatformTextMarkerRange); + static Ref<AccessibilityTextMarkerRange> create(const AccessibilityTextMarkerRange&); ~AccessibilityTextMarkerRange(); @@ -57,17 +56,15 @@ private: AccessibilityTextMarkerRange(PlatformTextMarkerRange); AccessibilityTextMarkerRange(const AccessibilityTextMarkerRange&); -#if PLATFORM(MAC) +#if PLATFORM(COCOA) RetainPtr<PlatformTextMarkerRange> m_textMarkerRange; #else PlatformTextMarkerRange m_textMarkerRange; #endif }; -#if !PLATFORM(MAC) +#if !PLATFORM(COCOA) inline bool AccessibilityTextMarkerRange::isEqual(AccessibilityTextMarkerRange*) { return false; } #endif } // namespace WTR - -#endif // AccessibilityTextMarkerRange_h diff --git a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp index 00e965ff3..233ff7d20 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp @@ -31,14 +31,14 @@ namespace WTR { -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::create(PlatformUIElement uiElement) +Ref<AccessibilityUIElement> AccessibilityUIElement::create(PlatformUIElement uiElement) { - return adoptRef(new AccessibilityUIElement(uiElement)); + return adoptRef(*new AccessibilityUIElement(uiElement)); } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::create(const AccessibilityUIElement& uiElement) +Ref<AccessibilityUIElement> AccessibilityUIElement::create(const AccessibilityUIElement& uiElement) { - return adoptRef(new AccessibilityUIElement(uiElement)); + return adoptRef(*new AccessibilityUIElement(uiElement)); } JSClassRef AccessibilityUIElement::wrapperClass() @@ -53,154 +53,55 @@ bool AccessibilityUIElement::isValid() const return m_element; } +// iOS specific methods +#if !PLATFORM(IOS) +JSRetainPtr<JSStringRef> AccessibilityUIElement::identifier() { return nullptr; } +JSRetainPtr<JSStringRef> AccessibilityUIElement::traits() { return nullptr; } +int AccessibilityUIElement::elementTextPosition() { return 0; } +int AccessibilityUIElement::elementTextLength() { return 0; } +JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForSelection() { return nullptr; } +JSValueRef AccessibilityUIElement::elementsForRange(unsigned, unsigned) { return nullptr; } +void AccessibilityUIElement::increaseTextSelection() { } +void AccessibilityUIElement::decreaseTextSelection() { } +RefPtr<AccessibilityUIElement> AccessibilityUIElement::linkedElement() { return nullptr; } +RefPtr<AccessibilityUIElement> AccessibilityUIElement::headerElementAtIndex(unsigned) { return nullptr; } +void AccessibilityUIElement::assistiveTechnologySimulatedFocus() { return; } +bool AccessibilityUIElement::scrollPageUp() { return false; } +bool AccessibilityUIElement::scrollPageDown() { return false; } +bool AccessibilityUIElement::scrollPageLeft() { return false; } +bool AccessibilityUIElement::scrollPageRight() { return false; } +bool AccessibilityUIElement::hasContainedByFieldsetTrait() { return false; } +RefPtr<AccessibilityUIElement> AccessibilityUIElement::fieldsetAncestorElement() { return nullptr; } +bool AccessibilityUIElement::isSearchField() const { return false; } +bool AccessibilityUIElement::isTextArea() const { return false; } + +#endif + // Unsupported methods on various platforms. As they're implemented on other platforms this list should be modified. #if (!PLATFORM(GTK) && !PLATFORM(EFL)) || !HAVE(ACCESSIBILITY) -JSRetainPtr<JSStringRef> AccessibilityUIElement::characterAtOffset(int) { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::wordAtOffset(int) { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::lineAtOffset(int) { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::sentenceAtOffset(int) { return 0; } +JSRetainPtr<JSStringRef> AccessibilityUIElement::characterAtOffset(int) { return nullptr; } +JSRetainPtr<JSStringRef> AccessibilityUIElement::wordAtOffset(int) { return nullptr; } +JSRetainPtr<JSStringRef> AccessibilityUIElement::lineAtOffset(int) { return nullptr; } +JSRetainPtr<JSStringRef> AccessibilityUIElement::sentenceAtOffset(int) { return nullptr; } #endif -#if (!PLATFORM(MAC) && !PLATFORM(GTK) && !PLATFORM(EFL)) || !HAVE(ACCESSIBILITY) -AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement) { } -AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement&) { } -AccessibilityUIElement::~AccessibilityUIElement() { } -bool AccessibilityUIElement::isEqual(AccessibilityUIElement*) { return false; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::elementAtPoint(int, int) { return 0; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::childAtIndex(unsigned) { return 0; } -unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement*) { return 0; } -int AccessibilityUIElement::childrenCount() { return 0; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::titleUIElement() { return 0; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::parentElement() { return 0; } -void AccessibilityUIElement::takeFocus() { } -void AccessibilityUIElement::takeSelection() { } -void AccessibilityUIElement::addSelection() { } -void AccessibilityUIElement::removeSelection() { } -JSRetainPtr<JSStringRef> AccessibilityUIElement::allAttributes() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfLinkedUIElements() { return 0; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::linkedUIElementAtIndex(unsigned) { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfDocumentLinks() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfChildren() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::parameterizedAttributeNames() { return 0; } -void AccessibilityUIElement::increment() { } -void AccessibilityUIElement::decrement() { } -void AccessibilityUIElement::showMenu() { } -void AccessibilityUIElement::press() { } -JSRetainPtr<JSStringRef> AccessibilityUIElement::stringAttributeValue(JSStringRef) { return 0; } -JSValueRef AccessibilityUIElement::uiElementArrayAttributeValue(JSStringRef) const { return nullptr; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementAttributeValue(JSStringRef) const { return 0; } -double AccessibilityUIElement::numberAttributeValue(JSStringRef) { return 0; } -bool AccessibilityUIElement::boolAttributeValue(JSStringRef) { return false; } -bool AccessibilityUIElement::isAttributeSupported(JSStringRef) { return false; } -bool AccessibilityUIElement::isAttributeSettable(JSStringRef) { return false; } -bool AccessibilityUIElement::isPressActionSupported() { return false; } -bool AccessibilityUIElement::isIncrementActionSupported() { return false; } -bool AccessibilityUIElement::isDecrementActionSupported() { return false; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::role() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::subrole() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::roleDescription() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::title() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::description() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::language() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::stringValue() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::accessibilityValue() const { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::helpText() const { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::orientation() const { return 0; } -double AccessibilityUIElement::x() { return 0; } -double AccessibilityUIElement::y() { return 0; } -double AccessibilityUIElement::width() { return 0; } -double AccessibilityUIElement::height() { return 0; } -double AccessibilityUIElement::intValue() const { return 0; } -double AccessibilityUIElement::minValue() { return 0; } -double AccessibilityUIElement::maxValue() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::valueDescription() { return 0; } -int AccessibilityUIElement::insertionPointLineNumber() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::selectedTextRange() { return 0; } -bool AccessibilityUIElement::isEnabled() { return false; } -bool AccessibilityUIElement::isRequired() const { return false; } -bool AccessibilityUIElement::isFocused() const { return false; } -bool AccessibilityUIElement::isFocusable() const { return false; } -bool AccessibilityUIElement::isSelected() const { return false; } -bool AccessibilityUIElement::isSelectedOptionActive() const { return false; } -bool AccessibilityUIElement::isSelectable() const { return false; } -bool AccessibilityUIElement::isMultiSelectable() const { return false; } -void AccessibilityUIElement::setSelectedChild(AccessibilityUIElement*) const { } -unsigned AccessibilityUIElement::selectedChildrenCount() const { return 0; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedChildAtIndex(unsigned) const { return 0; } -bool AccessibilityUIElement::isExpanded() const { return false; } -bool AccessibilityUIElement::isChecked() const { return false; } -bool AccessibilityUIElement::isIndeterminate() const { return false; } -bool AccessibilityUIElement::isVisible() const { return false; } -bool AccessibilityUIElement::isOffScreen() const { return false; } -bool AccessibilityUIElement::isCollapsed() const { return false; } -bool AccessibilityUIElement::isIgnored() const { return false; } -bool AccessibilityUIElement::hasPopup() const { return false; } -int AccessibilityUIElement::hierarchicalLevel() const { return 0; } -double AccessibilityUIElement::clickPointX() { return 0; } -double AccessibilityUIElement::clickPointY() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::documentEncoding() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::documentURI() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::url() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::speak() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfColumnHeaders() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfRowHeaders() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfColumns() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfRows() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfVisibleCells() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfHeader() { return 0; } -int AccessibilityUIElement::indexInTable() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::rowIndexRange() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::columnIndexRange() { return 0; } -int AccessibilityUIElement::rowCount() { return 0; } -int AccessibilityUIElement::columnCount() { return 0; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedRowAtIndex(unsigned) { return 0; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedByRow() { return 0; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedRowAtIndex(unsigned) { return 0; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::rowAtIndex(unsigned) { return 0; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned) { return 0; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned) { return 0; } -bool AccessibilityUIElement::ariaIsGrabbed() const { return false; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::ariaDropEffects() const { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::classList() const { return 0; } -int AccessibilityUIElement::lineForIndex(int) { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForLine(int) { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForPosition(int, int) { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::boundsForRange(unsigned, unsigned) { return 0; } -bool AccessibilityUIElement::setSelectedTextRange(unsigned, unsigned) { return false; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForRange(unsigned, unsigned) { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::attributedStringForRange(unsigned, unsigned) { return 0; } -bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned, unsigned) { return false; } -unsigned AccessibilityUIElement::uiElementCountForSearchPredicate(JSContextRef, AccessibilityUIElement*, bool, JSValueRef, JSStringRef, bool) { return 0; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef, AccessibilityUIElement*, bool, JSValueRef, JSStringRef, bool) { return 0; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::cellForColumnAndRow(unsigned, unsigned) { return 0; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::horizontalScrollbar() const { return 0; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::verticalScrollbar() const { return 0; } -bool AccessibilityUIElement::addNotificationListener(JSValueRef) { return false; } -bool AccessibilityUIElement::removeNotificationListener() { return false; } -PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForElement(AccessibilityUIElement*) { return 0; } -int AccessibilityUIElement::textMarkerRangeLength(AccessibilityTextMarkerRange*) { return 0; } -PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForMarkers(AccessibilityTextMarker*, AccessibilityTextMarker*) { return 0; } -PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange*) { return 0; } -PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange*) { return 0; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::accessibilityElementForTextMarker(AccessibilityTextMarker*) { return 0; } -PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForBounds(int x, int y, int width, int height) { return 0; } -PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForBounds(int x, int y, int width, int height) { return 0; } -PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForPoint(int, int) { return 0; } -PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousTextMarker(AccessibilityTextMarker*) { return 0; } -PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextTextMarker(AccessibilityTextMarker*) { return 0; } -PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarker() { return 0; } -PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarker() { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForTextMarkerRange(AccessibilityTextMarkerRange*) { return 0; } -bool AccessibilityUIElement::attributedStringForTextMarkerRangeContainsAttribute(JSStringRef, AccessibilityTextMarkerRange*) { return false; } -int AccessibilityUIElement::indexForTextMarker(AccessibilityTextMarker*) { return -1; } -bool AccessibilityUIElement::isTextMarkerValid(AccessibilityTextMarker*) { return false; } -PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForIndex(int) { return 0; } -void AccessibilityUIElement::scrollToMakeVisible() { } -JSRetainPtr<JSStringRef> AccessibilityUIElement::supportedActions() const { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::mathPostscriptsDescription() const { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::mathPrescriptsDescription() const { return 0; } -JSRetainPtr<JSStringRef> AccessibilityUIElement::pathDescription() const { return 0; } +#if !PLATFORM(MAC) || !HAVE(ACCESSIBILITY) +RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::selectedTextMarkerRange() { return nullptr; } +void AccessibilityUIElement::resetSelectedTextMarkerRange() { } +void AccessibilityUIElement::setBoolAttributeValue(JSStringRef, bool) { } +#endif +#if !PLATFORM(COCOA) || !HAVE(ACCESSIBILITY) +RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*) { return nullptr; } +RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*) { return nullptr; } +RefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*) { return nullptr; } +RefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*) { return nullptr; } +RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker(AccessibilityTextMarker*) { return nullptr; } +RefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker(AccessibilityTextMarker*) { return nullptr; } +RefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker(AccessibilityTextMarker*) { return nullptr; } +RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::sentenceTextMarkerRangeForTextMarker(AccessibilityTextMarker*) { return nullptr; } +RefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextSentenceEndTextMarkerForTextMarker(AccessibilityTextMarker*) { return nullptr; } +RefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousSentenceStartTextMarkerForTextMarker(AccessibilityTextMarker*) { return nullptr; } #endif } // namespace WTR diff --git a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h index 807b82446..5509af217 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h +++ b/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h @@ -23,8 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef AccessibilityUIElement_h -#define AccessibilityUIElement_h +#pragma once #include "AccessibilityTextMarker.h" #include "AccessibilityTextMarkerRange.h" @@ -35,7 +34,7 @@ #include <wtf/Platform.h> #include <wtf/Vector.h> -#if PLATFORM(MAC) +#if PLATFORM(COCOA) #ifdef __OBJC__ typedef id PlatformUIElement; #else @@ -44,13 +43,13 @@ typedef struct objc_object* PlatformUIElement; #elif HAVE(ACCESSIBILITY) && (PLATFORM(GTK) || PLATFORM(EFL)) #include "AccessibilityNotificationHandlerAtk.h" #include <atk/atk.h> -#include <wtf/gobject/GRefPtr.h> +#include <wtf/glib/GRefPtr.h> typedef GRefPtr<AtkObject> PlatformUIElement; #else typedef void* PlatformUIElement; #endif -#if PLATFORM(MAC) +#if PLATFORM(COCOA) #ifdef __OBJC__ typedef id NotificationHandler; #else @@ -62,8 +61,8 @@ namespace WTR { class AccessibilityUIElement : public JSWrappable { public: - static PassRefPtr<AccessibilityUIElement> create(PlatformUIElement); - static PassRefPtr<AccessibilityUIElement> create(const AccessibilityUIElement&); + static Ref<AccessibilityUIElement> create(PlatformUIElement); + static Ref<AccessibilityUIElement> create(const AccessibilityUIElement&); ~AccessibilityUIElement(); @@ -74,12 +73,12 @@ public: bool isEqual(AccessibilityUIElement* otherElement); - PassRefPtr<AccessibilityUIElement> elementAtPoint(int x, int y); - PassRefPtr<AccessibilityUIElement> childAtIndex(unsigned); + RefPtr<AccessibilityUIElement> elementAtPoint(int x, int y); + RefPtr<AccessibilityUIElement> childAtIndex(unsigned); unsigned indexOfChild(AccessibilityUIElement*); int childrenCount(); - PassRefPtr<AccessibilityUIElement> titleUIElement(); - PassRefPtr<AccessibilityUIElement> parentElement(); + RefPtr<AccessibilityUIElement> titleUIElement(); + RefPtr<AccessibilityUIElement> parentElement(); void takeFocus(); void takeSelection(); @@ -89,7 +88,7 @@ public: // Methods - platform-independent implementations JSRetainPtr<JSStringRef> allAttributes(); JSRetainPtr<JSStringRef> attributesOfLinkedUIElements(); - PassRefPtr<AccessibilityUIElement> linkedUIElementAtIndex(unsigned); + RefPtr<AccessibilityUIElement> linkedUIElementAtIndex(unsigned); JSRetainPtr<JSStringRef> attributesOfDocumentLinks(); JSRetainPtr<JSStringRef> attributesOfChildren(); @@ -103,8 +102,9 @@ public: JSRetainPtr<JSStringRef> stringAttributeValue(JSStringRef attribute); double numberAttributeValue(JSStringRef attribute); JSValueRef uiElementArrayAttributeValue(JSStringRef attribute) const; - PassRefPtr<AccessibilityUIElement> uiElementAttributeValue(JSStringRef attribute) const; + RefPtr<AccessibilityUIElement> uiElementAttributeValue(JSStringRef attribute) const; bool boolAttributeValue(JSStringRef attribute); + void setBoolAttributeValue(JSStringRef attribute, bool value); bool isAttributeSupported(JSStringRef attribute); bool isAttributeSettable(JSStringRef attribute); bool isPressActionSupported(); @@ -113,6 +113,7 @@ public: JSRetainPtr<JSStringRef> role(); JSRetainPtr<JSStringRef> subrole(); JSRetainPtr<JSStringRef> roleDescription(); + JSRetainPtr<JSStringRef> computedRoleString(); JSRetainPtr<JSStringRef> title(); JSRetainPtr<JSStringRef> description(); JSRetainPtr<JSStringRef> language(); @@ -140,8 +141,11 @@ public: bool isSelectable() const; bool isMultiSelectable() const; void setSelectedChild(AccessibilityUIElement*) const; + void setSelectedChildAtIndex(unsigned) const; + void removeSelectionAtIndex(unsigned) const; + void clearSelectedChildren() const; unsigned selectedChildrenCount() const; - PassRefPtr<AccessibilityUIElement> selectedChildAtIndex(unsigned) const; + RefPtr<AccessibilityUIElement> selectedChildAtIndex(unsigned) const; bool isValid() const; bool isExpanded() const; @@ -151,6 +155,8 @@ public: bool isOffScreen() const; bool isCollapsed() const; bool isIgnored() const; + bool isSingleLine() const; + bool isMultiLine() const; bool hasPopup() const; int hierarchicalLevel() const; double clickPointX(); @@ -179,14 +185,15 @@ public: JSValueRef columnHeaders() const; // Tree/Outline specific attributes - PassRefPtr<AccessibilityUIElement> selectedRowAtIndex(unsigned); - PassRefPtr<AccessibilityUIElement> disclosedByRow(); - PassRefPtr<AccessibilityUIElement> disclosedRowAtIndex(unsigned); - PassRefPtr<AccessibilityUIElement> rowAtIndex(unsigned); + RefPtr<AccessibilityUIElement> selectedRowAtIndex(unsigned); + RefPtr<AccessibilityUIElement> disclosedByRow(); + RefPtr<AccessibilityUIElement> disclosedRowAtIndex(unsigned); + RefPtr<AccessibilityUIElement> rowAtIndex(unsigned); // ARIA specific - PassRefPtr<AccessibilityUIElement> ariaOwnsElementAtIndex(unsigned); - PassRefPtr<AccessibilityUIElement> ariaFlowToElementAtIndex(unsigned); + RefPtr<AccessibilityUIElement> ariaOwnsElementAtIndex(unsigned); + RefPtr<AccessibilityUIElement> ariaFlowToElementAtIndex(unsigned); + RefPtr<AccessibilityUIElement> ariaControlsElementAtIndex(unsigned); // ARIA Drag and Drop bool ariaIsGrabbed() const; @@ -202,8 +209,9 @@ public: JSRetainPtr<JSStringRef> stringForRange(unsigned location, unsigned length); JSRetainPtr<JSStringRef> attributedStringForRange(unsigned location, unsigned length); bool attributedStringRangeIsMisspelled(unsigned location, unsigned length); - unsigned uiElementCountForSearchPredicate(JSContextRef, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly); - PassRefPtr<AccessibilityUIElement> uiElementForSearchPredicate(JSContextRef, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly); + unsigned uiElementCountForSearchPredicate(JSContextRef, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly); + RefPtr<AccessibilityUIElement> uiElementForSearchPredicate(JSContextRef, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly); + JSRetainPtr<JSStringRef> selectTextWithCriteria(JSContextRef, JSStringRef ambiguityResolution, JSValueRef searchStrings, JSStringRef replacementString, JSStringRef activity); // Text-specific JSRetainPtr<JSStringRef> characterAtOffset(int offset); @@ -212,33 +220,49 @@ public: JSRetainPtr<JSStringRef> sentenceAtOffset(int offset); // Table-specific - PassRefPtr<AccessibilityUIElement> cellForColumnAndRow(unsigned column, unsigned row); + RefPtr<AccessibilityUIElement> cellForColumnAndRow(unsigned column, unsigned row); // Scrollarea-specific - PassRefPtr<AccessibilityUIElement> horizontalScrollbar() const; - PassRefPtr<AccessibilityUIElement> verticalScrollbar() const; + RefPtr<AccessibilityUIElement> horizontalScrollbar() const; + RefPtr<AccessibilityUIElement> verticalScrollbar() const; void scrollToMakeVisible(); + void scrollToGlobalPoint(int x, int y); + void scrollToMakeVisibleWithSubFocus(int x, int y, int width, int height); // Text markers. - PassRefPtr<AccessibilityTextMarkerRange> textMarkerRangeForElement(AccessibilityUIElement*); - PassRefPtr<AccessibilityTextMarkerRange> textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker); - PassRefPtr<AccessibilityTextMarker> startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange*); - PassRefPtr<AccessibilityTextMarker> endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange*); - PassRefPtr<AccessibilityTextMarker> endTextMarkerForBounds(int x, int y, int width, int height); - PassRefPtr<AccessibilityTextMarker> startTextMarkerForBounds(int x, int y, int width, int height); - PassRefPtr<AccessibilityTextMarker> textMarkerForPoint(int x, int y); - PassRefPtr<AccessibilityTextMarker> previousTextMarker(AccessibilityTextMarker*); - PassRefPtr<AccessibilityTextMarker> nextTextMarker(AccessibilityTextMarker*); - PassRefPtr<AccessibilityUIElement> accessibilityElementForTextMarker(AccessibilityTextMarker*); + RefPtr<AccessibilityTextMarkerRange> lineTextMarkerRangeForTextMarker(AccessibilityTextMarker*); + RefPtr<AccessibilityTextMarkerRange> textMarkerRangeForElement(AccessibilityUIElement*); + RefPtr<AccessibilityTextMarkerRange> textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker); + RefPtr<AccessibilityTextMarkerRange> selectedTextMarkerRange(); + void resetSelectedTextMarkerRange(); + RefPtr<AccessibilityTextMarker> startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange*); + RefPtr<AccessibilityTextMarker> endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange*); + RefPtr<AccessibilityTextMarker> endTextMarkerForBounds(int x, int y, int width, int height); + RefPtr<AccessibilityTextMarker> startTextMarkerForBounds(int x, int y, int width, int height); + RefPtr<AccessibilityTextMarker> textMarkerForPoint(int x, int y); + RefPtr<AccessibilityTextMarker> previousTextMarker(AccessibilityTextMarker*); + RefPtr<AccessibilityTextMarker> nextTextMarker(AccessibilityTextMarker*); + RefPtr<AccessibilityUIElement> accessibilityElementForTextMarker(AccessibilityTextMarker*); JSRetainPtr<JSStringRef> stringForTextMarkerRange(AccessibilityTextMarkerRange*); int textMarkerRangeLength(AccessibilityTextMarkerRange*); bool attributedStringForTextMarkerRangeContainsAttribute(JSStringRef, AccessibilityTextMarkerRange*); int indexForTextMarker(AccessibilityTextMarker*); bool isTextMarkerValid(AccessibilityTextMarker*); - PassRefPtr<AccessibilityTextMarker> textMarkerForIndex(int); - PassRefPtr<AccessibilityTextMarker> startTextMarker(); - PassRefPtr<AccessibilityTextMarker> endTextMarker(); + RefPtr<AccessibilityTextMarker> textMarkerForIndex(int); + RefPtr<AccessibilityTextMarker> startTextMarker(); + RefPtr<AccessibilityTextMarker> endTextMarker(); + bool setSelectedVisibleTextRange(AccessibilityTextMarkerRange*); + RefPtr<AccessibilityTextMarkerRange> leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*); + RefPtr<AccessibilityTextMarkerRange> rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*); + RefPtr<AccessibilityTextMarker> previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*); + RefPtr<AccessibilityTextMarker> nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*); + RefPtr<AccessibilityTextMarkerRange> paragraphTextMarkerRangeForTextMarker(AccessibilityTextMarker*); + RefPtr<AccessibilityTextMarker> nextParagraphEndTextMarkerForTextMarker(AccessibilityTextMarker*); + RefPtr<AccessibilityTextMarker> previousParagraphStartTextMarkerForTextMarker(AccessibilityTextMarker*); + RefPtr<AccessibilityTextMarkerRange> sentenceTextMarkerRangeForTextMarker(AccessibilityTextMarker*); + RefPtr<AccessibilityTextMarker> nextSentenceEndTextMarkerForTextMarker(AccessibilityTextMarker*); + RefPtr<AccessibilityTextMarker> previousSentenceStartTextMarkerForTextMarker(AccessibilityTextMarker*); // Returns an ordered list of supported actions for an element. JSRetainPtr<JSStringRef> supportedActions() const; @@ -253,6 +277,29 @@ public: // Make sure you call remove, because you can't rely on objects being deallocated in a timely fashion. bool removeNotificationListener(); + JSRetainPtr<JSStringRef> identifier(); + JSRetainPtr<JSStringRef> traits(); + int elementTextPosition(); + int elementTextLength(); + JSRetainPtr<JSStringRef> stringForSelection(); + JSValueRef elementsForRange(unsigned location, unsigned length); + void increaseTextSelection(); + void decreaseTextSelection(); + RefPtr<AccessibilityUIElement> linkedElement(); + RefPtr<AccessibilityUIElement> headerElementAtIndex(unsigned index); + void assistiveTechnologySimulatedFocus(); + bool isSearchField() const; + bool isTextArea() const; + + bool scrollPageUp(); + bool scrollPageDown(); + bool scrollPageLeft(); + bool scrollPageRight(); + + // Fieldset + bool hasContainedByFieldsetTrait(); + RefPtr<AccessibilityUIElement> fieldsetAncestorElement(); + private: AccessibilityUIElement(PlatformUIElement); AccessibilityUIElement(const AccessibilityUIElement&); @@ -261,7 +308,7 @@ private: // A retained, platform specific object used to help manage notifications for this object. #if HAVE(ACCESSIBILITY) -#if PLATFORM(MAC) +#if PLATFORM(COCOA) NotificationHandler m_notificationHandler; void getLinkedUIElements(Vector<RefPtr<AccessibilityUIElement> >&); @@ -270,7 +317,7 @@ private: void getUIElementsWithAttribute(JSStringRef, Vector<RefPtr<AccessibilityUIElement> >&) const; #endif -#if PLATFORM(MAC) || PLATFORM(GTK) || PLATFORM(EFL) +#if PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(EFL) void getChildren(Vector<RefPtr<AccessibilityUIElement> >&); void getChildrenWithRange(Vector<RefPtr<AccessibilityUIElement> >&, unsigned location, unsigned length); #endif @@ -282,5 +329,3 @@ private: }; } // namespace WTR - -#endif // AccessibilityUIElement_h diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityController.idl b/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityController.idl new file mode 100644 index 000000000..d50a2033f --- /dev/null +++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityController.idl @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +interface AccessibilityController { + void enableEnhancedAccessibility(boolean enable); + readonly attribute boolean enhancedAccessibilityEnabled; + + readonly attribute DOMString platformName; + readonly attribute AccessibilityUIElement rootElement; + readonly attribute AccessibilityUIElement focusedElement; + AccessibilityUIElement elementAtPoint(long x, long y); + AccessibilityUIElement accessibleElementById(DOMString id); + + boolean addNotificationListener(object functionCallback); + boolean removeNotificationListener(); + + void logFocusEvents(); + void logValueChangeEvents(); + void logScrollingStartEvents(); + void logAccessibilityEvents(); + void resetToConsistentState(); +}; + diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityTextMarker.idl b/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityTextMarker.idl new file mode 100644 index 000000000..149c95f34 --- /dev/null +++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityTextMarker.idl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +interface AccessibilityTextMarker { + boolean isEqual(AccessibilityTextMarker otherMarker); +}; + diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityTextMarkerRange.idl b/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityTextMarkerRange.idl new file mode 100644 index 000000000..962c584e6 --- /dev/null +++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityTextMarkerRange.idl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +interface AccessibilityTextMarkerRange { + boolean isEqual(AccessibilityTextMarkerRange otherMarkerRange); +}; + diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl b/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl new file mode 100644 index 000000000..967cb975d --- /dev/null +++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +interface AccessibilityUIElement { + boolean isEqual(AccessibilityUIElement otherElement); + + // Document information + readonly attribute DOMString documentEncoding; + readonly attribute DOMString documentURI; + + // Element access. + AccessibilityUIElement elementAtPoint(long x, long y); + AccessibilityUIElement childAtIndex(unsigned long index); + unsigned long indexOfChild(AccessibilityUIElement child); + AccessibilityUIElement linkedUIElementAtIndex(unsigned long index); + AccessibilityUIElement selectedChildAtIndex(unsigned long index); + void setSelectedChild(AccessibilityUIElement element); + void setSelectedChildAtIndex(unsigned long index); + void removeSelectionAtIndex(unsigned long index); + void clearSelectedChildren(); + AccessibilityUIElement titleUIElement(); + AccessibilityUIElement parentElement(); + + readonly attribute DOMString role; + readonly attribute DOMString subrole; + readonly attribute DOMString roleDescription; + readonly attribute DOMString computedRoleString; + readonly attribute DOMString title; + readonly attribute DOMString description; + readonly attribute DOMString language; + readonly attribute DOMString helpText; + readonly attribute DOMString valueDescription; + readonly attribute DOMString url; + readonly attribute DOMString speak; + readonly attribute DOMString orientation; + readonly attribute long insertionPointLineNumber; + readonly attribute DOMString selectedTextRange; + + DOMString stringAttributeValue(DOMString attr); + double numberAttributeValue(DOMString attr); + object uiElementArrayAttributeValue(DOMString attr); + AccessibilityUIElement uiElementAttributeValue(DOMString attr); + boolean boolAttributeValue(DOMString attr); + void setBoolAttributeValue(DOMString attr, boolean value); + boolean isAttributeSupported(DOMString attr); + boolean isAttributeSettable(DOMString attr); + boolean isPressActionSupported(); + boolean isIncrementActionSupported(); + boolean isDecrementActionSupported(); + + readonly attribute DOMString stringValue; + readonly attribute long intValue; + readonly attribute long minValue; + readonly attribute long maxValue; + + readonly attribute boolean isEnabled; + readonly attribute boolean isRequired; + readonly attribute boolean isFocused; + readonly attribute boolean isFocusable; + readonly attribute boolean isSelectable; + readonly attribute boolean isSelected; + readonly attribute boolean isSelectedOptionActive; + readonly attribute boolean isMultiSelectable; + readonly attribute boolean isExpanded; + readonly attribute boolean isChecked; + readonly attribute boolean isIndeterminate; + readonly attribute boolean isVisible; + readonly attribute boolean isCollapsed; + readonly attribute boolean hasPopup; + readonly attribute boolean isIgnored; + readonly attribute boolean isSingleLine; + readonly attribute boolean isMultiLine; + readonly attribute boolean isOffScreen; + readonly attribute boolean isValid; + readonly attribute long hierarchicalLevel; + readonly attribute boolean ariaIsGrabbed; + readonly attribute DOMString ariaDropEffects; + readonly attribute DOMString classList; + + readonly attribute long x; + readonly attribute long y; + readonly attribute long width; + readonly attribute long height; + readonly attribute long clickPointX; + readonly attribute long clickPointY; + + readonly attribute long childrenCount; + readonly attribute long selectedChildrenCount; + readonly attribute long rowCount; + readonly attribute long columnCount; + + // Actions. + void increment(); + void decrement(); + void press(); + void showMenu(); + + // Attribute info. + DOMString allAttributes(); + DOMString attributesOfChildren(); + DOMString attributesOfLinkedUIElements(); + DOMString attributesOfDocumentLinks(); + + // Text info. + DOMString characterAtOffset(long offset); + DOMString wordAtOffset(long offset); + DOMString lineAtOffset(long offset); + DOMString sentenceAtOffset(long offset); + + // Table info. + DOMString attributesOfColumnHeaders(); + DOMString attributesOfRowHeaders(); + DOMString attributesOfColumns(); + DOMString attributesOfRows(); + DOMString attributesOfVisibleCells(); + DOMString attributesOfHeader(); + AccessibilityUIElement cellForColumnAndRow(unsigned long column, unsigned long row); + AccessibilityUIElement selectedRowAtIndex(unsigned long index); + AccessibilityUIElement disclosedByRow(); + AccessibilityUIElement disclosedRowAtIndex(unsigned long index); + AccessibilityUIElement rowAtIndex(unsigned long index); + long indexInTable(); + DOMString rowIndexRange(); + DOMString columnIndexRange(); + long rowCount(); + long columnCount(); + object columnHeaders(); + object rowHeaders(); + + AccessibilityUIElement ariaOwnsElementAtIndex(unsigned long index); + AccessibilityUIElement ariaFlowToElementAtIndex(unsigned long index); + AccessibilityUIElement ariaControlsElementAtIndex(unsigned long index); + + // Paramaterized attributes. + DOMString parameterizedAttributeNames(); + long lineForIndex(long index); + DOMString rangeForLine(long index); + DOMString rangeForPosition(long x, long y); + DOMString boundsForRange(unsigned long location, unsigned long length); + DOMString stringForRange(unsigned long location, unsigned long length); + DOMString attributedStringForRange(unsigned long location, unsigned long length); + boolean attributedStringRangeIsMisspelled(unsigned long location, unsigned long length); + [PassContext] unsigned long uiElementCountForSearchPredicate(AccessibilityUIElement startElement, boolean isDirectionNext, object searchKey, DOMString searchText, boolean visibleOnly, boolean immediateDescendantsOnly); + [PassContext] AccessibilityUIElement uiElementForSearchPredicate(AccessibilityUIElement startElement, boolean isDirectionNext, object searchKey, DOMString searchText, boolean visibleOnly, boolean immediateDescendantsOnly); + [PassContext] DOMString selectTextWithCriteria(DOMString ambiguityResolution, object searchStrings, DOMString replacementString, DOMString activity); + boolean setSelectedTextRange(unsigned long location, unsigned long length); + + // Scroll area attributes. + readonly attribute AccessibilityUIElement horizontalScrollbar; + readonly attribute AccessibilityUIElement verticalScrollbar; + + void scrollToMakeVisible(); + void scrollToGlobalPoint(long x, long y); + void scrollToMakeVisibleWithSubFocus(long x, long y, long width, long height); + + void takeFocus(); + boolean scrollPageDown(); + boolean scrollPageUp(); + boolean scrollPageLeft(); + boolean scrollPageRight(); + + // Text markers. + AccessibilityTextMarkerRange lineTextMarkerRangeForTextMarker(AccessibilityTextMarker textMarker); + AccessibilityTextMarkerRange textMarkerRangeForElement(AccessibilityUIElement element); + AccessibilityTextMarkerRange textMarkerRangeForMarkers(AccessibilityTextMarker startMarker, AccessibilityTextMarker endMarker); + AccessibilityTextMarkerRange selectedTextMarkerRange(); + void resetSelectedTextMarkerRange(); + AccessibilityTextMarker startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange range); + AccessibilityTextMarker endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange range); + AccessibilityTextMarker endTextMarkerForBounds(long x, long y, long width, long height); + AccessibilityTextMarker startTextMarkerForBounds(long x, long y, long width, long height); + AccessibilityTextMarker textMarkerForPoint(long x, long y); + AccessibilityTextMarker previousTextMarker(AccessibilityTextMarker marker); + AccessibilityTextMarker nextTextMarker(AccessibilityTextMarker marker); + AccessibilityUIElement accessibilityElementForTextMarker(AccessibilityTextMarker marker); + DOMString stringForTextMarkerRange(AccessibilityTextMarkerRange range); + long textMarkerRangeLength(AccessibilityTextMarkerRange range); + boolean attributedStringForTextMarkerRangeContainsAttribute(DOMString attr, AccessibilityTextMarkerRange range); + long indexForTextMarker(AccessibilityTextMarker marker); + boolean isTextMarkerValid(AccessibilityTextMarker marker); + AccessibilityTextMarker textMarkerForIndex(long textIndex); + readonly attribute AccessibilityTextMarker startTextMarker; + readonly attribute AccessibilityTextMarker endTextMarker; + boolean setSelectedVisibleTextRange(AccessibilityTextMarkerRange range); + AccessibilityTextMarkerRange leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker textMarker); + AccessibilityTextMarkerRange rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker textMarker); + AccessibilityTextMarker previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker textMarker); + AccessibilityTextMarker nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker textMarker); + AccessibilityTextMarkerRange paragraphTextMarkerRangeForTextMarker(AccessibilityTextMarker textMarker); + AccessibilityTextMarker previousParagraphStartTextMarkerForTextMarker(AccessibilityTextMarker textMarker); + AccessibilityTextMarker nextParagraphEndTextMarkerForTextMarker(AccessibilityTextMarker textMarker); + AccessibilityTextMarkerRange sentenceTextMarkerRangeForTextMarker(AccessibilityTextMarker textMarker); + AccessibilityTextMarker previousSentenceStartTextMarkerForTextMarker(AccessibilityTextMarker textMarker); + AccessibilityTextMarker nextSentenceEndTextMarkerForTextMarker(AccessibilityTextMarker textMarker); + + // Returns an ordered list of supported actions for an element. + readonly attribute DOMString supportedActions; + readonly attribute DOMString mathPostscriptsDescription; + readonly attribute DOMString mathPrescriptsDescription; + + readonly attribute DOMString pathDescription; + + // iOS specific accessibility methods. + readonly attribute DOMString identifier; + readonly attribute DOMString traits; + readonly attribute long elementTextPosition; + readonly attribute long elementTextLength; + readonly attribute DOMString stringForSelection; + object elementsForRange(unsigned long location, unsigned long length); + void increaseTextSelection(); + void decreaseTextSelection(); + AccessibilityUIElement linkedElement(); + AccessibilityUIElement headerElementAtIndex(unsigned long index); + // This will simulate the accessibilityDidBecomeFocused API in UIKit. + void assistiveTechnologySimulatedFocus(); + readonly attribute boolean isSearchField; + readonly attribute boolean isTextArea; + + // Fieldset + readonly attribute boolean hasContainedByFieldsetTrait; + AccessibilityUIElement fieldsetAncestorElement(); + + // Notification support. + boolean addNotificationListener(object callbackFunction); + boolean removeNotificationListener(); +}; + diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm b/Tools/WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm new file mode 100644 index 000000000..98d37dab9 --- /dev/null +++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm @@ -0,0 +1,577 @@ +# Copyright (C) 2010 Apple Inc. All rights reserved. +# Copyright (C) 2012 Samsung Electronics +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + +use strict; +use warnings; +use File::Spec; + +package CodeGeneratorTestRunner; + +use Carp qw<longmess>; +use Data::Dumper; + +sub assert +{ + my $message = shift; + + my $mess = longmess(); + print Dumper($mess); + + die $message; +} + +sub new +{ + my ($class, $codeGenerator, $writeDependencies, $verbose, $idlFilePath) = @_; + + my $reference = { + codeGenerator => $codeGenerator, + idlFilePath => $idlFilePath, + }; + + bless($reference, $class); + return $reference; +} + +sub GenerateInterface +{ +} + +sub WriteData +{ + my ($self, $interface, $outputDir) = @_; + + foreach my $file ($self->_generateHeaderFile($interface), $self->_generateImplementationFile($interface)) { + $$self{codeGenerator}->UpdateFile(File::Spec->catfile($outputDir, $$file{name}), join("", @{$$file{contents}})); + } +} + +sub _className +{ + my ($type) = @_; + + return "JS" . _implementationClassName($type); +} + +sub _classRefGetter +{ + my ($self, $type) = @_; + + return $$self{codeGenerator}->WK_lcfirst(_implementationClassName($type)) . "Class"; +} + +sub _parseLicenseBlock +{ + my ($fileHandle) = @_; + + my ($copyright, $readCount, $buffer, $currentCharacter, $previousCharacter); + my $startSentinel = "/*"; + my $lengthOfStartSentinel = length($startSentinel); + $readCount = read($fileHandle, $buffer, $lengthOfStartSentinel); + return "" if ($readCount < $lengthOfStartSentinel || $buffer ne $startSentinel); + $copyright = $buffer; + + while ($readCount = read($fileHandle, $currentCharacter, 1)) { + $copyright .= $currentCharacter; + return $copyright if $currentCharacter eq "/" && $previousCharacter eq "*"; + $previousCharacter = $currentCharacter; + } + + return ""; +} + +sub _parseLicenseBlockFromFile +{ + my ($path) = @_; + open my $fileHandle, "<", $path or die "Failed to open $path for reading: $!"; + my $licenseBlock = _parseLicenseBlock($fileHandle); + close($fileHandle); + return $licenseBlock; +} + +sub _defaultLicenseBlock +{ + return <<EOF; +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +EOF +} + +sub _licenseBlock +{ + my ($self) = @_; + return $self->{licenseBlock} if $self->{licenseBlock}; + + my $licenseBlock = _parseLicenseBlockFromFile($self->{idlFilePath}) || _defaultLicenseBlock(); + $self->{licenseBlock} = $licenseBlock; + return $licenseBlock; +} + +sub _generateHeaderFile +{ + my ($self, $interface) = @_; + + my @contents = (); + + my $type = $interface->type; + my $className = _className($type); + my $implementationClassName = _implementationClassName($type); + my $filename = $className . ".h"; + + push(@contents, $self->_licenseBlock()); + + my $parentClassName = _parentClassName($interface); + + push(@contents, <<EOF); + +#ifndef ${className}_h +#define ${className}_h + +#include "${parentClassName}.h" +EOF + push(@contents, <<EOF); + +namespace WTR { + +class ${implementationClassName}; + +class ${className} : public ${parentClassName} { +public: + static JSClassRef @{[$self->_classRefGetter($type)]}(); + +private: + static const JSStaticFunction* staticFunctions(); + static const JSStaticValue* staticValues(); +EOF + + if (my @functions = @{$interface->functions}) { + push(@contents, "\n // Functions\n\n"); + foreach my $function (@functions) { + push(@contents, " static JSValueRef @{[$function->name]}(JSContextRef, JSObjectRef, JSObjectRef, size_t, const JSValueRef[], JSValueRef*);\n"); + } + } + + if (my @attributes = @{$interface->attributes}) { + push(@contents, "\n // Attributes\n\n"); + foreach my $attribute (@attributes) { + push(@contents, " static JSValueRef @{[$self->_getterName($attribute)]}(JSContextRef, JSObjectRef, JSStringRef, JSValueRef*);\n"); + push(@contents, " static bool @{[$self->_setterName($attribute)]}(JSContextRef, JSObjectRef, JSStringRef, JSValueRef, JSValueRef*);\n") unless $attribute->isReadOnly; + } + } + + push(@contents, <<EOF); +}; + +${implementationClassName}* to${implementationClassName}(JSContextRef, JSValueRef); + +} // namespace WTR + +#endif // ${className}_h +EOF + + return { name => $filename, contents => \@contents }; +} + +sub _generateImplementationFile +{ + my ($self, $interface) = @_; + + my @contentsPrefix = (); + my %contentsIncludes = (); + my @contents = (); + + my $type = $interface->type; + my $className = _className($type); + my $implementationClassName = _implementationClassName($type); + my $filename = $className . ".cpp"; + + push(@contentsPrefix, $self->_licenseBlock()); + + my $classRefGetter = $self->_classRefGetter($type); + my $parentClassName = _parentClassName($interface); + + $contentsIncludes{"${className}.h"} = 1; + $contentsIncludes{"${implementationClassName}.h"} = 1; + + push(@contentsPrefix, <<EOF); + +EOF + + push(@contents, <<EOF); +#include <JavaScriptCore/JSRetainPtr.h> +#include <wtf/GetPtr.h> + +namespace WTR { + +${implementationClassName}* to${implementationClassName}(JSContextRef context, JSValueRef value) +{ + if (!context || !value || !${className}::${classRefGetter}() || !JSValueIsObjectOfClass(context, value, ${className}::${classRefGetter}())) + return 0; + return static_cast<${implementationClassName}*>(JSWrapper::unwrap(context, value)); +} + +JSClassRef ${className}::${classRefGetter}() +{ + static JSClassRef jsClass; + if (!jsClass) { + JSClassDefinition definition = kJSClassDefinitionEmpty; + definition.className = "@{[$type->name]}"; + definition.parentClass = @{[$self->_parentClassRefGetterExpression($interface)]}; + definition.staticValues = staticValues(); + definition.staticFunctions = staticFunctions(); +EOF + + push(@contents, " definition.initialize = initialize;\n") unless _parentInterface($interface); + push(@contents, " definition.finalize = finalize;\n") unless _parentInterface($interface); + + push(@contents, <<EOF); + jsClass = JSClassCreate(&definition); + } + return jsClass; +} + +EOF + + push(@contents, $self->_staticFunctionsGetterImplementation($interface), "\n"); + push(@contents, $self->_staticValuesGetterImplementation($interface)); + + if (my @functions = @{$interface->functions}) { + push(@contents, "\n// Functions\n"); + + foreach my $function (@functions) { + push(@contents, <<EOF); + +JSValueRef ${className}::@{[$function->name]}(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + ${implementationClassName}* impl = to${implementationClassName}(context, thisObject); + if (!impl) + return JSValueMakeUndefined(context); + +EOF + my $functionCall; + if ($function->extendedAttributes->{"CustomArgumentHandling"}) { + $functionCall = "impl->" . $function->name . "(context, argumentCount, arguments, exception)"; + } else { + my @arguments = (); + my @specifiedArguments = @{$function->arguments}; + + $self->_includeHeaders(\%contentsIncludes, $function->type); + + if ($function->extendedAttributes->{"PassContext"}) { + push(@arguments, "context"); + } + + foreach my $i (0..$#specifiedArguments) { + my $argument = $specifiedArguments[$i]; + + $self->_includeHeaders(\%contentsIncludes, $type); + + push(@contents, " " . $self->_platformTypeVariableDeclaration($argument->type, $argument->name, "arguments[$i]", "argumentCount > $i") . "\n"); + + push(@arguments, $self->_argumentExpression($argument)); + } + + $functionCall = "impl->" . $function->name . "(" . join(", ", @arguments) . ")"; + } + + push(@contents, " ${functionCall};\n\n") if $function->type->name eq "void"; + push(@contents, " return " . $self->_returnExpression($function->type, $functionCall) . ";\n}\n"); + } + } + + if (my @attributes = @{$interface->attributes}) { + push(@contents, "\n// Attributes\n"); + foreach my $attribute (@attributes) { + $self->_includeHeaders(\%contentsIncludes, $attribute->type); + + my $getterName = $self->_getterName($attribute); + my $getterExpression = "impl->${getterName}()"; + + push(@contents, <<EOF); + +JSValueRef ${className}::${getterName}(JSContextRef context, JSObjectRef object, JSStringRef, JSValueRef* exception) +{ + ${implementationClassName}* impl = to${implementationClassName}(context, object); + if (!impl) + return JSValueMakeUndefined(context); + + return @{[$self->_returnExpression($attribute->type, $getterExpression)]}; +} +EOF + + unless ($attribute->isReadOnly) { + push(@contents, <<EOF); + +bool ${className}::@{[$self->_setterName($attribute)]}(JSContextRef context, JSObjectRef object, JSStringRef, JSValueRef value, JSValueRef* exception) +{ + ${implementationClassName}* impl = to${implementationClassName}(context, object); + if (!impl) + return false; + +EOF + + my $platformValue = $self->_platformTypeConstructor($attribute->type, "value"); + + push(@contents, <<EOF); + impl->@{[$self->_setterName($attribute)]}(${platformValue}); + + return true; +} +EOF + } + } + } + + push(@contents, <<EOF); + +} // namespace WTR + +EOF + + unshift(@contents, map { "#include \"$_\"\n" } sort keys(%contentsIncludes)); + unshift(@contents, "#include \"config.h\"\n"); + unshift(@contents, @contentsPrefix); + + return { name => $filename, contents => \@contents }; +} + +sub _getterName +{ + my ($self, $attribute) = @_; + + return $attribute->name; +} + +sub _includeHeaders +{ + my ($self, $headers, $type) = @_; + + return unless defined $type; + return if $type->name eq "boolean"; + return if $type->name eq "object"; + return if $$self{codeGenerator}->IsNonPointerType($type); + return if $$self{codeGenerator}->IsStringType($type); + + $$headers{_className($type) . ".h"} = 1; + $$headers{_implementationClassName($type) . ".h"} = 1; +} + +sub _implementationClassName +{ + my ($type) = @_; + + return $type->name; +} + +sub _parentClassName +{ + my ($interface) = @_; + + my $parentInterface = _parentInterface($interface); + return $parentInterface ? _className($parentInterface) : "JSWrapper"; +} + +sub _parentClassRefGetterExpression +{ + my ($self, $interface) = @_; + + my $parentInterface = _parentInterface($interface); + return $parentInterface ? $self->_classRefGetter($parentInterface) . "()" : "0"; +} + +sub _parentInterface +{ + my ($interface) = @_; + return $interface->parentType; +} + +sub _platformType +{ + my ($self, $type) = @_; + + return undef unless defined $type; + + return "bool" if $type->name eq "boolean"; + return "JSValueRef" if $type->name eq "object"; + return "JSRetainPtr<JSStringRef>" if $$self{codeGenerator}->IsStringType($type); + return "double" if $$self{codeGenerator}->IsNonPointerType($type); + return _implementationClassName($type); +} + +sub _platformTypeConstructor +{ + my ($self, $type, $argumentName) = @_; + + return "JSValueToNullableBoolean(context, $argumentName)" if $type->name eq "boolean" && $type->isNullable; + return "JSValueToBoolean(context, $argumentName)" if $type->name eq "boolean"; + return "$argumentName" if $type->name eq "object"; + return "JSRetainPtr<JSStringRef>(Adopt, JSValueToStringCopy(context, $argumentName, 0))" if $$self{codeGenerator}->IsStringType($type); + return "JSValueToNumber(context, $argumentName, 0)" if $$self{codeGenerator}->IsNonPointerType($type); + return "to" . _implementationClassName($type) . "(context, $argumentName)"; +} + +sub _platformTypeVariableDeclaration +{ + my ($self, $type, $variableName, $argumentName, $condition) = @_; + + my $platformType = $self->_platformType($type); + my $constructor = $self->_platformTypeConstructor($type, $argumentName); + + my %nonPointerTypes = ( + "bool" => 1, + "double" => 1, + "JSRetainPtr<JSStringRef>" => 1, + "JSValueRef" => 1, + ); + + my $nullValue = "0"; + if ($platformType eq "JSValueRef") { + $nullValue = "JSValueMakeUndefined(context)"; + } elsif (defined $nonPointerTypes{$platformType} && $platformType ne "double") { + $nullValue = "$platformType()"; + } + + $platformType .= "*" unless defined $nonPointerTypes{$platformType}; + + return "$platformType $variableName = $condition && $constructor;" if $condition && $platformType eq "bool"; + return "$platformType $variableName = $condition ? $constructor : $nullValue;" if $condition; + return "$platformType $variableName = $constructor;"; +} + +sub _returnExpression +{ + my ($self, $returnType, $expression) = @_; + + return "JSValueMakeUndefined(context)" if $returnType->name eq "void"; + return "JSValueMakeBooleanOrNull(context, ${expression})" if $returnType->name eq "boolean" && $returnType->isNullable; + return "JSValueMakeBoolean(context, ${expression})" if $returnType->name eq "boolean"; + return "${expression}" if $returnType->name eq "object"; + return "JSValueMakeNumber(context, ${expression})" if $$self{codeGenerator}->IsNonPointerType($returnType); + return "JSValueMakeStringOrNull(context, ${expression}.get())" if $$self{codeGenerator}->IsStringType($returnType); + return "toJS(context, WTF::getPtr(${expression}))"; +} + +sub _argumentExpression +{ + my ($self, $argument) = @_; + + my $type = $argument->type; + my $name = $argument->name; + + return "${name}.get()" if $$self{codeGenerator}->IsStringType($type); + return $name; +} + +sub _setterName +{ + my ($self, $attribute) = @_; + + my $name = $attribute->name; + + return "set" . $$self{codeGenerator}->WK_ucfirst($name); +} + +sub _staticFunctionsGetterImplementation +{ + my ($self, $interface) = @_; + + my $mapFunction = sub { + my $name = $_->name; + my @attributes = qw(kJSPropertyAttributeDontDelete kJSPropertyAttributeReadOnly); + push(@attributes, "kJSPropertyAttributeDontEnum") if $_->extendedAttributes->{"DontEnum"}; + + return "{ \"$name\", $name, " . join(" | ", @attributes) . " }"; + }; + + return $self->_staticFunctionsOrValuesGetterImplementation($interface, "function", "{ 0, 0, 0 }", $mapFunction, $interface->functions); +} + +sub _staticFunctionsOrValuesGetterImplementation +{ + my ($self, $interface, $functionOrValue, $arrayTerminator, $mapFunction, $functionsOrAttributes) = @_; + + my $className = _className($interface->type); + my $uppercaseFunctionOrValue = $$self{codeGenerator}->WK_ucfirst($functionOrValue); + + my $result = <<EOF; +const JSStatic${uppercaseFunctionOrValue}* ${className}::static${uppercaseFunctionOrValue}s() +{ +EOF + + my @initializers = map(&$mapFunction, @{$functionsOrAttributes}); + return $result . " return 0;\n}\n" unless @initializers; + + $result .= <<EOF + static const JSStatic${uppercaseFunctionOrValue} ${functionOrValue}s[] = { + @{[join(",\n ", @initializers)]}, + ${arrayTerminator} + }; + return ${functionOrValue}s; +} +EOF +} + +sub _staticValuesGetterImplementation +{ + my ($self, $interface) = @_; + + my $mapFunction = sub { + return if $_->extendedAttributes->{"NoImplementation"}; + + my $attributeName = $_->name; + my $getterName = $self->_getterName($_); + my $setterName = $_->isReadOnly ? "0" : $self->_setterName($_); + my @attributes = qw(kJSPropertyAttributeDontDelete); + push(@attributes, "kJSPropertyAttributeReadOnly") if $_->isReadOnly; + push(@attributes, "kJSPropertyAttributeDontEnum") if $_->extendedAttributes->{"DontEnum"}; + + return "{ \"$attributeName\", $getterName, $setterName, " . join(" | ", @attributes) . " }"; + }; + + return $self->_staticFunctionsOrValuesGetterImplementation($interface, "value", "{ 0, 0, 0, 0 }", $mapFunction, $interface->attributes); +} + +1; diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/EventSendingController.idl b/Tools/WebKitTestRunner/InjectedBundle/Bindings/EventSendingController.idl new file mode 100644 index 000000000..f3280bb94 --- /dev/null +++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/EventSendingController.idl @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2010, 2011, 2014-2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +interface EventSendingController { + void mouseDown(long buttonNumber, object modifierArray); + void mouseUp(long buttonNumber, object modifierArray); + void mouseMoveTo(long x, long y); + void mouseForceClick(); + void startAndCancelMouseForceClick(); + void mouseForceDown(); + void mouseForceUp(); + void mouseForceChanged(double force); + void mouseScrollBy(long x, long y); + void mouseScrollByWithWheelAndMomentumPhases(long x, long y, DOMString phase, DOMString momentum); + void swipeGestureWithWheelAndMomentumPhases(long x, long y, DOMString phase, DOMString momentum); + void continuousMouseScrollBy(long x, long y, optional boolean paged); + object contextClick(); + void scheduleAsynchronousClick(); + + void leapForward(long milliseconds); + + void keyDown(DOMString key, object modifierArray, long location); + void scheduleAsynchronousKeyDown(DOMString key); + + // Zoom functions. + void textZoomIn(); + void textZoomOut(); + void zoomPageIn(); + void zoomPageOut(); + void scalePageBy(double scale, double x, double y); + + void monitorWheelEvents(); + void callAfterScrollingCompletes(object functionCallback); + +#if defined(ENABLE_TOUCH_EVENTS) && ENABLE_TOUCH_EVENTS + // Touch events. + void addTouchPoint(long x, long y); + void updateTouchPoint(long index, long x, long y); + void setTouchModifier(DOMString modifier, boolean enable); + void setTouchPointRadius(long radiusX, long radiusY); + void touchStart(); + void touchMove(); + void touchEnd(); + void touchCancel(); + void clearTouchPoints(); + void releaseTouchPoint(long index); + void cancelTouchPoint(long index); +#endif +}; + diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrappable.h b/Tools/WebKitTestRunner/InjectedBundle/Bindings/GCController.idl index 5ec7197c5..fb933834d 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrappable.h +++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/GCController.idl @@ -23,25 +23,9 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSWrappable_h -#define JSWrappable_h - -#include <JavaScriptCore/JavaScript.h> -#include <wtf/RefCounted.h> - -namespace WTR { - -class JSWrappable : public RefCounted<JSWrappable> { -public: - virtual ~JSWrappable() { } - virtual JSClassRef wrapperClass() = 0; +interface GCController { + void collect(); + void collectOnAlternateThread(boolean waitUntilDone); + unsigned long long getJSObjectCount(); }; -inline JSValueRef JSValueMakeStringOrNull(JSContextRef context, JSStringRef stringOrNull) -{ - return stringOrNull ? JSValueMakeString(context, stringOrNull) : JSValueMakeNull(context); -} - -} // namespace WTR - -#endif // JSWrappable_h diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl b/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl new file mode 100644 index 000000000..352fa0ae7 --- /dev/null +++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2010-2017 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +interface TestRunner { + readonly attribute boolean isWebKit2; + + // The basics. + void dumpAsText(boolean dumpPixels); + void dumpChildFramesAsText(); + void waitForPolicyDelegate(); + void waitUntilDone(); + void waitUntilDownloadFinished(); + void notifyDone(); + double preciseTime(); + readonly attribute double timeout; + + // Other dumping. + void dumpBackForwardList(); + void dumpChildFrameScrollPositions(); + void dumpEditingCallbacks(); + void dumpSelectionRect(); + void dumpStatusCallbacks(); + void dumpTitleChanges(); + void dumpFullScreenCallbacks(); + void dumpFrameLoadCallbacks(); + void dumpProgressFinishedCallback(); + void dumpResourceLoadCallbacks(); + void dumpResourceResponseMIMETypes(); + void dumpWillCacheResponse(); + void dumpApplicationCacheDelegateCallbacks(); + void dumpDatabaseCallbacks(); + void dumpDOMAsWebArchive(); + void dumpPolicyDelegateCallbacks(); + + // Special options. + void keepWebHistory(); + void setAcceptsEditing(boolean value); + void setCanOpenWindows(boolean value); + void setCloseRemainingWindowsWhenComplete(boolean value); + void setXSSAuditorEnabled(boolean value); + void setAllowUniversalAccessFromFileURLs(boolean value); + void setAllowFileAccessFromFileURLs(boolean value); + void setNeedsStorageAccessFromFileURLsQuirk(boolean value); + void setPluginsEnabled(boolean value); + void setJavaScriptCanAccessClipboard(boolean value); + void setPrivateBrowsingEnabled(boolean value); + void setUseDashboardCompatibilityMode(boolean value); + void setPopupBlockingEnabled(boolean value); + void setAuthorAndUserStylesEnabled(boolean value); + void setCustomPolicyDelegate(boolean enabled, boolean permissive); + void addOriginAccessWhitelistEntry(DOMString sourceOrigin, DOMString destinationProtocol, DOMString destinationHost, boolean allowDestinationSubdomains); + void removeOriginAccessWhitelistEntry(DOMString sourceOrigin, DOMString destinationProtocol, DOMString destinationHost, boolean allowDestinationSubdomains); + void setUserStyleSheetEnabled(boolean value); + void setUserStyleSheetLocation(DOMString location); + void setSpatialNavigationEnabled(boolean value); + void setTabKeyCyclesThroughElements(boolean enabled); + void setSerializeHTTPLoads(); + void dispatchPendingLoadRequests(); + void setCacheModel(long model); + void setAsynchronousSpellCheckingEnabled(boolean value); + void setPrinting(); + void setShouldDecideNavigationPolicyAfterDelay(boolean value); + void setNavigationGesturesEnabled(boolean value); + void setIgnoresViewportScaleLimits(boolean value); + void setShouldDownloadUndisplayableMIMETypes(boolean value); + + // Special DOM functions. + void clearBackForwardList(); + void execCommand(DOMString name, DOMString argument); + boolean isCommandEnabled(DOMString name); + unsigned long windowCount(); + + // Special DOM variables. + attribute boolean globalFlag; + + // Repaint testing. + void testRepaint(); + void repaintSweepHorizontally(); + void display(); + + // Printing + boolean isPageBoxVisible(long pageIndex); + + [PassContext] void setValueForUser(object element, DOMString value); + + // UserContent testing. + void addUserScript(DOMString source, boolean runAtStart, boolean allFrames); + void addUserStyleSheet(DOMString source, boolean allFrames); + + // Local storage API + void clearAllDatabases(); + void setDatabaseQuota(unsigned long long quota); + DOMString pathToLocalResource(DOMString url); + + attribute double databaseDefaultQuota; + attribute double databaseMaxQuota; + + // Application Cache API + void clearAllApplicationCaches(); + void setAppCacheMaximumSize(unsigned long long size); + long long applicationCacheDiskUsageForOrigin(DOMString origin); + void clearApplicationCacheForOrigin(DOMString name); + void disallowIncreaseForApplicationCacheQuota(); + object originsWithApplicationCache(); + + // Text search testing. + boolean findString(DOMString target, object optionsArray); + + // Evaluating script in a special context. + [PassContext] void evaluateScriptInIsolatedWorld(unsigned long worldID, DOMString script); + + // For Web Inspector tests + void showWebInspector(); + void closeWebInspector(); + void evaluateInWebInspector(DOMString script); + readonly attribute DOMString inspectorTestStubURL; + + void setPOSIXLocale(DOMString locale); + + void setTextDirection(DOMString direction); + + void setWillSendRequestReturnsNull(boolean flag); + void setWillSendRequestReturnsNullOnRedirect(boolean flag); + void setWillSendRequestAddsHTTPBody(DOMString body); + + void setShouldStayOnPageAfterHandlingBeforeUnload(boolean flag); + + void setDefersLoading(boolean flag); + void setStopProvisionalFrameLoads(); + + // Focus testing. + void addChromeInputField(object callback); + void removeChromeInputField(object callback); + void focusWebView(object callback); + + // Window/view state + void setBackingScaleFactor(double backingScaleFactor, object callback); + + void setWindowIsKey(boolean isKey); + void setViewSize(double width, double height); + + // Cookies testing + void setAlwaysAcceptCookies(boolean accept); + + void overridePreference(DOMString preference, DOMString value); + + // Page Visibility API + void setPageVisibility(DOMString state); + void resetPageVisibility(); + + // Control full screen behavior. + void setHasCustomFullScreenBehavior(boolean value); + + // Web notifications support + void grantWebNotificationPermission(DOMString origin); + void denyWebNotificationPermission(DOMString origin); + void removeAllWebNotificationPermissions(); + void simulateWebNotificationClick(object notification); + + // Geolocation + void setGeolocationPermission(boolean value); + void setMockGeolocationPosition(double latitude, double longitude, double accuracy, optional object altitude, optional object altitudeAccuracy, optional object heading, optional object speed); + void setMockGeolocationPositionUnavailableError(DOMString errorMessage); + boolean isGeolocationProviderActive(); + + // MediaStream + void setUserMediaPermission(boolean value); + void setUserMediaPersistentPermissionForOrigin(boolean permission, DOMString origin, DOMString parentOrigin); + unsigned long userMediaPermissionRequestCountForOrigin(DOMString origin, DOMString parentOrigin); + void resetUserMediaPermissionRequestCountForOrigin(DOMString origin, DOMString parentOrigin); + + // Audio testing. + [PassContext] void setAudioResult(object data); + + boolean callShouldCloseOnWebView(); + + // Work queue. + void queueBackNavigation(unsigned long howFarBackward); + void queueForwardNavigation(unsigned long howFarForward); + void queueLoad(DOMString url, DOMString target, optional boolean shouldOpenExternalURLs); + void queueLoadHTMLString(DOMString content, optional DOMString baseURL, optional DOMString unreachableURL); + void queueReload(); + void queueLoadingScript(DOMString script); + void queueNonLoadingScript(DOMString script); + + // Authentication + void setRejectsProtectionSpaceAndContinueForAuthenticationChallenges(boolean value); + void setHandlesAuthenticationChallenges(boolean value); + void setShouldLogCanAuthenticateAgainstProtectionSpace(boolean value); + void setAuthenticationUsername(DOMString username); + void setAuthenticationPassword(DOMString password); + + void setAllowsAnySSLCertificate(boolean value); + + // Secure text input mode (Mac only) + readonly attribute boolean secureEventInputIsEnabled; + + // Override plugin load policy. + void setBlockAllPlugins(boolean shouldBlock); + + // Hooks to the JSC compiler. + object failNextNewCodeBlock(); + object numberOfDFGCompiles(object function); + object neverInlineFunction(object function); + + // Swipe gestures + void installDidBeginSwipeCallback(object callback); + void installWillEndSwipeCallback(object callback); + void installDidEndSwipeCallback(object callback); + void installDidRemoveSwipeSnapshotCallback(object callback); + + unsigned long imageCountInGeneralPasteboard(); + + // UI Process Testing + void runUIScript(DOMString script, object callback); + + void clearTestRunnerCallbacks(); + + void accummulateLogsForChannel(DOMString channel); + + // Gamepad + void setMockGamepadDetails(unsigned long index, DOMString id, unsigned long axisCount, unsigned long buttonCount); + void setMockGamepadAxisValue(unsigned long index, unsigned long axisIndex, double value); + void setMockGamepadButtonValue(unsigned long index, unsigned long buttonIndex, double value); + void connectMockGamepad(unsigned long index); + void disconnectMockGamepad(unsigned long index); + + // Resource Load Statistics + void installStatisticsDidModifyDataRecordsCallback(object callback); + void setStatisticsPrevalentResource(DOMString hostName, boolean value); + boolean isStatisticsPrevalentResource(DOMString hostName); + void setStatisticsHasHadUserInteraction(DOMString hostName, boolean value); + boolean isStatisticsHasHadUserInteraction(DOMString hostName); + void setStatisticsTimeToLiveUserInteraction(double seconds); + void statisticsFireDataModificationHandler(); + void setStatisticsNotifyPagesWhenDataRecordsWereScanned(boolean value); + void setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(boolean value); + void setStatisticsMinimumTimeBetweeenDataRecordsRemoval(double seconds); + void statisticsResetToConsistentState(); +}; diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/TextInputController.idl b/Tools/WebKitTestRunner/InjectedBundle/Bindings/TextInputController.idl new file mode 100644 index 000000000..d95a6985d --- /dev/null +++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/TextInputController.idl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +interface TextInputController { + void setMarkedText(DOMString string, long from, long length); + boolean hasMarkedText(); + void unmarkText(); + void insertText(DOMString string); +}; + diff --git a/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.cpp b/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.cpp index 65e355652..6bd165288 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2010, 2011, 2014-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,13 +30,13 @@ #include "InjectedBundlePage.h" #include "JSEventSendingController.h" #include "StringFunctions.h" -#include <WebKit2/WKBundle.h> -#include <WebKit2/WKBundleFrame.h> -#include <WebKit2/WKBundlePagePrivate.h> -#include <WebKit2/WKBundlePrivate.h> -#include <WebKit2/WKContextMenuItem.h> -#include <WebKit2/WKMutableDictionary.h> -#include <WebKit2/WKNumber.h> +#include <WebKit/WKBundle.h> +#include <WebKit/WKBundleFrame.h> +#include <WebKit/WKBundlePagePrivate.h> +#include <WebKit/WKBundlePrivate.h> +#include <WebKit/WKContextMenuItem.h> +#include <WebKit/WKMutableDictionary.h> +#include <WebKit/WKNumber.h> #include <wtf/StdLibExtras.h> namespace WTR { @@ -116,6 +116,8 @@ static WKEventModifiers parseModifier(JSStringRef modifier) return kWKEventModifiersAltKey; if (JSStringIsEqualToUTF8CString(modifier, "metaKey")) return kWKEventModifiersMetaKey; + if (JSStringIsEqualToUTF8CString(modifier, "capsLockKey")) + return kWKEventModifiersCapsLockKey; if (JSStringIsEqualToUTF8CString(modifier, "addSelectionKey")) { #if OS(MAC_OS_X) return kWKEventModifiersMetaKey; @@ -164,9 +166,9 @@ static WKEventModifiers parseModifierArray(JSContextRef context, JSValueRef arra return modifiers; } -PassRefPtr<EventSendingController> EventSendingController::create() +Ref<EventSendingController> EventSendingController::create() { - return adoptRef(new EventSendingController); + return adoptRef(*new EventSendingController); } EventSendingController::EventSendingController() @@ -208,7 +210,8 @@ static WKMutableDictionaryRef createMouseMessageBody(MouseState state, int butto void EventSendingController::mouseDown(int button, JSValueRef modifierArray) { - WKBundlePageRef page = InjectedBundle::shared().page()->page(); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundlePageRef page = injectedBundle.page()->page(); WKBundleFrameRef frame = WKBundlePageGetMainFrame(page); JSContextRef context = WKBundleFrameGetJavaScriptContext(frame); WKEventModifiers modifiers = parseModifierArray(context, modifierArray); @@ -216,12 +219,12 @@ void EventSendingController::mouseDown(int button, JSValueRef modifierArray) WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr<WKMutableDictionaryRef> EventSenderMessageBody(AdoptWK, createMouseMessageBody(MouseDown, button, modifiers)); - WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); + WKBundlePagePostSynchronousMessageForTesting(page, EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::mouseUp(int button, JSValueRef modifierArray) { - WKBundlePageRef page = InjectedBundle::shared().page()->page(); + WKBundlePageRef page = InjectedBundle::singleton().page()->page(); WKBundleFrameRef frame = WKBundlePageGetMainFrame(page); JSContextRef context = WKBundleFrameGetJavaScriptContext(frame); WKEventModifiers modifiers = parseModifierArray(context, modifierArray); @@ -229,7 +232,7 @@ void EventSendingController::mouseUp(int button, JSValueRef modifierArray) WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr<WKMutableDictionaryRef> EventSenderMessageBody(AdoptWK, createMouseMessageBody(MouseUp, button, modifiers)); - WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); + WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::mouseMoveTo(int x, int y) @@ -249,7 +252,73 @@ void EventSendingController::mouseMoveTo(int x, int y) WKRetainPtr<WKDoubleRef> yRef(AdoptWK, WKDoubleCreate(y)); WKDictionarySetItem(EventSenderMessageBody.get(), yKey.get(), yRef.get()); - WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); + m_position = WKPointMake(x, y); + + WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); +} + +void EventSendingController::mouseForceClick() +{ + WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); + WKRetainPtr<WKMutableDictionaryRef> EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); + + WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); + WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("MouseForceClick")); + WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); + + WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); +} + +void EventSendingController::startAndCancelMouseForceClick() +{ + WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); + WKRetainPtr<WKMutableDictionaryRef> EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); + + WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); + WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("StartAndCancelMouseForceClick")); + WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); + + WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); +} + +void EventSendingController::mouseForceDown() +{ + WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); + WKRetainPtr<WKMutableDictionaryRef> EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); + + WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); + WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("MouseForceDown")); + WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); + + WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); +} + +void EventSendingController::mouseForceUp() +{ + WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); + WKRetainPtr<WKMutableDictionaryRef> EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); + + WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); + WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("MouseForceUp")); + WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); + + WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); +} + +void EventSendingController::mouseForceChanged(double force) +{ + WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); + WKRetainPtr<WKMutableDictionaryRef> EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); + + WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); + WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("MouseForceChanged")); + WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); + + WKRetainPtr<WKStringRef> forceKey(AdoptWK, WKStringCreateWithUTF8CString("Force")); + WKRetainPtr<WKDoubleRef> forceRef(AdoptWK, WKDoubleCreate(force)); + WKDictionarySetItem(EventSenderMessageBody.get(), forceKey.get(), forceRef.get()); + + WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::leapForward(int milliseconds) @@ -265,7 +334,7 @@ void EventSendingController::leapForward(int milliseconds) WKRetainPtr<WKUInt64Ref> timeRef(AdoptWK, WKUInt64Create(milliseconds)); WKDictionarySetItem(EventSenderMessageBody.get(), timeKey.get(), timeRef.get()); - WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); + WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::scheduleAsynchronousClick() @@ -277,11 +346,11 @@ void EventSendingController::scheduleAsynchronousClick() // Asynchronous mouse down. WKRetainPtr<WKMutableDictionaryRef> mouseDownMessageBody(AdoptWK, createMouseMessageBody(MouseDown, button, modifiers)); - WKBundlePostMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), mouseDownMessageBody.get()); + WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), mouseDownMessageBody.get()); // Asynchronous mouse up. WKRetainPtr<WKMutableDictionaryRef> mouseUpMessageBody(AdoptWK, createMouseMessageBody(MouseUp, button, modifiers)); - WKBundlePostMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), mouseUpMessageBody.get()); + WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), mouseUpMessageBody.get()); } static WKRetainPtr<WKMutableDictionaryRef> createKeyDownMessageBody(JSStringRef key, WKEventModifiers modifiers, int location) @@ -308,7 +377,7 @@ static WKRetainPtr<WKMutableDictionaryRef> createKeyDownMessageBody(JSStringRef void EventSendingController::keyDown(JSStringRef key, JSValueRef modifierArray, int location) { - WKBundlePageRef page = InjectedBundle::shared().page()->page(); + WKBundlePageRef page = InjectedBundle::singleton().page()->page(); WKBundleFrameRef frame = WKBundlePageGetMainFrame(page); JSContextRef context = WKBundleFrameGetJavaScriptContext(frame); WKEventModifiers modifiers = parseModifierArray(context, modifierArray); @@ -316,7 +385,7 @@ void EventSendingController::keyDown(JSStringRef key, JSValueRef modifierArray, WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr<WKMutableDictionaryRef> keyDownMessageBody = createKeyDownMessageBody(key, modifiers, location); - WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), keyDownMessageBody.get(), 0); + WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), keyDownMessageBody.get(), 0); } void EventSendingController::scheduleAsynchronousKeyDown(JSStringRef key) @@ -324,7 +393,7 @@ void EventSendingController::scheduleAsynchronousKeyDown(JSStringRef key) WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr<WKMutableDictionaryRef> keyDownMessageBody = createKeyDownMessageBody(key, 0 /* modifiers */, 0 /* location */); - WKBundlePostMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), keyDownMessageBody.get()); + WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), keyDownMessageBody.get()); } void EventSendingController::mouseScrollBy(int x, int y) @@ -344,7 +413,106 @@ void EventSendingController::mouseScrollBy(int x, int y) WKRetainPtr<WKDoubleRef> yRef(AdoptWK, WKDoubleCreate(y)); WKDictionarySetItem(EventSenderMessageBody.get(), yKey.get(), yRef.get()); - WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); + WKBundlePageForceRepaint(InjectedBundle::singleton().page()->page()); // Triggers a scrolling tree commit. + WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get()); +} + +static uint64_t cgEventPhaseFromString(JSStringRef phaseStr) +{ + if (JSStringIsEqualToUTF8CString(phaseStr, "none")) + return 0; + if (JSStringIsEqualToUTF8CString(phaseStr, "began")) + return 1; // kCGScrollPhaseBegan + if (JSStringIsEqualToUTF8CString(phaseStr, "changed")) + return 2; // kCGScrollPhaseChanged + if (JSStringIsEqualToUTF8CString(phaseStr, "ended")) + return 4; // kCGScrollPhaseEnded + if (JSStringIsEqualToUTF8CString(phaseStr, "cancelled")) + return 8; // kCGScrollPhaseCancelled + if (JSStringIsEqualToUTF8CString(phaseStr, "maybegin")) + return 128; // kCGScrollPhaseMayBegin + + ASSERT_NOT_REACHED(); + return 0; +} + +static uint64_t cgEventMomentumPhaseFromString(JSStringRef phaseStr) +{ + if (JSStringIsEqualToUTF8CString(phaseStr, "none")) + return 0; // kCGMomentumScrollPhaseNone + if (JSStringIsEqualToUTF8CString(phaseStr, "begin")) + return 1; // kCGMomentumScrollPhaseBegin + if (JSStringIsEqualToUTF8CString(phaseStr, "continue")) + return 2; // kCGMomentumScrollPhaseContinue + if (JSStringIsEqualToUTF8CString(phaseStr, "end")) + return 3; // kCGMomentumScrollPhaseEnd + + ASSERT_NOT_REACHED(); + return 0; +} + +void EventSendingController::mouseScrollByWithWheelAndMomentumPhases(int x, int y, JSStringRef phaseStr, JSStringRef momentumStr) +{ + WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); + WKRetainPtr<WKMutableDictionaryRef> EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); + + WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); + WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("MouseScrollByWithWheelAndMomentumPhases")); + WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); + + WKRetainPtr<WKStringRef> xKey(AdoptWK, WKStringCreateWithUTF8CString("X")); + WKRetainPtr<WKDoubleRef> xRef(AdoptWK, WKDoubleCreate(x)); + WKDictionarySetItem(EventSenderMessageBody.get(), xKey.get(), xRef.get()); + + WKRetainPtr<WKStringRef> yKey(AdoptWK, WKStringCreateWithUTF8CString("Y")); + WKRetainPtr<WKDoubleRef> yRef(AdoptWK, WKDoubleCreate(y)); + WKDictionarySetItem(EventSenderMessageBody.get(), yKey.get(), yRef.get()); + + uint64_t phase = cgEventPhaseFromString(phaseStr); + uint64_t momentum = cgEventMomentumPhaseFromString(momentumStr); + + WKRetainPtr<WKStringRef> phaseKey(AdoptWK, WKStringCreateWithUTF8CString("Phase")); + WKRetainPtr<WKUInt64Ref> phaseRef(AdoptWK, WKUInt64Create(phase)); + WKDictionarySetItem(EventSenderMessageBody.get(), phaseKey.get(), phaseRef.get()); + + WKRetainPtr<WKStringRef> momentumKey(AdoptWK, WKStringCreateWithUTF8CString("Momentum")); + WKRetainPtr<WKUInt64Ref> momentumRef(AdoptWK, WKUInt64Create(momentum)); + WKDictionarySetItem(EventSenderMessageBody.get(), momentumKey.get(), momentumRef.get()); + + WKBundlePageForceRepaint(InjectedBundle::singleton().page()->page()); // Triggers a scrolling tree commit. + WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get()); +} + +void EventSendingController::swipeGestureWithWheelAndMomentumPhases(int x, int y, JSStringRef phaseStr, JSStringRef momentumStr) +{ + WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); + WKRetainPtr<WKMutableDictionaryRef> EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); + + WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); + WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("SwipeGestureWithWheelAndMomentumPhases")); + WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); + + WKRetainPtr<WKStringRef> xKey(AdoptWK, WKStringCreateWithUTF8CString("X")); + WKRetainPtr<WKDoubleRef> xRef(AdoptWK, WKDoubleCreate(x)); + WKDictionarySetItem(EventSenderMessageBody.get(), xKey.get(), xRef.get()); + + WKRetainPtr<WKStringRef> yKey(AdoptWK, WKStringCreateWithUTF8CString("Y")); + WKRetainPtr<WKDoubleRef> yRef(AdoptWK, WKDoubleCreate(y)); + WKDictionarySetItem(EventSenderMessageBody.get(), yKey.get(), yRef.get()); + + uint64_t phase = cgEventPhaseFromString(phaseStr); + uint64_t momentum = cgEventMomentumPhaseFromString(momentumStr); + + WKRetainPtr<WKStringRef> phaseKey(AdoptWK, WKStringCreateWithUTF8CString("Phase")); + WKRetainPtr<WKUInt64Ref> phaseRef(AdoptWK, WKUInt64Create(phase)); + WKDictionarySetItem(EventSenderMessageBody.get(), phaseKey.get(), phaseRef.get()); + + WKRetainPtr<WKStringRef> momentumKey(AdoptWK, WKStringCreateWithUTF8CString("Momentum")); + WKRetainPtr<WKUInt64Ref> momentumRef(AdoptWK, WKUInt64Create(momentum)); + WKDictionarySetItem(EventSenderMessageBody.get(), momentumKey.get(), momentumRef.get()); + + WKBundlePageForceRepaint(InjectedBundle::singleton().page()->page()); // Triggers a scrolling tree commit. + WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get()); } void EventSendingController::continuousMouseScrollBy(int x, int y, bool paged) @@ -368,31 +536,33 @@ void EventSendingController::continuousMouseScrollBy(int x, int y, bool paged) WKRetainPtr<WKUInt64Ref> pagedRef(AdoptWK, WKUInt64Create(paged)); WKDictionarySetItem(EventSenderMessageBody.get(), pagedKey.get(), pagedRef.get()); - WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); + // FIXME: This message should be asynchronous, as scrolling is intrinsically asynchronous. + // See also: <https://bugs.webkit.org/show_bug.cgi?id=148256>. + WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } JSValueRef EventSendingController::contextClick() { - WKBundlePageRef page = InjectedBundle::shared().page()->page(); + WKBundlePageRef page = InjectedBundle::singleton().page()->page(); WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(page); JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame); #if ENABLE(CONTEXT_MENUS) - // Do mouse context click. - mouseDown(2, 0); - mouseUp(2, 0); + WKRetainPtr<WKArrayRef> menuEntries = adoptWK(WKBundlePageCopyContextMenuAtPointInWindow(page, m_position)); + JSValueRef arrayResult = JSObjectMakeArray(context, 0, 0, 0); + if (!menuEntries) + return arrayResult; - WKRetainPtr<WKArrayRef> menuEntries = adoptWK(WKBundlePageCopyContextMenuItems(page)); + JSObjectRef arrayObj = JSValueToObject(context, arrayResult, 0); size_t entriesSize = WKArrayGetSize(menuEntries.get()); - auto jsValuesArray = std::make_unique<JSValueRef[]>(entriesSize); for (size_t i = 0; i < entriesSize; ++i) { ASSERT(WKGetTypeID(WKArrayGetItemAtIndex(menuEntries.get(), i)) == WKContextMenuItemGetTypeID()); WKContextMenuItemRef item = static_cast<WKContextMenuItemRef>(WKArrayGetItemAtIndex(menuEntries.get(), i)); MenuItemPrivateData* privateData = new MenuItemPrivateData(page, item); - jsValuesArray[i] = JSObjectMake(context, getMenuItemClass(), privateData); + JSObjectSetPropertyAtIndex(context, arrayObj, i, JSObjectMake(context, getMenuItemClass(), privateData), 0); } - return JSObjectMakeArray(context, entriesSize, jsValuesArray.get(), 0); + return arrayResult; #else return JSValueMakeUndefined(context); #endif @@ -400,44 +570,96 @@ JSValueRef EventSendingController::contextClick() void EventSendingController::textZoomIn() { + auto& injectedBundle = InjectedBundle::singleton(); // Ensure page zoom is reset. - WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), 1); + WKBundlePageSetPageZoomFactor(injectedBundle.page()->page(), 1); - double zoomFactor = WKBundlePageGetTextZoomFactor(InjectedBundle::shared().page()->page()); - WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor * ZoomMultiplierRatio); + double zoomFactor = WKBundlePageGetTextZoomFactor(injectedBundle.page()->page()); + WKBundlePageSetTextZoomFactor(injectedBundle.page()->page(), zoomFactor * ZoomMultiplierRatio); } void EventSendingController::textZoomOut() { + auto& injectedBundle = InjectedBundle::singleton(); // Ensure page zoom is reset. - WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), 1); + WKBundlePageSetPageZoomFactor(injectedBundle.page()->page(), 1); - double zoomFactor = WKBundlePageGetTextZoomFactor(InjectedBundle::shared().page()->page()); - WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor / ZoomMultiplierRatio); + double zoomFactor = WKBundlePageGetTextZoomFactor(injectedBundle.page()->page()); + WKBundlePageSetTextZoomFactor(injectedBundle.page()->page(), zoomFactor / ZoomMultiplierRatio); } void EventSendingController::zoomPageIn() { + auto& injectedBundle = InjectedBundle::singleton(); // Ensure text zoom is reset. - WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), 1); + WKBundlePageSetTextZoomFactor(injectedBundle.page()->page(), 1); - double zoomFactor = WKBundlePageGetPageZoomFactor(InjectedBundle::shared().page()->page()); - WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor * ZoomMultiplierRatio); + double zoomFactor = WKBundlePageGetPageZoomFactor(injectedBundle.page()->page()); + WKBundlePageSetPageZoomFactor(injectedBundle.page()->page(), zoomFactor * ZoomMultiplierRatio); } void EventSendingController::zoomPageOut() { + auto& injectedBundle = InjectedBundle::singleton(); // Ensure text zoom is reset. - WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), 1); + WKBundlePageSetTextZoomFactor(injectedBundle.page()->page(), 1); - double zoomFactor = WKBundlePageGetPageZoomFactor(InjectedBundle::shared().page()->page()); - WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor / ZoomMultiplierRatio); + double zoomFactor = WKBundlePageGetPageZoomFactor(injectedBundle.page()->page()); + WKBundlePageSetPageZoomFactor(injectedBundle.page()->page(), zoomFactor / ZoomMultiplierRatio); } void EventSendingController::scalePageBy(double scale, double x, double y) { WKPoint origin = { x, y }; - WKBundlePageSetScaleAtOrigin(InjectedBundle::shared().page()->page(), scale, origin); + WKBundlePageSetScaleAtOrigin(InjectedBundle::singleton().page()->page(), scale, origin); +} + +void EventSendingController::monitorWheelEvents() +{ + WKBundlePageRef page = InjectedBundle::singleton().page()->page(); + + WKBundlePageStartMonitoringScrollOperations(page); +} + +struct ScrollCompletionCallbackData { + JSContextRef m_context; + JSObjectRef m_function; + + ScrollCompletionCallbackData(JSContextRef context, JSObjectRef function) + : m_context(context), m_function(function) + { + } +}; + +static void executeCallback(void* context) +{ + if (!context) + return; + + std::unique_ptr<ScrollCompletionCallbackData> callBackData(reinterpret_cast<ScrollCompletionCallbackData*>(context)); + + JSObjectCallAsFunction(callBackData->m_context, callBackData->m_function, nullptr, 0, nullptr, nullptr); + JSValueUnprotect(callBackData->m_context, callBackData->m_function); +} + +void EventSendingController::callAfterScrollingCompletes(JSValueRef functionCallback) +{ + if (!functionCallback) + return; + + WKBundlePageRef page = InjectedBundle::singleton().page()->page(); + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(page); + JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame); + + JSObjectRef functionCallbackObject = JSValueToObject(context, functionCallback, nullptr); + if (!functionCallbackObject) + return; + + JSValueProtect(context, functionCallbackObject); + + auto scrollCompletionCallbackData = std::make_unique<ScrollCompletionCallbackData>(context, functionCallbackObject); + + WKBundlePageRegisterScrollOperationCompletionCallback(page, executeCallback, scrollCompletionCallbackData.release()); } #if ENABLE(TOUCH_EVENTS) @@ -458,7 +680,7 @@ void EventSendingController::addTouchPoint(int x, int y) WKRetainPtr<WKUInt64Ref> yRef(AdoptWK, WKUInt64Create(y)); WKDictionarySetItem(EventSenderMessageBody.get(), yKey.get(), yRef.get()); - WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); + WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::updateTouchPoint(int index, int x, int y) @@ -482,7 +704,7 @@ void EventSendingController::updateTouchPoint(int index, int x, int y) WKRetainPtr<WKUInt64Ref> yRef(AdoptWK, WKUInt64Create(y)); WKDictionarySetItem(EventSenderMessageBody.get(), yKey.get(), yRef.get()); - WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); + WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::setTouchModifier(const JSStringRef &modifier, bool enable) @@ -512,7 +734,7 @@ void EventSendingController::setTouchModifier(const JSStringRef &modifier, bool WKRetainPtr<WKUInt64Ref> enableRef(AdoptWK, WKUInt64Create(enable)); WKDictionarySetItem(EventSenderMessageBody.get(), enableKey.get(), enableRef.get()); - WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); + WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } @@ -533,7 +755,7 @@ void EventSendingController::setTouchPointRadius(int radiusX, int radiusY) WKRetainPtr<WKUInt64Ref> yRef(AdoptWK, WKUInt64Create(radiusY)); WKDictionarySetItem(EventSenderMessageBody.get(), yKey.get(), yRef.get()); - WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); + WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::touchStart() @@ -545,7 +767,7 @@ void EventSendingController::touchStart() WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("TouchStart")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); - WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); + WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::touchMove() @@ -557,7 +779,7 @@ void EventSendingController::touchMove() WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("TouchMove")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); - WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); + WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::touchEnd() @@ -569,7 +791,7 @@ void EventSendingController::touchEnd() WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("TouchEnd")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); - WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); + WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::touchCancel() @@ -581,7 +803,7 @@ void EventSendingController::touchCancel() WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("TouchCancel")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); - WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); + WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::clearTouchPoints() @@ -593,7 +815,7 @@ void EventSendingController::clearTouchPoints() WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("ClearTouchPoints")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); - WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); + WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::releaseTouchPoint(int index) @@ -609,7 +831,7 @@ void EventSendingController::releaseTouchPoint(int index) WKRetainPtr<WKUInt64Ref> indexRef(AdoptWK, WKUInt64Create(index)); WKDictionarySetItem(EventSenderMessageBody.get(), indexKey.get(), indexRef.get()); - WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); + WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::cancelTouchPoint(int index) @@ -625,7 +847,7 @@ void EventSendingController::cancelTouchPoint(int index) WKRetainPtr<WKUInt64Ref> indexRef(AdoptWK, WKUInt64Create(index)); WKDictionarySetItem(EventSenderMessageBody.get(), indexKey.get(), indexRef.get()); - WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); + WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } #endif diff --git a/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.h b/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.h index c6a9131e4..3eb8129c7 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.h +++ b/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2010, 2011, 2014-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,19 +23,18 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef EventSendingController_h -#define EventSendingController_h +#pragma once #include "JSWrappable.h" -#include <WebKit2/WKEvent.h> -#include <WebKit2/WKGeometry.h> -#include <wtf/PassRefPtr.h> +#include <WebKit/WKEvent.h> +#include <WebKit/WKGeometry.h> +#include <wtf/Ref.h> namespace WTR { class EventSendingController : public JSWrappable { public: - static PassRefPtr<EventSendingController> create(); + static Ref<EventSendingController> create(); virtual ~EventSendingController(); void makeWindowObject(JSContextRef, JSObjectRef windowObject, JSValueRef* exception); @@ -46,11 +45,20 @@ public: void mouseDown(int button, JSValueRef modifierArray); void mouseUp(int button, JSValueRef modifierArray); void mouseMoveTo(int x, int y); + void mouseForceClick(); + void startAndCancelMouseForceClick(); + void mouseForceDown(); + void mouseForceUp(); + void mouseForceChanged(double force); void mouseScrollBy(int x, int y); + void mouseScrollByWithWheelAndMomentumPhases(int x, int y, JSStringRef phase, JSStringRef momentum); + void swipeGestureWithWheelAndMomentumPhases(int x, int y, JSStringRef phase, JSStringRef momentum); void continuousMouseScrollBy(int x, int y, bool paged); JSValueRef contextClick(); void leapForward(int milliseconds); void scheduleAsynchronousClick(); + void monitorWheelEvents(); + void callAfterScrollingCompletes(JSValueRef functionCallback); void keyDown(JSStringRef key, JSValueRef modifierArray, int location); void scheduleAsynchronousKeyDown(JSStringRef key); @@ -79,8 +87,7 @@ public: private: EventSendingController(); + WKPoint m_position; }; } // namespace WTR - -#endif // EventSendingController_h diff --git a/Tools/WebKitTestRunner/InjectedBundle/GCController.cpp b/Tools/WebKitTestRunner/InjectedBundle/GCController.cpp index 10c21dba8..9358f4a0d 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/GCController.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/GCController.cpp @@ -28,13 +28,13 @@ #include "InjectedBundle.h" #include "JSGCController.h" -#include <WebKit2/WKBundlePrivate.h> +#include <WebKit/WKBundlePrivate.h> namespace WTR { -PassRefPtr<GCController> GCController::create() +Ref<GCController> GCController::create() { - return adoptRef(new GCController); + return adoptRef(*new GCController); } GCController::GCController() @@ -52,17 +52,17 @@ JSClassRef GCController::wrapperClass() void GCController::collect() { - WKBundleGarbageCollectJavaScriptObjects(InjectedBundle::shared().bundle()); + WKBundleGarbageCollectJavaScriptObjects(InjectedBundle::singleton().bundle()); } void GCController::collectOnAlternateThread(bool waitUntilDone) { - WKBundleGarbageCollectJavaScriptObjectsOnAlternateThreadForDebugging(InjectedBundle::shared().bundle(), waitUntilDone); + WKBundleGarbageCollectJavaScriptObjectsOnAlternateThreadForDebugging(InjectedBundle::singleton().bundle(), waitUntilDone); } size_t GCController::getJSObjectCount() { - return WKBundleGetJavaScriptObjectsCount(InjectedBundle::shared().bundle()); + return WKBundleGetJavaScriptObjectsCount(InjectedBundle::singleton().bundle()); } // Object Creation diff --git a/Tools/WebKitTestRunner/InjectedBundle/GCController.h b/Tools/WebKitTestRunner/InjectedBundle/GCController.h index 760fbb1e6..d349c1ce9 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/GCController.h +++ b/Tools/WebKitTestRunner/InjectedBundle/GCController.h @@ -23,17 +23,16 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef GCController_h -#define GCController_h +#pragma once #include "JSWrappable.h" -#include <wtf/PassRefPtr.h> +#include <wtf/Ref.h> namespace WTR { class GCController : public JSWrappable { public: - static PassRefPtr<GCController> create(); + static Ref<GCController> create(); virtual ~GCController(); void makeWindowObject(JSContextRef, JSObjectRef windowObject, JSValueRef* exception); @@ -50,5 +49,3 @@ private: }; } // namespace WTR - -#endif // GCController_h diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp index f71fe9360..f247b362b 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010, 2011, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2010-2017 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,20 +29,20 @@ #include "ActivateFonts.h" #include "InjectedBundlePage.h" #include "StringFunctions.h" -#include <WebKit2/WKBundle.h> -#include <WebKit2/WKBundlePage.h> -#include <WebKit2/WKBundlePagePrivate.h> -#include <WebKit2/WKBundlePrivate.h> -#include <WebKit2/WKRetainPtr.h> -#include <WebKit2/WebKit2_C.h> -#include <wtf/PassOwnPtr.h> +#include "WebCoreTestSupport.h" +#include <WebKit/WKBundle.h> +#include <WebKit/WKBundlePage.h> +#include <WebKit/WKBundlePagePrivate.h> +#include <WebKit/WKBundlePrivate.h> +#include <WebKit/WKRetainPtr.h> +#include <WebKit/WebKit2_C.h> #include <wtf/text/CString.h> #include <wtf/text/StringBuilder.h> #include <wtf/Vector.h> namespace WTR { -InjectedBundle& InjectedBundle::shared() +InjectedBundle& InjectedBundle::singleton() { static InjectedBundle& shared = *new InjectedBundle; return shared; @@ -101,23 +101,18 @@ void InjectedBundle::initialize(WKBundleRef bundle, WKTypeRef initializationUser platformInitialize(initializationUserData); activateFonts(); - WKBundleActivateMacFontAscentHack(m_bundle); } void InjectedBundle::didCreatePage(WKBundlePageRef page) { - m_pages.append(adoptPtr(new InjectedBundlePage(page))); + m_pages.append(std::make_unique<InjectedBundlePage>(page)); } void InjectedBundle::willDestroyPage(WKBundlePageRef page) { - size_t size = m_pages.size(); - for (size_t i = 0; i < size; ++i) { - if (m_pages[i]->page() == page) { - m_pages.remove(i); - break; - } - } + m_pages.removeFirstMatching([page](auto& current) { + return current->page() == page; + }); } void InjectedBundle::didInitializePageGroup(WKBundlePageGroupRef pageGroup) @@ -139,6 +134,13 @@ void InjectedBundle::resetLocalSettings() void InjectedBundle::didReceiveMessage(WKStringRef messageName, WKTypeRef messageBody) { + WKRetainPtr<WKStringRef> errorMessageName(AdoptWK, WKStringCreateWithUTF8CString("Error")); + WKRetainPtr<WKStringRef> errorMessageBody(AdoptWK, WKStringCreateWithUTF8CString("Unknown")); + WKBundlePostMessage(m_bundle, errorMessageName.get(), errorMessageBody.get()); +} + +void InjectedBundle::didReceiveMessageToPage(WKBundlePageRef page, WKStringRef messageName, WKTypeRef messageBody) +{ if (WKStringIsEqualToUTF8CString(messageName, "BeginTest")) { ASSERT(messageBody); ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID()); @@ -153,13 +155,18 @@ void InjectedBundle::didReceiveMessage(WKStringRef messageName, WKTypeRef messag WKRetainPtr<WKStringRef> timeoutKey(AdoptWK, WKStringCreateWithUTF8CString("Timeout")); m_timeout = (int)WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, timeoutKey.get()))); + WKRetainPtr<WKStringRef> dumpJSConsoleLogInStdErrKey(AdoptWK, WKStringCreateWithUTF8CString("DumpJSConsoleLogInStdErr")); + m_dumpJSConsoleLogInStdErr = WKBooleanGetValue(static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, dumpJSConsoleLogInStdErrKey.get()))); + WKRetainPtr<WKStringRef> ackMessageName(AdoptWK, WKStringCreateWithUTF8CString("Ack")); WKRetainPtr<WKStringRef> ackMessageBody(AdoptWK, WKStringCreateWithUTF8CString("BeginTest")); - WKBundlePostMessage(m_bundle, ackMessageName.get(), ackMessageBody.get()); + WKBundlePagePostMessage(page, ackMessageName.get(), ackMessageBody.get()); beginTesting(messageBodyDictionary); return; - } else if (WKStringIsEqualToUTF8CString(messageName, "Reset")) { + } + + if (WKStringIsEqualToUTF8CString(messageName, "Reset")) { ASSERT(messageBody); ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID()); WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody); @@ -170,48 +177,103 @@ void InjectedBundle::didReceiveMessage(WKStringRef messageName, WKTypeRef messag if (shouldGC) WKBundleGarbageCollectJavaScriptObjects(m_bundle); + WKRetainPtr<WKStringRef> allowedHostsKey(AdoptWK, WKStringCreateWithUTF8CString("AllowedHosts")); + WKTypeRef allowedHostsValue = WKDictionaryGetItemForKey(messageBodyDictionary, allowedHostsKey.get()); + if (allowedHostsValue && WKGetTypeID(allowedHostsValue) == WKArrayGetTypeID()) { + WKArrayRef allowedHostsArray = static_cast<WKArrayRef>(allowedHostsValue); + for (size_t i = 0, size = WKArrayGetSize(allowedHostsArray); i < size; ++i) { + WKTypeRef item = WKArrayGetItemAtIndex(allowedHostsArray, i); + if (item && WKGetTypeID(item) == WKStringGetTypeID()) + m_allowedHosts.append(toWTFString(static_cast<WKStringRef>(item))); + } + } + m_state = Idle; m_dumpPixels = false; + m_pixelResultIsPending = false; resetLocalSettings(); - m_testRunner->removeAllWebNotificationPermissions(); + TestRunner::removeAllWebNotificationPermissions(); - page()->resetAfterTest(); + InjectedBundle::page()->resetAfterTest(); return; } + if (WKStringIsEqualToUTF8CString(messageName, "CallAddChromeInputFieldCallback")) { m_testRunner->callAddChromeInputFieldCallback(); return; } + if (WKStringIsEqualToUTF8CString(messageName, "CallRemoveChromeInputFieldCallback")) { m_testRunner->callRemoveChromeInputFieldCallback(); return; } + if (WKStringIsEqualToUTF8CString(messageName, "CallFocusWebViewCallback")) { m_testRunner->callFocusWebViewCallback(); return; } + if (WKStringIsEqualToUTF8CString(messageName, "CallSetBackingScaleFactorCallback")) { m_testRunner->callSetBackingScaleFactorCallback(); return; - } + } + + if (WKStringIsEqualToUTF8CString(messageName, "CallDidBeginSwipeCallback")) { + m_testRunner->callDidBeginSwipeCallback(); + return; + } + + if (WKStringIsEqualToUTF8CString(messageName, "CallWillEndSwipeCallback")) { + m_testRunner->callWillEndSwipeCallback(); + return; + } + + if (WKStringIsEqualToUTF8CString(messageName, "CallDidEndSwipeCallback")) { + m_testRunner->callDidEndSwipeCallback(); + return; + } + + if (WKStringIsEqualToUTF8CString(messageName, "CallDidRemoveSwipeSnapshotCallback")) { + m_testRunner->callDidRemoveSwipeSnapshotCallback(); + return; + } + + if (WKStringIsEqualToUTF8CString(messageName, "NotifyDownloadDone")) { + m_testRunner->notifyDone(); + return; + } + + if (WKStringIsEqualToUTF8CString(messageName, "CallUISideScriptCallback")) { + WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody); + + WKRetainPtr<WKStringRef> resultKey(AdoptWK, WKStringCreateWithUTF8CString("Result")); + WKRetainPtr<WKStringRef> callbackIDKey(AdoptWK, WKStringCreateWithUTF8CString("CallbackID")); + + unsigned callbackID = (unsigned)WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, callbackIDKey.get()))); + + WKStringRef resultString = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, resultKey.get())); + auto resultJSString = toJS(resultString); + + m_testRunner->runUIScriptCallback(callbackID, resultJSString.get()); + return; + } + if (WKStringIsEqualToUTF8CString(messageName, "WorkQueueProcessedCallback")) { if (!topLoadingFrame() && !m_testRunner->waitToDump()) - page()->dump(); + InjectedBundle::page()->dump(); return; } - WKRetainPtr<WKStringRef> errorMessageName(AdoptWK, WKStringCreateWithUTF8CString("Error")); - WKRetainPtr<WKStringRef> errorMessageBody(AdoptWK, WKStringCreateWithUTF8CString("Unknown")); - WKBundlePostMessage(m_bundle, errorMessageName.get(), errorMessageBody.get()); -} + if (WKStringIsEqualToUTF8CString(messageName, "WebsiteDataDeletionForTopPrivatelyOwnedDomainsFinished")) { + m_testRunner->statisticsDidModifyDataRecordsCallback(); + return; + } -void InjectedBundle::didReceiveMessageToPage(WKBundlePageRef page, WKStringRef messageName, WKTypeRef messageBody) -{ WKRetainPtr<WKStringRef> errorMessageName(AdoptWK, WKStringCreateWithUTF8CString("Error")); WKRetainPtr<WKStringRef> errorMessageBody(AdoptWK, WKStringCreateWithUTF8CString("Unknown")); - WKBundlePostMessage(m_bundle, errorMessageName.get(), errorMessageBody.get()); + WKBundlePagePostMessage(page, errorMessageName.get(), errorMessageBody.get()); } bool InjectedBundle::booleanForKey(WKDictionaryRef dictionary, const char* key) @@ -236,41 +298,60 @@ void InjectedBundle::beginTesting(WKDictionaryRef settings) m_gcController = GCController::create(); m_eventSendingController = EventSendingController::create(); m_textInputController = TextInputController::create(); +#if HAVE(ACCESSIBILITY) m_accessibilityController = AccessibilityController::create(); +#endif - WKBundleSetShouldTrackVisitedLinks(m_bundle, false); - WKBundleRemoveAllVisitedLinks(m_bundle); WKBundleSetAllowUniversalAccessFromFileURLs(m_bundle, m_pageGroup, true); WKBundleSetJavaScriptCanAccessClipboard(m_bundle, m_pageGroup, true); WKBundleSetPrivateBrowsingEnabled(m_bundle, m_pageGroup, false); + WKBundleSetUseDashboardCompatibilityMode(m_bundle, m_pageGroup, false); WKBundleSetAuthorAndUserStylesEnabled(m_bundle, m_pageGroup, true); WKBundleSetFrameFlatteningEnabled(m_bundle, m_pageGroup, false); WKBundleSetMinimumLogicalFontSize(m_bundle, m_pageGroup, 9); WKBundleSetSpatialNavigationEnabled(m_bundle, m_pageGroup, false); WKBundleSetAllowFileAccessFromFileURLs(m_bundle, m_pageGroup, true); - WKBundleSetPluginsEnabled(m_bundle, m_pageGroup, true); WKBundleSetPopupBlockingEnabled(m_bundle, m_pageGroup, false); - WKBundleSetAlwaysAcceptCookies(m_bundle, false); - WKBundleSetSerialLoadingEnabled(m_bundle, false); - WKBundleSetShadowDOMEnabled(m_bundle, true); - WKBundleSetSeamlessIFramesEnabled(m_bundle, true); - WKBundleSetCacheModel(m_bundle, 1 /*CacheModelDocumentBrowser*/); + WKBundleSetAllowStorageAccessFromFileURLS(m_bundle, m_pageGroup, false); - WKBundleRemoveAllUserContent(m_bundle, m_pageGroup); +#if PLATFORM(IOS) + WKBundlePageSetUseTestingViewportConfiguration(page()->page(), !booleanForKey(settings, "UseFlexibleViewport")); +#endif + + m_testRunner->setPluginsEnabled(true); m_testRunner->setShouldDumpFrameLoadCallbacks(booleanForKey(settings, "DumpFrameLoadDelegates")); m_testRunner->setUserStyleSheetEnabled(false); m_testRunner->setXSSAuditorEnabled(false); + + m_testRunner->setShadowDOMEnabled(true); + m_testRunner->setCustomElementsEnabled(true); + + m_testRunner->setWebGL2Enabled(true); + + m_testRunner->setFetchAPIEnabled(true); + + m_testRunner->setDownloadAttributeEnabled(true); + + m_testRunner->setEncryptedMediaAPIEnabled(true); + m_testRunner->setCloseRemainingWindowsWhenComplete(false); m_testRunner->setAcceptsEditing(true); m_testRunner->setTabKeyCyclesThroughElements(true); + m_testRunner->clearTestRunnerCallbacks(); + + m_testRunner->setSubtleCryptoEnabled(true); - m_testRunner->setCustomTimeout(m_timeout); + m_testRunner->setMediaStreamEnabled(true); + m_testRunner->setPeerConnectionEnabled(true); + + if (m_timeout > 0) + m_testRunner->setCustomTimeout(m_timeout); page()->prepare(); WKBundleClearAllDatabases(m_bundle); - WKBundleClearApplicationCache(m_bundle); + WKBundlePageClearApplicationCache(page()->page()); WKBundleResetOriginAccessWhitelists(m_bundle); // [WK2] REGRESSION(r128623): It made layout tests extremely slow @@ -287,13 +368,21 @@ void InjectedBundle::done() page()->stopLoading(); setTopLoadingFrame(0); + m_testRunner->invalidateWaitToDumpWatchdogTimer(); + m_accessibilityController->resetToConsistentState(); WKRetainPtr<WKStringRef> doneMessageName(AdoptWK, WKStringCreateWithUTF8CString("Done")); WKRetainPtr<WKMutableDictionaryRef> doneMessageBody(AdoptWK, WKMutableDictionaryCreate()); - WKRetainPtr<WKStringRef> pixelResultKey = adoptWK(WKStringCreateWithUTF8CString("PixelResult")); - WKDictionarySetItem(doneMessageBody.get(), pixelResultKey.get(), m_pixelResult.get()); + WKRetainPtr<WKStringRef> pixelResultIsPendingKey = adoptWK(WKStringCreateWithUTF8CString("PixelResultIsPending")); + WKRetainPtr<WKBooleanRef> pixelResultIsPending(AdoptWK, WKBooleanCreate(m_pixelResultIsPending)); + WKDictionarySetItem(doneMessageBody.get(), pixelResultIsPendingKey.get(), pixelResultIsPending.get()); + + if (!m_pixelResultIsPending) { + WKRetainPtr<WKStringRef> pixelResultKey = adoptWK(WKStringCreateWithUTF8CString("PixelResult")); + WKDictionarySetItem(doneMessageBody.get(), pixelResultKey.get(), m_pixelResult.get()); + } WKRetainPtr<WKStringRef> repaintRectsKey = adoptWK(WKStringCreateWithUTF8CString("RepaintRects")); WKDictionarySetItem(doneMessageBody.get(), repaintRectsKey.get(), m_repaintRects.get()); @@ -301,7 +390,7 @@ void InjectedBundle::done() WKRetainPtr<WKStringRef> audioResultKey = adoptWK(WKStringCreateWithUTF8CString("AudioResult")); WKDictionarySetItem(doneMessageBody.get(), audioResultKey.get(), m_audioResult.get()); - WKBundlePostMessage(m_bundle, doneMessageName.get(), doneMessageBody.get()); + WKBundlePagePostMessage(page()->page(), doneMessageName.get(), doneMessageBody.get()); closeOtherPages(); @@ -326,6 +415,17 @@ void InjectedBundle::dumpBackForwardListsForAllPages(StringBuilder& stringBuilde m_pages[i]->dumpBackForwardList(stringBuilder); } +void InjectedBundle::dumpToStdErr(const String& output) +{ + if (m_state != Testing) + return; + if (output.isEmpty()) + return; + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("DumpToStdErr")); + WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithUTF8CString(output.utf8().data())); + WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); +} + void InjectedBundle::outputText(const String& output) { if (m_state != Testing) @@ -334,60 +434,85 @@ void InjectedBundle::outputText(const String& output) return; WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("TextOutput")); WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithUTF8CString(output.utf8().data())); - WKBundlePostMessage(m_bundle, messageName.get(), messageBody.get()); + WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); } void InjectedBundle::postNewBeforeUnloadReturnValue(bool value) { WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("BeforeUnloadReturnValue")); WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value)); - WKBundlePostMessage(m_bundle, messageName.get(), messageBody.get()); + WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); } void InjectedBundle::postAddChromeInputField() { WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("AddChromeInputField")); - WKBundlePostMessage(m_bundle, messageName.get(), 0); + WKBundlePagePostMessage(page()->page(), messageName.get(), 0); } void InjectedBundle::postRemoveChromeInputField() { WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("RemoveChromeInputField")); - WKBundlePostMessage(m_bundle, messageName.get(), 0); + WKBundlePagePostMessage(page()->page(), messageName.get(), 0); } void InjectedBundle::postFocusWebView() { WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("FocusWebView")); - WKBundlePostMessage(m_bundle, messageName.get(), 0); + WKBundlePagePostMessage(page()->page(), messageName.get(), 0); } void InjectedBundle::postSetBackingScaleFactor(double backingScaleFactor) { WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetBackingScaleFactor")); WKRetainPtr<WKDoubleRef> messageBody(AdoptWK, WKDoubleCreate(backingScaleFactor)); - WKBundlePostMessage(m_bundle, messageName.get(), messageBody.get()); + WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); } void InjectedBundle::postSetWindowIsKey(bool isKey) { WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetWindowIsKey")); WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(isKey)); - WKBundlePostSynchronousMessage(m_bundle, messageName.get(), messageBody.get(), 0); + WKBundlePagePostSynchronousMessageForTesting(page()->page(), messageName.get(), messageBody.get(), 0); +} + +void InjectedBundle::postSetViewSize(double width, double height) +{ + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetViewSize")); + + WKRetainPtr<WKStringRef> widthKey(AdoptWK, WKStringCreateWithUTF8CString("width")); + WKRetainPtr<WKStringRef> heightKey(AdoptWK, WKStringCreateWithUTF8CString("height")); + + WKRetainPtr<WKMutableDictionaryRef> messageBody(AdoptWK, WKMutableDictionaryCreate()); + + WKRetainPtr<WKDoubleRef> widthWK(AdoptWK, WKDoubleCreate(width)); + WKDictionarySetItem(messageBody.get(), widthKey.get(), widthWK.get()); + + WKRetainPtr<WKDoubleRef> heightWK(AdoptWK, WKDoubleCreate(height)); + WKDictionarySetItem(messageBody.get(), heightKey.get(), heightWK.get()); + + WKBundlePagePostSynchronousMessageForTesting(page()->page(), messageName.get(), messageBody.get(), 0); } void InjectedBundle::postSimulateWebNotificationClick(uint64_t notificationID) { WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SimulateWebNotificationClick")); WKRetainPtr<WKUInt64Ref> messageBody(AdoptWK, WKUInt64Create(notificationID)); - WKBundlePostMessage(m_bundle, messageName.get(), messageBody.get()); + WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); +} + +void InjectedBundle::postSetAddsVisitedLinks(bool addsVisitedLinks) +{ + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAddsVisitedLinks")); + WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(addsVisitedLinks)); + WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); } void InjectedBundle::setGeolocationPermission(bool enabled) { WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetGeolocationPermission")); WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(enabled)); - WKBundlePostMessage(m_bundle, messageName.get(), messageBody.get()); + WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); } void InjectedBundle::setMockGeolocationPosition(double latitude, double longitude, double accuracy, bool providesAltitude, double altitude, bool providesAltitudeAccuracy, double altitudeAccuracy, bool providesHeading, double heading, bool providesSpeed, double speed) @@ -440,13 +565,90 @@ void InjectedBundle::setMockGeolocationPosition(double latitude, double longitud WKRetainPtr<WKDoubleRef> speedWK(AdoptWK, WKDoubleCreate(speed)); WKDictionarySetItem(messageBody.get(), speedKeyWK.get(), speedWK.get()); - WKBundlePostMessage(m_bundle, messageName.get(), messageBody.get()); + WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); } void InjectedBundle::setMockGeolocationPositionUnavailableError(WKStringRef errorMessage) { WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGeolocationPositionUnavailableError")); - WKBundlePostMessage(m_bundle, messageName.get(), errorMessage); + WKBundlePagePostMessage(page()->page(), messageName.get(), errorMessage); +} + +bool InjectedBundle::isGeolocationProviderActive() const +{ + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsGeolocationClientActive")); + WKTypeRef resultToPass = 0; + WKBundlePagePostSynchronousMessageForTesting(page()->page(), messageName.get(), 0, &resultToPass); + WKRetainPtr<WKBooleanRef> isActive(AdoptWK, static_cast<WKBooleanRef>(resultToPass)); + + return WKBooleanGetValue(isActive.get()); +} + +unsigned InjectedBundle::imageCountInGeneralPasteboard() const +{ + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ImageCountInGeneralPasteboard")); + WKTypeRef resultToPass = 0; + WKBundlePagePostSynchronousMessageForTesting(page()->page(), messageName.get(), 0, &resultToPass); + WKRetainPtr<WKUInt64Ref> imageCount(AdoptWK, static_cast<WKUInt64Ref>(resultToPass)); + + return static_cast<unsigned>(WKUInt64GetValue(imageCount.get())); +} + +void InjectedBundle::setUserMediaPermission(bool enabled) +{ + auto messageName = adoptWK(WKStringCreateWithUTF8CString("SetUserMediaPermission")); + auto messageBody = adoptWK(WKBooleanCreate(enabled)); + WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); +} + +void InjectedBundle::setUserMediaPersistentPermissionForOrigin(bool permission, WKStringRef origin, WKStringRef parentOrigin) +{ + auto messageName = adoptWK(WKStringCreateWithUTF8CString("SetUserMediaPersistentPermissionForOrigin")); + WKRetainPtr<WKMutableDictionaryRef> messageBody(AdoptWK, WKMutableDictionaryCreate()); + + WKRetainPtr<WKStringRef> permissionKeyWK(AdoptWK, WKStringCreateWithUTF8CString("permission")); + WKRetainPtr<WKBooleanRef> permissionWK(AdoptWK, WKBooleanCreate(permission)); + WKDictionarySetItem(messageBody.get(), permissionKeyWK.get(), permissionWK.get()); + + WKRetainPtr<WKStringRef> originKeyWK(AdoptWK, WKStringCreateWithUTF8CString("origin")); + WKDictionarySetItem(messageBody.get(), originKeyWK.get(), origin); + + WKRetainPtr<WKStringRef> parentOriginKeyWK(AdoptWK, WKStringCreateWithUTF8CString("parentOrigin")); + WKDictionarySetItem(messageBody.get(), parentOriginKeyWK.get(), parentOrigin); + + WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); +} + +unsigned InjectedBundle::userMediaPermissionRequestCountForOrigin(WKStringRef origin, WKStringRef parentOrigin) const +{ + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("UserMediaPermissionRequestCountForOrigin")); + WKRetainPtr<WKMutableDictionaryRef> messageBody(AdoptWK, WKMutableDictionaryCreate()); + + WKRetainPtr<WKStringRef> originKeyWK(AdoptWK, WKStringCreateWithUTF8CString("origin")); + WKDictionarySetItem(messageBody.get(), originKeyWK.get(), origin); + + WKRetainPtr<WKStringRef> parentOriginKeyWK(AdoptWK, WKStringCreateWithUTF8CString("parentOrigin")); + WKDictionarySetItem(messageBody.get(), parentOriginKeyWK.get(), parentOrigin); + + WKTypeRef resultToPass = 0; + WKBundlePagePostSynchronousMessageForTesting(page()->page(), messageName.get(), messageBody.get(), &resultToPass); + WKRetainPtr<WKUInt64Ref> count(AdoptWK, static_cast<WKUInt64Ref>(resultToPass)); + + return static_cast<unsigned>(WKUInt64GetValue(count.get())); +} + +void InjectedBundle::resetUserMediaPermissionRequestCountForOrigin(WKStringRef origin, WKStringRef parentOrigin) +{ + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ResetUserMediaPermissionRequestCountForOrigin")); + WKRetainPtr<WKMutableDictionaryRef> messageBody(AdoptWK, WKMutableDictionaryCreate()); + + WKRetainPtr<WKStringRef> originKeyWK(AdoptWK, WKStringCreateWithUTF8CString("origin")); + WKDictionarySetItem(messageBody.get(), originKeyWK.get(), origin); + + WKRetainPtr<WKStringRef> parentOriginKeyWK(AdoptWK, WKStringCreateWithUTF8CString("parentOrigin")); + WKDictionarySetItem(messageBody.get(), parentOriginKeyWK.get(), parentOrigin); + + WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); } void InjectedBundle::setCustomPolicyDelegate(bool enabled, bool permissive) @@ -463,23 +665,26 @@ void InjectedBundle::setCustomPolicyDelegate(bool enabled, bool permissive) WKRetainPtr<WKBooleanRef> permissiveWK(AdoptWK, WKBooleanCreate(permissive)); WKDictionarySetItem(messageBody.get(), permissiveKeyWK.get(), permissiveWK.get()); - WKBundlePostMessage(m_bundle, messageName.get(), messageBody.get()); + WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); } -void InjectedBundle::setVisibilityState(WKPageVisibilityState visibilityState, bool isInitialState) +void InjectedBundle::setHidden(bool hidden) { - WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetVisibilityState")); + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetHidden")); WKRetainPtr<WKMutableDictionaryRef> messageBody(AdoptWK, WKMutableDictionaryCreate()); - WKRetainPtr<WKStringRef> visibilityStateKeyWK(AdoptWK, WKStringCreateWithUTF8CString("visibilityState")); - WKRetainPtr<WKUInt64Ref> visibilityStateWK(AdoptWK, WKUInt64Create(visibilityState)); - WKDictionarySetItem(messageBody.get(), visibilityStateKeyWK.get(), visibilityStateWK.get()); - - WKRetainPtr<WKStringRef> isInitialKeyWK(AdoptWK, WKStringCreateWithUTF8CString("isInitialState")); - WKRetainPtr<WKBooleanRef> isInitialWK(AdoptWK, WKBooleanCreate(isInitialState)); + WKRetainPtr<WKStringRef> isInitialKeyWK(AdoptWK, WKStringCreateWithUTF8CString("hidden")); + WKRetainPtr<WKBooleanRef> isInitialWK(AdoptWK, WKBooleanCreate(hidden)); WKDictionarySetItem(messageBody.get(), isInitialKeyWK.get(), isInitialWK.get()); - WKBundlePostMessage(m_bundle, messageName.get(), messageBody.get()); + WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); +} + +void InjectedBundle::setCacheModel(int model) +{ + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetCacheModel")); + WKRetainPtr<WKUInt64Ref> messageBody(AdoptWK, WKUInt64Create(model)); + WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); } bool InjectedBundle::shouldProcessWorkQueue() const @@ -489,7 +694,7 @@ bool InjectedBundle::shouldProcessWorkQueue() const WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsWorkQueueEmpty")); WKTypeRef resultToPass = 0; - WKBundlePostSynchronousMessage(m_bundle, messageName.get(), 0, &resultToPass); + WKBundlePagePostSynchronousMessageForTesting(page()->page(), messageName.get(), 0, &resultToPass); WKRetainPtr<WKBooleanRef> isEmpty(AdoptWK, static_cast<WKBooleanRef>(resultToPass)); return !WKBooleanGetValue(isEmpty.get()); @@ -498,7 +703,7 @@ bool InjectedBundle::shouldProcessWorkQueue() const void InjectedBundle::processWorkQueue() { WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ProcessWorkQueue")); - WKBundlePostMessage(m_bundle, messageName.get(), 0); + WKBundlePagePostMessage(page()->page(), messageName.get(), 0); } void InjectedBundle::queueBackNavigation(unsigned howFarBackward) @@ -507,7 +712,7 @@ void InjectedBundle::queueBackNavigation(unsigned howFarBackward) WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("QueueBackNavigation")); WKRetainPtr<WKUInt64Ref> messageBody(AdoptWK, WKUInt64Create(howFarBackward)); - WKBundlePostMessage(m_bundle, messageName.get(), messageBody.get()); + WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); } void InjectedBundle::queueForwardNavigation(unsigned howFarForward) @@ -516,10 +721,10 @@ void InjectedBundle::queueForwardNavigation(unsigned howFarForward) WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("QueueForwardNavigation")); WKRetainPtr<WKUInt64Ref> messageBody(AdoptWK, WKUInt64Create(howFarForward)); - WKBundlePostMessage(m_bundle, messageName.get(), messageBody.get()); + WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); } -void InjectedBundle::queueLoad(WKStringRef url, WKStringRef target) +void InjectedBundle::queueLoad(WKStringRef url, WKStringRef target, bool shouldOpenExternalURLs) { m_useWorkQueue = true; @@ -533,7 +738,11 @@ void InjectedBundle::queueLoad(WKStringRef url, WKStringRef target) WKRetainPtr<WKStringRef> targetKey(AdoptWK, WKStringCreateWithUTF8CString("target")); WKDictionarySetItem(loadData.get(), targetKey.get(), target); - WKBundlePostMessage(m_bundle, messageName.get(), loadData.get()); + WKRetainPtr<WKStringRef> shouldOpenExternalURLsKey(AdoptWK, WKStringCreateWithUTF8CString("shouldOpenExternalURLs")); + WKRetainPtr<WKBooleanRef> shouldOpenExternalURLsValue(AdoptWK, WKBooleanCreate(shouldOpenExternalURLs)); + WKDictionarySetItem(loadData.get(), shouldOpenExternalURLsKey.get(), shouldOpenExternalURLsValue.get()); + + WKBundlePagePostMessage(page()->page(), messageName.get(), loadData.get()); } void InjectedBundle::queueLoadHTMLString(WKStringRef content, WKStringRef baseURL, WKStringRef unreachableURL) @@ -557,7 +766,7 @@ void InjectedBundle::queueLoadHTMLString(WKStringRef content, WKStringRef baseUR WKDictionarySetItem(loadData.get(), unreachableURLKey.get(), unreachableURL); } - WKBundlePostMessage(m_bundle, messageName.get(), loadData.get()); + WKBundlePagePostMessage(page()->page(), messageName.get(), loadData.get()); } void InjectedBundle::queueReload() @@ -565,7 +774,7 @@ void InjectedBundle::queueReload() m_useWorkQueue = true; WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("QueueReload")); - WKBundlePostMessage(m_bundle, messageName.get(), 0); + WKBundlePagePostMessage(page()->page(), messageName.get(), 0); } void InjectedBundle::queueLoadingScript(WKStringRef script) @@ -573,7 +782,7 @@ void InjectedBundle::queueLoadingScript(WKStringRef script) m_useWorkQueue = true; WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("QueueLoadingScript")); - WKBundlePostMessage(m_bundle, messageName.get(), script); + WKBundlePagePostMessage(page()->page(), messageName.get(), script); } void InjectedBundle::queueNonLoadingScript(WKStringRef script) @@ -581,7 +790,19 @@ void InjectedBundle::queueNonLoadingScript(WKStringRef script) m_useWorkQueue = true; WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("QueueNonLoadingScript")); - WKBundlePostMessage(m_bundle, messageName.get(), script); + WKBundlePagePostMessage(page()->page(), messageName.get(), script); +} + +bool InjectedBundle::isAllowedHost(WKStringRef host) +{ + if (m_allowedHosts.isEmpty()) + return false; + return m_allowedHosts.contains(toWTFString(host)); +} + +void InjectedBundle::setAllowsAnySSLCertificate(bool allowsAnySSLCertificate) +{ + WebCoreTestSupport::setAllowsAnySSLCertificate(allowsAnySSLCertificate); } } // namespace WTR diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h index 170c8ac70..2edd5e797 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h +++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010, 2011, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2010-2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,29 +23,30 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef InjectedBundle_h -#define InjectedBundle_h +#pragma once -#include "AccessibilityController.h" #include "EventSendingController.h" #include "GCController.h" #include "TestRunner.h" #include "TextInputController.h" -#include <WebKit2/WKBase.h> -#include <WebKit2/WKRetainPtr.h> +#include <WebKit/WKBase.h> +#include <WebKit/WKRetainPtr.h> #include <sstream> #include <wtf/Forward.h> -#include <wtf/OwnPtr.h> #include <wtf/RefPtr.h> #include <wtf/Vector.h> +#if HAVE(ACCESSIBILITY) +#include "AccessibilityController.h" +#endif + namespace WTR { class InjectedBundlePage; class InjectedBundle { public: - static InjectedBundle& shared(); + static InjectedBundle& singleton(); // Initialize the InjectedBundle. void initialize(WKBundleRef, WKTypeRef initializationUserData); @@ -57,7 +58,9 @@ public: GCController* gcController() { return m_gcController.get(); } EventSendingController* eventSendingController() { return m_eventSendingController.get(); } TextInputController* textInputController() { return m_textInputController.get(); } +#if HAVE(ACCESSIBILITY) AccessibilityController* accessibilityController() { return m_accessibilityController.get(); } +#endif InjectedBundlePage* page() const; size_t pageCount() const { return m_pages.size(); } @@ -67,7 +70,8 @@ public: void done(); void setAudioResult(WKDataRef audioData) { m_audioResult = audioData; } - void setPixelResult(WKImageRef image) { m_pixelResult = image; } + void setPixelResult(WKImageRef image) { m_pixelResult = image; m_pixelResultIsPending = false; } + void setPixelResultIsPending(bool isPending) { m_pixelResultIsPending = isPending; } void setRepaintRects(WKArrayRef rects) { m_repaintRects = rects; } bool isTestRunning() { return m_state == Testing; } @@ -77,38 +81,58 @@ public: bool shouldDumpPixels() const { return m_dumpPixels; } bool useWaitToDumpWatchdogTimer() const { return m_useWaitToDumpWatchdogTimer; } - + bool dumpJSConsoleLogInStdErr() const { return m_dumpJSConsoleLogInStdErr; }; + void outputText(const String&); + void dumpToStdErr(const String&); void postNewBeforeUnloadReturnValue(bool); void postAddChromeInputField(); void postRemoveChromeInputField(); void postFocusWebView(); void postSetBackingScaleFactor(double); void postSetWindowIsKey(bool); + void postSetViewSize(double width, double height); void postSimulateWebNotificationClick(uint64_t notificationID); + void postSetAddsVisitedLinks(bool); // Geolocation. void setGeolocationPermission(bool); void setMockGeolocationPosition(double latitude, double longitude, double accuracy, bool providesAltitude, double altitude, bool providesAltitudeAccuracy, double altitudeAccuracy, bool providesHeading, double heading, bool providesSpeed, double speed); void setMockGeolocationPositionUnavailableError(WKStringRef errorMessage); + bool isGeolocationProviderActive() const; + + // MediaStream. + void setUserMediaPermission(bool); + void setUserMediaPersistentPermissionForOrigin(bool permission, WKStringRef origin, WKStringRef parentOrigin); + unsigned userMediaPermissionRequestCountForOrigin(WKStringRef origin, WKStringRef parentOrigin) const; + void resetUserMediaPermissionRequestCountForOrigin(WKStringRef origin, WKStringRef parentOrigin); // Policy delegate. void setCustomPolicyDelegate(bool enabled, bool permissive); // Page Visibility. - void setVisibilityState(WKPageVisibilityState, bool isInitialState); + void setHidden(bool); + + // Cache. + void setCacheModel(int); // Work queue. bool shouldProcessWorkQueue() const; void processWorkQueue(); void queueBackNavigation(unsigned howFarBackward); void queueForwardNavigation(unsigned howFarForward); - void queueLoad(WKStringRef url, WKStringRef target); + void queueLoad(WKStringRef url, WKStringRef target, bool shouldOpenExternalURLs = false); void queueLoadHTMLString(WKStringRef content, WKStringRef baseURL = 0, WKStringRef unreachableURL = 0); void queueReload(); void queueLoadingScript(WKStringRef script); void queueNonLoadingScript(WKStringRef script); + bool isAllowedHost(WKStringRef); + + unsigned imageCountInGeneralPasteboard() const; + + void setAllowsAnySSLCertificate(bool); + private: InjectedBundle(); ~InjectedBundle(); @@ -134,9 +158,11 @@ private: WKBundleRef m_bundle; WKBundlePageGroupRef m_pageGroup; - Vector<OwnPtr<InjectedBundlePage> > m_pages; + Vector<std::unique_ptr<InjectedBundlePage>> m_pages; +#if HAVE(ACCESSIBILITY) RefPtr<AccessibilityController> m_accessibilityController; +#endif RefPtr<TestRunner> m_testRunner; RefPtr<GCController> m_gcController; RefPtr<EventSendingController> m_eventSendingController; @@ -155,12 +181,14 @@ private: bool m_useWaitToDumpWatchdogTimer; bool m_useWorkQueue; int m_timeout; + bool m_pixelResultIsPending { false }; + bool m_dumpJSConsoleLogInStdErr { false }; WKRetainPtr<WKDataRef> m_audioResult; WKRetainPtr<WKImageRef> m_pixelResult; WKRetainPtr<WKArrayRef> m_repaintRects; + + Vector<String> m_allowedHosts; }; } // namespace WTR - -#endif // InjectedBundle_h diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp index 58af68221..4f1272214 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp @@ -26,10 +26,10 @@ #include "config.h" #include "InjectedBundle.h" -#include <WebKit2/WKBundleInitialize.h> +#include <WebKit/WKBundleInitialize.h> extern "C" void WKBundleInitialize(WKBundleRef bundle, WKTypeRef initializationUserData) { - WTR::InjectedBundle::shared().initialize(bundle, initializationUserData); + WTR::InjectedBundle::singleton().initialize(bundle, initializationUserData); } diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp index e161156a7..61c59b2e3 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010, 2011, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2010-2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,19 +31,20 @@ #include "WebCoreTestSupport.h" #include <cmath> #include <JavaScriptCore/JSRetainPtr.h> -#include <WebKit2/WKArray.h> -#include <WebKit2/WKBundle.h> -#include <WebKit2/WKBundleBackForwardList.h> -#include <WebKit2/WKBundleBackForwardListItem.h> -#include <WebKit2/WKBundleFrame.h> -#include <WebKit2/WKBundleFramePrivate.h> -#include <WebKit2/WKBundleHitTestResult.h> -#include <WebKit2/WKBundleNavigationAction.h> -#include <WebKit2/WKBundleNodeHandlePrivate.h> -#include <WebKit2/WKBundlePagePrivate.h> -#include <WebKit2/WKBundlePrivate.h> -#include <WebKit2/WKSecurityOrigin.h> -#include <WebKit2/WKURLRequest.h> +#include <WebKit/WKArray.h> +#include <WebKit/WKBundle.h> +#include <WebKit/WKBundleBackForwardList.h> +#include <WebKit/WKBundleBackForwardListItem.h> +#include <WebKit/WKBundleFrame.h> +#include <WebKit/WKBundleFramePrivate.h> +#include <WebKit/WKBundleHitTestResult.h> +#include <WebKit/WKBundleNavigationAction.h> +#include <WebKit/WKBundleNavigationActionPrivate.h> +#include <WebKit/WKBundleNodeHandlePrivate.h> +#include <WebKit/WKBundlePagePrivate.h> +#include <WebKit/WKBundlePrivate.h> +#include <WebKit/WKSecurityOriginRef.h> +#include <WebKit/WKURLRequest.h> #include <wtf/HashMap.h> #include <wtf/text/CString.h> #include <wtf/text/StringBuilder.h> @@ -240,7 +241,7 @@ static inline WTF::String pathSuitableForTestResult(WKURLRef fileUrl) if (!isLocalFileScheme(schemeString.get())) return toWTFString(adoptWK(WKURLCopyString(fileUrl))); - WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page()); WKRetainPtr<WKURLRef> mainFrameURL = adoptWK(WKBundleFrameCopyURL(mainFrame)); if (!mainFrameURL) mainFrameURL = adoptWK(WKBundleFrameCopyProvisionalURL(mainFrame)); @@ -268,8 +269,8 @@ InjectedBundlePage::InjectedBundlePage(WKBundlePageRef page) : m_page(page) , m_world(AdoptWK, WKBundleScriptWorldCreateWorld()) { - WKBundlePageLoaderClientV7 loaderClient = { - { 7, this }, + WKBundlePageLoaderClientV8 loaderClient = { + { 8, this }, didStartProvisionalLoadForFrame, didReceiveServerRedirectForProvisionalLoadForFrame, didFailProvisionalLoadWithErrorForFrame, @@ -304,7 +305,8 @@ InjectedBundlePage::InjectedBundlePage(WKBundlePageRef page) 0, // featuresUsedInPage 0, // willLoadURLRequest 0, // willLoadDataRequest - 0, // willDestroyFrame + 0, // willDestroyFrame_unavailable + 0, // userAgentForURL }; WKBundlePageSetPageLoaderClient(m_page, &loaderClient.base); @@ -412,14 +414,26 @@ void InjectedBundlePage::prepare() WKBundleFrameClearOpener(WKBundlePageGetMainFrame(m_page)); WKBundlePageSetTracksRepaints(m_page, false); + + // Force consistent "responsive" behavior for WebPage::eventThrottlingDelay() for testing. Tests can override via internals. + WKEventThrottlingBehavior behavior = kWKEventThrottlingBehaviorResponsive; + WKBundlePageSetEventThrottlingBehaviorOverride(m_page, &behavior); } void InjectedBundlePage::resetAfterTest() { WKBundleFrameRef frame = WKBundlePageGetMainFrame(m_page); + + // WebKit currently doesn't reset focus even when navigating to a new page. This may or may not be a bug + // (see <https://bugs.webkit.org/show_bug.cgi?id=138334>), however for tests, we want to start each one with a clean state. + WKBundleFrameFocus(frame); + JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame); WebCoreTestSupport::resetInternalsObject(context); assignedUrlsCache.clear(); + + // User scripts need to be removed after the test and before loading about:blank, as otherwise they would run in about:blank, and potentially leak results into a subsequest test. + WKBundlePageRemoveAllUserContent(m_page); } // Loader Client Callbacks @@ -457,7 +471,7 @@ static void dumpLoadEvent(WKBundleFrameRef frame, const char* eventName) stringBuilder.appendLiteral(" - "); stringBuilder.append(eventName); stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); + InjectedBundle::singleton().outputText(stringBuilder.toString()); } static inline void dumpRequestDescriptionSuitableForTestResult(WKURLRequestRef request, StringBuilder& stringBuilder) @@ -646,49 +660,64 @@ bool InjectedBundlePage::shouldCacheResponse(WKBundlePageRef page, WKBundleFrame void InjectedBundlePage::didStartProvisionalLoadForFrame(WKBundleFrameRef frame) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; + if (!injectedBundle.testRunner()->testURL()) { + WKRetainPtr<WKURLRef> testURL = adoptWK(WKBundleFrameCopyProvisionalURL(frame)); + injectedBundle.testRunner()->setTestURL(testURL.get()); + } + platformDidStartProvisionalLoadForFrame(frame); - if (InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks()) + if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) dumpLoadEvent(frame, "didStartProvisionalLoadForFrame"); - if (!InjectedBundle::shared().topLoadingFrame()) - InjectedBundle::shared().setTopLoadingFrame(frame); + if (!injectedBundle.topLoadingFrame()) + injectedBundle.setTopLoadingFrame(frame); - if (InjectedBundle::shared().testRunner()->shouldStopProvisionalFrameLoads()) + if (injectedBundle.testRunner()->shouldStopProvisionalFrameLoads()) dumpLoadEvent(frame, "stopping load in didStartProvisionalLoadForFrame callback"); } void InjectedBundlePage::didReceiveServerRedirectForProvisionalLoadForFrame(WKBundleFrameRef frame) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; - if (!InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks()) + if (!injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) return; dumpLoadEvent(frame, "didReceiveServerRedirectForProvisionalLoadForFrame"); } -void InjectedBundlePage::didFailProvisionalLoadWithErrorForFrame(WKBundleFrameRef frame, WKErrorRef) +void InjectedBundlePage::didFailProvisionalLoadWithErrorForFrame(WKBundleFrameRef frame, WKErrorRef error) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; - if (InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks()) + if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) { dumpLoadEvent(frame, "didFailProvisionalLoadWithError"); + auto code = WKErrorGetErrorCode(error); + if (code == kWKErrorCodeCannotShowURL) + dumpLoadEvent(frame, "(ErrorCodeCannotShowURL)"); + else if (code == kWKErrorCodeFrameLoadBlockedByContentBlocker) + dumpLoadEvent(frame, "(kWKErrorCodeFrameLoadBlockedByContentBlocker)"); + } frameDidChangeLocation(frame); } void InjectedBundlePage::didCommitLoadForFrame(WKBundleFrameRef frame) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; - if (!InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks()) + if (!injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) return; dumpLoadEvent(frame, "didCommitLoadForFrame"); @@ -696,13 +725,14 @@ void InjectedBundlePage::didCommitLoadForFrame(WKBundleFrameRef frame) void InjectedBundlePage::didFinishProgress() { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; - if (!InjectedBundle::shared().testRunner()->shouldDumpProgressFinishedCallback()) + if (!injectedBundle.testRunner()->shouldDumpProgressFinishedCallback()) return; - InjectedBundle::shared().outputText("postProgressFinishedNotification\n"); + injectedBundle.outputText("postProgressFinishedNotification\n"); } enum FrameNamePolicy { ShouldNotIncludeFrameName, ShouldIncludeFrameName }; @@ -816,16 +846,15 @@ void InjectedBundlePage::dumpDOMAsWebArchive(WKBundleFrameRef frame, StringBuild #if USE(CF) WKRetainPtr<WKDataRef> wkData = adoptWK(WKBundleFrameCopyWebArchive(frame)); RetainPtr<CFDataRef> cfData = adoptCF(CFDataCreate(0, WKDataGetBytes(wkData.get()), WKDataGetSize(wkData.get()))); - RetainPtr<CFStringRef> cfString = adoptCF(createXMLStringFromWebArchiveData(cfData.get())); + RetainPtr<CFStringRef> cfString = adoptCF(WebCoreTestSupport::createXMLStringFromWebArchiveData(cfData.get())); stringBuilder.append(cfString.get()); #endif } void InjectedBundlePage::dump() { - ASSERT(InjectedBundle::shared().isTestRunning()); - - InjectedBundle::shared().testRunner()->invalidateWaitToDumpWatchdogTimer(); + auto& injectedBundle = InjectedBundle::singleton(); + ASSERT(injectedBundle.isTestRunning()); // Force a paint before dumping. This matches DumpRenderTree on Windows. (DumpRenderTree on Mac // does this at a slightly different time.) See <http://webkit.org/b/55469> for details. @@ -836,13 +865,13 @@ void InjectedBundlePage::dump() String url = toWTFString(adoptWK(WKURLCopyString(urlRef.get()))); WKRetainPtr<WKStringRef> mimeType = adoptWK(WKBundleFrameCopyMIMETypeForResourceWithURL(frame, urlRef.get())); if (url.find("dumpAsText/") != notFound || WKStringIsEqualToUTF8CString(mimeType.get(), "text/plain")) - InjectedBundle::shared().testRunner()->dumpAsText(false); + injectedBundle.testRunner()->dumpAsText(false); StringBuilder stringBuilder; - switch (InjectedBundle::shared().testRunner()->whatToDump()) { + switch (injectedBundle.testRunner()->whatToDump()) { case TestRunner::RenderTree: { - if (InjectedBundle::shared().testRunner()->isPrinting()) + if (injectedBundle.testRunner()->isPrinting()) stringBuilder.append(toWTFString(adoptWK(WKBundlePageCopyRenderTreeExternalRepresentationForPrinting(m_page)).get())); else stringBuilder.append(toWTFString(adoptWK(WKBundlePageCopyRenderTreeExternalRepresentation(m_page)).get())); @@ -861,34 +890,47 @@ void InjectedBundlePage::dump() break; } - if (InjectedBundle::shared().testRunner()->shouldDumpAllFrameScrollPositions()) + if (injectedBundle.testRunner()->shouldDumpAllFrameScrollPositions()) dumpAllFrameScrollPositions(stringBuilder); - else if (InjectedBundle::shared().testRunner()->shouldDumpMainFrameScrollPosition()) + else if (injectedBundle.testRunner()->shouldDumpMainFrameScrollPosition()) dumpFrameScrollPosition(WKBundlePageGetMainFrame(m_page), stringBuilder); - if (InjectedBundle::shared().testRunner()->shouldDumpBackForwardListsForAllWindows()) - InjectedBundle::shared().dumpBackForwardListsForAllPages(stringBuilder); + if (injectedBundle.testRunner()->shouldDumpBackForwardListsForAllWindows()) + injectedBundle.dumpBackForwardListsForAllPages(stringBuilder); + + if (injectedBundle.shouldDumpPixels() && injectedBundle.testRunner()->shouldDumpPixels()) { + bool shouldCreateSnapshot = injectedBundle.testRunner()->isPrinting(); + if (shouldCreateSnapshot) { + WKSnapshotOptions options = kWKSnapshotOptionsShareable; + WKRect snapshotRect = WKBundleFrameGetVisibleContentBounds(WKBundlePageGetMainFrame(m_page)); - if (InjectedBundle::shared().shouldDumpPixels() && InjectedBundle::shared().testRunner()->shouldDumpPixels()) { - WKSnapshotOptions options = kWKSnapshotOptionsShareable | kWKSnapshotOptionsInViewCoordinates; - if (InjectedBundle::shared().testRunner()->shouldDumpSelectionRect()) - options |= kWKSnapshotOptionsPaintSelectionRectangle; + if (injectedBundle.testRunner()->isPrinting()) + options |= kWKSnapshotOptionsPrinting; + else { + options |= kWKSnapshotOptionsInViewCoordinates; + if (injectedBundle.testRunner()->shouldDumpSelectionRect()) + options |= kWKSnapshotOptionsPaintSelectionRectangle; + } + + injectedBundle.setPixelResult(adoptWK(WKBundlePageCreateSnapshotWithOptions(m_page, snapshotRect, options)).get()); + } else + injectedBundle.setPixelResultIsPending(true); - InjectedBundle::shared().setPixelResult(adoptWK(WKBundlePageCreateSnapshotWithOptions(m_page, WKBundleFrameGetVisibleContentBounds(WKBundlePageGetMainFrame(m_page)), options)).get()); - if (WKBundlePageIsTrackingRepaints(m_page)) - InjectedBundle::shared().setRepaintRects(adoptWK(WKBundlePageCopyTrackedRepaintRects(m_page)).get()); + if (WKBundlePageIsTrackingRepaints(m_page) && !injectedBundle.testRunner()->isPrinting()) + injectedBundle.setRepaintRects(adoptWK(WKBundlePageCopyTrackedRepaintRects(m_page)).get()); } - InjectedBundle::shared().outputText(stringBuilder.toString()); - InjectedBundle::shared().done(); + injectedBundle.outputText(stringBuilder.toString()); + injectedBundle.done(); } void InjectedBundlePage::didFinishLoadForFrame(WKBundleFrameRef frame) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; - if (InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks()) + if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) dumpLoadEvent(frame, "didFinishLoadForFrame"); frameDidChangeLocation(frame, /*shouldDump*/ true); @@ -896,10 +938,11 @@ void InjectedBundlePage::didFinishLoadForFrame(WKBundleFrameRef frame) void InjectedBundlePage::didFailLoadWithErrorForFrame(WKBundleFrameRef frame, WKErrorRef) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; - if (InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks()) + if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) dumpLoadEvent(frame, "didFailLoadWithError"); frameDidChangeLocation(frame); @@ -907,29 +950,31 @@ void InjectedBundlePage::didFailLoadWithErrorForFrame(WKBundleFrameRef frame, WK void InjectedBundlePage::didReceiveTitleForFrame(WKStringRef title, WKBundleFrameRef frame) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; StringBuilder stringBuilder; - if (InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks()) { + if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) { dumpFrameDescriptionSuitableForTestResult(frame, stringBuilder); stringBuilder.appendLiteral(" - didReceiveTitle: "); stringBuilder.append(toWTFString(title)); stringBuilder.append('\n'); } - if (InjectedBundle::shared().testRunner()->shouldDumpTitleChanges()) { + if (injectedBundle.testRunner()->shouldDumpTitleChanges()) { stringBuilder.appendLiteral("TITLE CHANGED: '"); stringBuilder.append(toWTFString(title)); stringBuilder.appendLiteral("'\n"); } - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); } void InjectedBundlePage::didClearWindowForFrame(WKBundleFrameRef frame, WKBundleScriptWorldRef world) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; JSGlobalContextRef context = WKBundleFrameGetJavaScriptContextForWorld(frame, world); @@ -940,22 +985,23 @@ void InjectedBundlePage::didClearWindowForFrame(WKBundleFrameRef frame, WKBundle return; } - JSValueRef exception = 0; - InjectedBundle::shared().testRunner()->makeWindowObject(context, window, &exception); - InjectedBundle::shared().gcController()->makeWindowObject(context, window, &exception); - InjectedBundle::shared().eventSendingController()->makeWindowObject(context, window, &exception); - InjectedBundle::shared().textInputController()->makeWindowObject(context, window, &exception); - InjectedBundle::shared().accessibilityController()->makeWindowObject(context, window, &exception); + JSValueRef exception = nullptr; + injectedBundle.testRunner()->makeWindowObject(context, window, &exception); + injectedBundle.gcController()->makeWindowObject(context, window, &exception); + injectedBundle.eventSendingController()->makeWindowObject(context, window, &exception); + injectedBundle.textInputController()->makeWindowObject(context, window, &exception); + injectedBundle.accessibilityController()->makeWindowObject(context, window, &exception); WebCoreTestSupport::injectInternalsObject(context); } void InjectedBundlePage::didCancelClientRedirectForFrame(WKBundleFrameRef frame) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; - if (!InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks()) + if (!injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) return; dumpLoadEvent(frame, "didCancelClientRedirectForFrame"); @@ -963,10 +1009,11 @@ void InjectedBundlePage::didCancelClientRedirectForFrame(WKBundleFrameRef frame) void InjectedBundlePage::willPerformClientRedirectForFrame(WKBundlePageRef, WKBundleFrameRef frame, WKURLRef url, double delay, double date) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; - if (!InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks()) + if (!injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) return; StringBuilder stringBuilder; @@ -974,19 +1021,31 @@ void InjectedBundlePage::willPerformClientRedirectForFrame(WKBundlePageRef, WKBu stringBuilder.appendLiteral(" - willPerformClientRedirectToURL: "); stringBuilder.append(pathSuitableForTestResult(url)); stringBuilder.appendLiteral(" \n"); - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); } void InjectedBundlePage::didSameDocumentNavigationForFrame(WKBundleFrameRef frame, WKSameDocumentNavigationType type) { + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) + return; + + if (!injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) + return; + + if (type != kWKSameDocumentNavigationAnchorNavigation) + return; + + dumpLoadEvent(frame, "didChangeLocationWithinPageForFrame"); } void InjectedBundlePage::didFinishDocumentLoadForFrame(WKBundleFrameRef frame) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; - if (InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks()) + if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) dumpLoadEvent(frame, "didFinishDocumentLoadForFrame"); unsigned pendingFrameUnloadEvents = WKBundleFrameGetPendingUnloadCount(frame); @@ -996,40 +1055,44 @@ void InjectedBundlePage::didFinishDocumentLoadForFrame(WKBundleFrameRef frame) stringBuilder.appendLiteral(" - has "); stringBuilder.appendNumber(pendingFrameUnloadEvents); stringBuilder.appendLiteral(" onunload handler(s)\n"); - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); } } void InjectedBundlePage::didHandleOnloadEventsForFrame(WKBundleFrameRef frame) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; - if (InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks()) + if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) dumpLoadEvent(frame, "didHandleOnloadEventsForFrame"); } -void InjectedBundlePage::didDisplayInsecureContentForFrame(WKBundleFrameRef frame) +void InjectedBundlePage::didDisplayInsecureContentForFrame(WKBundleFrameRef) { - if (InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks()) - InjectedBundle::shared().outputText("didDisplayInsecureContent\n"); + auto& injectedBundle = InjectedBundle::singleton(); + if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) + injectedBundle.outputText("didDisplayInsecureContent\n"); } -void InjectedBundlePage::didRunInsecureContentForFrame(WKBundleFrameRef frame) +void InjectedBundlePage::didRunInsecureContentForFrame(WKBundleFrameRef) { - if (InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks()) - InjectedBundle::shared().outputText("didRunInsecureContent\n"); + auto& injectedBundle = InjectedBundle::singleton(); + if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) + injectedBundle.outputText("didRunInsecureContent\n"); } -void InjectedBundlePage::didDetectXSSForFrame(WKBundleFrameRef frame) +void InjectedBundlePage::didDetectXSSForFrame(WKBundleFrameRef) { - if (InjectedBundle::shared().testRunner()->shouldDumpFrameLoadCallbacks()) - InjectedBundle::shared().outputText("didDetectXSS\n"); + auto& injectedBundle = InjectedBundle::singleton(); + if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) + injectedBundle.outputText("didDetectXSS\n"); } void InjectedBundlePage::didInitiateLoadForResource(WKBundlePageRef page, WKBundleFrameRef, uint64_t identifier, WKURLRequestRef request, bool) { - if (!InjectedBundle::shared().isTestRunning()) + if (!InjectedBundle::singleton().isTestRunning()) return; WKRetainPtr<WKURLRef> url = adoptWK(WKURLRequestCopyURL(request)); @@ -1048,10 +1111,16 @@ static inline bool isHTTPOrHTTPSScheme(WKStringRef scheme) return WKStringIsEqualToUTF8CStringIgnoringCase(scheme, "http") || WKStringIsEqualToUTF8CStringIgnoringCase(scheme, "https"); } +static inline bool isAllowedHost(WKStringRef host) +{ + return InjectedBundle::singleton().isAllowedHost(host); +} + WKURLRequestRef InjectedBundlePage::willSendRequestForFrame(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, WKURLRequestRef request, WKURLResponseRef response) { - if (InjectedBundle::shared().isTestRunning() - && InjectedBundle::shared().testRunner()->shouldDumpResourceLoadCallbacks()) { + auto& injectedBundle = InjectedBundle::singleton(); + if (injectedBundle.isTestRunning() + && injectedBundle.testRunner()->shouldDumpResourceLoadCallbacks()) { StringBuilder stringBuilder; dumpResourceURL(identifier, stringBuilder); stringBuilder.appendLiteral(" - willSendRequest "); @@ -1059,16 +1128,16 @@ WKURLRequestRef InjectedBundlePage::willSendRequestForFrame(WKBundlePageRef page stringBuilder.appendLiteral(" redirectResponse "); dumpResponseDescriptionSuitableForTestResult(response, stringBuilder); stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); } - if (InjectedBundle::shared().isTestRunning() && InjectedBundle::shared().testRunner()->willSendRequestReturnsNull()) - return 0; + if (injectedBundle.isTestRunning() && injectedBundle.testRunner()->willSendRequestReturnsNull()) + return nullptr; WKRetainPtr<WKURLRef> redirectURL = adoptWK(WKURLResponseCopyURL(response)); - if (InjectedBundle::shared().isTestRunning() && InjectedBundle::shared().testRunner()->willSendRequestReturnsNullOnRedirect() && redirectURL) { - InjectedBundle::shared().outputText("Returning null for this redirect\n"); - return 0; + if (injectedBundle.isTestRunning() && injectedBundle.testRunner()->willSendRequestReturnsNullOnRedirect() && redirectURL) { + injectedBundle.outputText("Returning null for this redirect\n"); + return nullptr; } WKRetainPtr<WKURLRef> url = adoptWK(WKURLRequestCopyURL(request)); @@ -1080,23 +1149,31 @@ WKURLRequestRef InjectedBundlePage::willSendRequestForFrame(WKBundlePageRef page && !WKStringIsEqualToUTF8CString(host.get(), "255.255.255.255") // Used in some tests that expect to get back an error. && !isLocalHost(host.get())) { bool mainFrameIsExternal = false; - if (InjectedBundle::shared().isTestRunning()) { - WKBundleFrameRef mainFrame = InjectedBundle::shared().topLoadingFrame(); + if (injectedBundle.isTestRunning()) { + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(m_page); WKRetainPtr<WKURLRef> mainFrameURL = adoptWK(WKBundleFrameCopyURL(mainFrame)); if (!mainFrameURL || WKStringIsEqualToUTF8CString(adoptWK(WKURLCopyString(mainFrameURL.get())).get(), "about:blank")) mainFrameURL = adoptWK(WKBundleFrameCopyProvisionalURL(mainFrame)); - WKRetainPtr<WKStringRef> mainFrameHost = WKURLCopyHostName(mainFrameURL.get()); - WKRetainPtr<WKStringRef> mainFrameScheme = WKURLCopyScheme(mainFrameURL.get()); + WKRetainPtr<WKStringRef> mainFrameHost = adoptWK(WKURLCopyHostName(mainFrameURL.get())); + WKRetainPtr<WKStringRef> mainFrameScheme = adoptWK(WKURLCopyScheme(mainFrameURL.get())); mainFrameIsExternal = isHTTPOrHTTPSScheme(mainFrameScheme.get()) && !isLocalHost(mainFrameHost.get()); } - if (!mainFrameIsExternal) { + if (!mainFrameIsExternal && !isAllowedHost(host.get())) { StringBuilder stringBuilder; stringBuilder.appendLiteral("Blocked access to external URL "); stringBuilder.append(toWTFString(urlString)); stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); - return 0; + injectedBundle.outputText(stringBuilder.toString()); + return nullptr; + } + } + + if (injectedBundle.isTestRunning()) { + String body = injectedBundle.testRunner()->willSendRequestHTTPBody(); + if (!body.isEmpty()) { + CString cBody = body.utf8(); + return WKURLRequestCopySettingHTTPBody(request, WKDataCreate(reinterpret_cast<const unsigned char*>(cBody.data()), cBody.length())); } } @@ -1106,20 +1183,21 @@ WKURLRequestRef InjectedBundlePage::willSendRequestForFrame(WKBundlePageRef page void InjectedBundlePage::didReceiveResponseForResource(WKBundlePageRef page, WKBundleFrameRef, uint64_t identifier, WKURLResponseRef response) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; - if (InjectedBundle::shared().testRunner()->shouldDumpResourceLoadCallbacks()) { + if (injectedBundle.testRunner()->shouldDumpResourceLoadCallbacks()) { StringBuilder stringBuilder; dumpResourceURL(identifier, stringBuilder); stringBuilder.appendLiteral(" - didReceiveResponse "); dumpResponseDescriptionSuitableForTestResult(response, stringBuilder); stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); } - if (!InjectedBundle::shared().testRunner()->shouldDumpResourceResponseMIMETypes()) + if (!injectedBundle.testRunner()->shouldDumpResourceResponseMIMETypes()) return; WKRetainPtr<WKURLRef> url = adoptWK(WKURLResponseCopyURL(response)); @@ -1130,8 +1208,16 @@ void InjectedBundlePage::didReceiveResponseForResource(WKBundlePageRef page, WKB stringBuilder.append(toWTFString(urlString)); stringBuilder.appendLiteral(" has MIME type "); stringBuilder.append(toWTFString(mimeTypeString)); + + String platformMimeType = platformResponseMimeType(response); + if (!platformMimeType.isEmpty() && platformMimeType != toWTFString(mimeTypeString)) { + stringBuilder.appendLiteral(" but platform response has "); + stringBuilder.append(platformMimeType); + } + stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); + + injectedBundle.outputText(stringBuilder.toString()); } void InjectedBundlePage::didReceiveContentLengthForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t, uint64_t) @@ -1140,24 +1226,26 @@ void InjectedBundlePage::didReceiveContentLengthForResource(WKBundlePageRef, WKB void InjectedBundlePage::didFinishLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; - if (!InjectedBundle::shared().testRunner()->shouldDumpResourceLoadCallbacks()) + if (!injectedBundle.testRunner()->shouldDumpResourceLoadCallbacks()) return; StringBuilder stringBuilder; dumpResourceURL(identifier, stringBuilder); stringBuilder.appendLiteral(" - didFinishLoading\n"); - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); } void InjectedBundlePage::didFailLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier, WKErrorRef error) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; - if (!InjectedBundle::shared().testRunner()->shouldDumpResourceLoadCallbacks()) + if (!injectedBundle.testRunner()->shouldDumpResourceLoadCallbacks()) return; StringBuilder stringBuilder; @@ -1166,21 +1254,22 @@ void InjectedBundlePage::didFailLoadForResource(WKBundlePageRef, WKBundleFrameRe dumpErrorDescriptionSuitableForTestResult(error, stringBuilder); stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); } bool InjectedBundlePage::shouldCacheResponse(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return true; - if (!InjectedBundle::shared().testRunner()->shouldDumpWillCacheResponse()) + if (!injectedBundle.testRunner()->shouldDumpWillCacheResponse()) return true; StringBuilder stringBuilder; stringBuilder.appendNumber(identifier); stringBuilder.appendLiteral(" - willCacheResponse: called\n"); - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); // The default behavior is the cache the response. return true; @@ -1211,11 +1300,30 @@ void InjectedBundlePage::unableToImplementPolicy(WKBundlePageRef page, WKBundleF WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForNavigationAction(WKBundlePageRef page, WKBundleFrameRef frame, WKBundleNavigationActionRef navigationAction, WKURLRequestRef request, WKTypeRef* userData) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return WKBundlePagePolicyActionUse; - if (!InjectedBundle::shared().testRunner()->isPolicyDelegateEnabled()) - return WKBundlePagePolicyActionUse; + if (injectedBundle.testRunner()->shouldDumpPolicyCallbacks()) { + StringBuilder stringBuilder; + stringBuilder.appendLiteral(" - decidePolicyForNavigationAction \n"); + dumpRequestDescriptionSuitableForTestResult(request, stringBuilder); + stringBuilder.appendLiteral(" is main frame - "); + stringBuilder.append(WKBundleFrameIsMainFrame(frame) ? "yes" : "no"); + stringBuilder.appendLiteral(" should open URLs externally - "); + stringBuilder.append(WKBundleNavigationActionGetShouldOpenExternalURLs(navigationAction) ? "yes" : "no"); + stringBuilder.append('\n'); + injectedBundle.outputText(stringBuilder.toString()); + } + + if (injectedBundle.testRunner()->shouldDecideNavigationPolicyAfterDelay()) + return WKBundlePagePolicyActionPassThrough; + + if (!injectedBundle.testRunner()->isPolicyDelegateEnabled()) { + WKRetainPtr<WKStringRef> downloadAttributeRef(AdoptWK, WKBundleNavigationActionCopyDownloadAttribute(navigationAction)); + String downloadAttribute = toWTFString(downloadAttributeRef); + return downloadAttribute.isNull() ? WKBundlePagePolicyActionUse : WKBundlePagePolicyActionPassThrough; + } WKRetainPtr<WKURLRef> url = adoptWK(WKURLRequestCopyURL(request)); WKRetainPtr<WKStringRef> urlScheme = adoptWK(WKURLCopyScheme(url.get())); @@ -1239,10 +1347,10 @@ WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForNavigationAction(WKB } stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); - InjectedBundle::shared().testRunner()->notifyDone(); + injectedBundle.outputText(stringBuilder.toString()); + injectedBundle.testRunner()->notifyDone(); - if (InjectedBundle::shared().testRunner()->isPolicyDelegatePermissive()) + if (injectedBundle.testRunner()->isPolicyDelegatePermissive()) return WKBundlePagePolicyActionUse; return WKBundlePagePolicyActionPassThrough; } @@ -1254,13 +1362,13 @@ WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForNewWindowAction(WKBu WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForResponse(WKBundlePageRef page, WKBundleFrameRef, WKURLResponseRef response, WKURLRequestRef, WKTypeRef*) { - if (WKURLResponseIsAttachment(response)) { + if (InjectedBundle::singleton().testRunner()->isPolicyDelegateEnabled() && WKURLResponseIsAttachment(response)) { StringBuilder stringBuilder; WKRetainPtr<WKStringRef> filename = adoptWK(WKURLResponseCopySuggestedFilename(response)); stringBuilder.appendLiteral("Policy delegate: resource is an attachment, suggested file name \'"); stringBuilder.append(toWTFString(filename)); stringBuilder.appendLiteral("\'\n"); - InjectedBundle::shared().outputText(stringBuilder.toString()); + InjectedBundle::singleton().outputText(stringBuilder.toString()); } WKRetainPtr<WKStringRef> mimeType = adoptWK(WKURLResponseCopyMIMEType(response)); @@ -1330,7 +1438,8 @@ static WTF::String lastFileURLPathComponent(const WTF::String& path) void InjectedBundlePage::willAddMessageToConsole(WKStringRef message, uint32_t lineNumber) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; WTF::String messageString = toWTFString(message); @@ -1352,46 +1461,53 @@ void InjectedBundlePage::willAddMessageToConsole(WKStringRef message, uint32_t l } stringBuilder.append(messageString); stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); + + if (injectedBundle.dumpJSConsoleLogInStdErr()) + injectedBundle.dumpToStdErr(stringBuilder.toString()); + else + injectedBundle.outputText(stringBuilder.toString()); } void InjectedBundlePage::willSetStatusbarText(WKStringRef statusbarText) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; - if (!InjectedBundle::shared().testRunner()->shouldDumpStatusCallbacks()) + if (!injectedBundle.testRunner()->shouldDumpStatusCallbacks()) return; StringBuilder stringBuilder; stringBuilder.appendLiteral("UI DELEGATE STATUS CALLBACK: setStatusText:"); stringBuilder.append(toWTFString(statusbarText)); stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); } void InjectedBundlePage::willRunJavaScriptAlert(WKStringRef message, WKBundleFrameRef) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; StringBuilder stringBuilder; stringBuilder.appendLiteral("ALERT: "); stringBuilder.append(toWTFString(message)); stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); } void InjectedBundlePage::willRunJavaScriptConfirm(WKStringRef message, WKBundleFrameRef) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; StringBuilder stringBuilder; stringBuilder.appendLiteral("CONFIRM: "); stringBuilder.append(toWTFString(message)); stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); } void InjectedBundlePage::willRunJavaScriptPrompt(WKStringRef message, WKStringRef defaultValue, WKBundleFrameRef) @@ -1402,12 +1518,13 @@ void InjectedBundlePage::willRunJavaScriptPrompt(WKStringRef message, WKStringRe stringBuilder.appendLiteral(", default text: "); stringBuilder.append(toWTFString(defaultValue)); stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); + InjectedBundle::singleton().outputText(stringBuilder.toString()); } void InjectedBundlePage::didReachApplicationCacheOriginQuota(WKSecurityOriginRef origin, int64_t totalBytesNeeded) { - if (InjectedBundle::shared().testRunner()->shouldDumpApplicationCacheDelegateCallbacks()) { + auto& injectedBundle = InjectedBundle::singleton(); + if (injectedBundle.testRunner()->shouldDumpApplicationCacheDelegateCallbacks()) { // For example, numbers from 30000 - 39999 will output as 30000. // Rounding up or down does not really matter for these tests. It's // sufficient to just get a range of 10000 to determine if we were @@ -1420,36 +1537,37 @@ void InjectedBundlePage::didReachApplicationCacheOriginQuota(WKSecurityOriginRef stringBuilder.appendLiteral(" totalSpaceNeeded:~"); stringBuilder.appendNumber(truncatedSpaceNeeded); stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); } - if (InjectedBundle::shared().testRunner()->shouldDisallowIncreaseForApplicationCacheQuota()) + if (injectedBundle.testRunner()->shouldDisallowIncreaseForApplicationCacheQuota()) return; // Reset default application cache quota. - WKBundleResetApplicationCacheOriginQuota(InjectedBundle::shared().bundle(), adoptWK(WKSecurityOriginCopyToString(origin)).get()); + WKBundlePageResetApplicationCacheOriginQuota(injectedBundle.page()->page(), adoptWK(WKSecurityOriginCopyToString(origin)).get()); } uint64_t InjectedBundlePage::didExceedDatabaseQuota(WKSecurityOriginRef origin, WKStringRef databaseName, WKStringRef databaseDisplayName, uint64_t currentQuotaBytes, uint64_t currentOriginUsageBytes, uint64_t currentDatabaseUsageBytes, uint64_t expectedUsageBytes) { - if (InjectedBundle::shared().testRunner()->shouldDumpDatabaseCallbacks()) { + auto& injectedBundle = InjectedBundle::singleton(); + if (injectedBundle.testRunner()->shouldDumpDatabaseCallbacks()) { StringBuilder stringBuilder; stringBuilder.appendLiteral("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:"); stringBuilder.append(securityOriginToStr(origin)); stringBuilder.appendLiteral(" database:"); stringBuilder.append(toWTFString(databaseName)); stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); } uint64_t defaultQuota = 5 * 1024 * 1024; - double testDefaultQuota = InjectedBundle::shared().testRunner()->databaseDefaultQuota(); + double testDefaultQuota = injectedBundle.testRunner()->databaseDefaultQuota(); if (testDefaultQuota >= 0) defaultQuota = testDefaultQuota; unsigned long long newQuota = defaultQuota; - double maxQuota = InjectedBundle::shared().testRunner()->databaseMaxQuota(); + double maxQuota = injectedBundle.testRunner()->databaseMaxQuota(); if (maxQuota >= 0) { if (defaultQuota < expectedUsageBytes && expectedUsageBytes <= maxQuota) { newQuota = expectedUsageBytes; @@ -1458,7 +1576,7 @@ uint64_t InjectedBundlePage::didExceedDatabaseQuota(WKSecurityOriginRef origin, stringBuilder.appendLiteral("UI DELEGATE DATABASE CALLBACK: increased quota to "); stringBuilder.appendNumber(newQuota); stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); } } return newQuota; @@ -1523,37 +1641,40 @@ void InjectedBundlePage::didChangeSelection(WKBundlePageRef page, WKStringRef no bool InjectedBundlePage::shouldBeginEditing(WKBundleRangeHandleRef range) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return true; - if (InjectedBundle::shared().testRunner()->shouldDumpEditingCallbacks()) { + if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) { StringBuilder stringBuilder; stringBuilder.appendLiteral("EDITING DELEGATE: shouldBeginEditingInDOMRange:"); stringBuilder.append(rangeToStr(m_page, m_world.get(), range)); stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); } - return InjectedBundle::shared().testRunner()->shouldAllowEditing(); + return injectedBundle.testRunner()->shouldAllowEditing(); } bool InjectedBundlePage::shouldEndEditing(WKBundleRangeHandleRef range) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return true; - if (InjectedBundle::shared().testRunner()->shouldDumpEditingCallbacks()) { + if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) { StringBuilder stringBuilder; stringBuilder.appendLiteral("EDITING DELEGATE: shouldEndEditingInDOMRange:"); stringBuilder.append(rangeToStr(m_page, m_world.get(), range)); stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); } - return InjectedBundle::shared().testRunner()->shouldAllowEditing(); + return injectedBundle.testRunner()->shouldAllowEditing(); } bool InjectedBundlePage::shouldInsertNode(WKBundleNodeHandleRef node, WKBundleRangeHandleRef rangeToReplace, WKInsertActionType action) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return true; static const char* insertactionstring[] = { @@ -1562,7 +1683,7 @@ bool InjectedBundlePage::shouldInsertNode(WKBundleNodeHandleRef node, WKBundleRa "WebViewInsertActionDropped", }; - if (InjectedBundle::shared().testRunner()->shouldDumpEditingCallbacks()) { + if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) { StringBuilder stringBuilder; stringBuilder.appendLiteral("EDITING DELEGATE: shouldInsertNode:"); stringBuilder.append(dumpPath(m_page, m_world.get(), node)); @@ -1571,14 +1692,15 @@ bool InjectedBundlePage::shouldInsertNode(WKBundleNodeHandleRef node, WKBundleRa stringBuilder.appendLiteral(" givenAction:"); stringBuilder.append(insertactionstring[action]); stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); } - return InjectedBundle::shared().testRunner()->shouldAllowEditing(); + return injectedBundle.testRunner()->shouldAllowEditing(); } bool InjectedBundlePage::shouldInsertText(WKStringRef text, WKBundleRangeHandleRef rangeToReplace, WKInsertActionType action) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return true; static const char *insertactionstring[] = { @@ -1587,7 +1709,7 @@ bool InjectedBundlePage::shouldInsertText(WKStringRef text, WKBundleRangeHandleR "WebViewInsertActionDropped", }; - if (InjectedBundle::shared().testRunner()->shouldDumpEditingCallbacks()) { + if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) { StringBuilder stringBuilder; stringBuilder.appendLiteral("EDITING DELEGATE: shouldInsertText:"); stringBuilder.append(toWTFString(text)); @@ -1596,29 +1718,31 @@ bool InjectedBundlePage::shouldInsertText(WKStringRef text, WKBundleRangeHandleR stringBuilder.appendLiteral(" givenAction:"); stringBuilder.append(insertactionstring[action]); stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); } - return InjectedBundle::shared().testRunner()->shouldAllowEditing(); + return injectedBundle.testRunner()->shouldAllowEditing(); } bool InjectedBundlePage::shouldDeleteRange(WKBundleRangeHandleRef range) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return true; - if (InjectedBundle::shared().testRunner()->shouldDumpEditingCallbacks()) { + if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) { StringBuilder stringBuilder; stringBuilder.appendLiteral("EDITING DELEGATE: shouldDeleteDOMRange:"); stringBuilder.append(rangeToStr(m_page, m_world.get(), range)); stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); } - return InjectedBundle::shared().testRunner()->shouldAllowEditing(); + return injectedBundle.testRunner()->shouldAllowEditing(); } bool InjectedBundlePage::shouldChangeSelectedRange(WKBundleRangeHandleRef fromRange, WKBundleRangeHandleRef toRange, WKAffinityType affinity, bool stillSelecting) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return true; static const char *affinitystring[] = { @@ -1630,7 +1754,7 @@ bool InjectedBundlePage::shouldChangeSelectedRange(WKBundleRangeHandleRef fromRa "TRUE" }; - if (InjectedBundle::shared().testRunner()->shouldDumpEditingCallbacks()) { + if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) { StringBuilder stringBuilder; stringBuilder.appendLiteral("EDITING DELEGATE: shouldChangeSelectedDOMRange:"); stringBuilder.append(rangeToStr(m_page, m_world.get(), fromRange)); @@ -1641,98 +1765,105 @@ bool InjectedBundlePage::shouldChangeSelectedRange(WKBundleRangeHandleRef fromRa stringBuilder.appendLiteral(" stillSelecting:"); stringBuilder.append(boolstring[stillSelecting]); stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); } - return InjectedBundle::shared().testRunner()->shouldAllowEditing(); + return injectedBundle.testRunner()->shouldAllowEditing(); } bool InjectedBundlePage::shouldApplyStyle(WKBundleCSSStyleDeclarationRef style, WKBundleRangeHandleRef range) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return true; - if (InjectedBundle::shared().testRunner()->shouldDumpEditingCallbacks()) { + if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) { StringBuilder stringBuilder; stringBuilder.appendLiteral("EDITING DELEGATE: shouldApplyStyle:"); stringBuilder.append(styleDecToStr(style)); stringBuilder.appendLiteral(" toElementsInDOMRange:"); stringBuilder.append(rangeToStr(m_page, m_world.get(), range)); stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); } - return InjectedBundle::shared().testRunner()->shouldAllowEditing(); + return injectedBundle.testRunner()->shouldAllowEditing(); } void InjectedBundlePage::didBeginEditing(WKStringRef notificationName) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; - if (!InjectedBundle::shared().testRunner()->shouldDumpEditingCallbacks()) + if (!injectedBundle.testRunner()->shouldDumpEditingCallbacks()) return; StringBuilder stringBuilder; stringBuilder.appendLiteral("EDITING DELEGATE: webViewDidBeginEditing:"); stringBuilder.append(toWTFString(notificationName)); stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); } void InjectedBundlePage::didEndEditing(WKStringRef notificationName) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; - if (!InjectedBundle::shared().testRunner()->shouldDumpEditingCallbacks()) + if (!injectedBundle.testRunner()->shouldDumpEditingCallbacks()) return; StringBuilder stringBuilder; stringBuilder.appendLiteral("EDITING DELEGATE: webViewDidEndEditing:"); stringBuilder.append(toWTFString(notificationName)); stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); } void InjectedBundlePage::didChange(WKStringRef notificationName) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; - if (!InjectedBundle::shared().testRunner()->shouldDumpEditingCallbacks()) + if (!injectedBundle.testRunner()->shouldDumpEditingCallbacks()) return; StringBuilder stringBuilder; stringBuilder.appendLiteral("EDITING DELEGATE: webViewDidChange:"); stringBuilder.append(toWTFString(notificationName)); stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); } void InjectedBundlePage::didChangeSelection(WKStringRef notificationName) { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; - if (!InjectedBundle::shared().testRunner()->shouldDumpEditingCallbacks()) + if (!injectedBundle.testRunner()->shouldDumpEditingCallbacks()) return; StringBuilder stringBuilder; stringBuilder.appendLiteral("EDITING DELEGATE: webViewDidChangeSelection:"); stringBuilder.append(toWTFString(notificationName)); stringBuilder.append('\n'); - InjectedBundle::shared().outputText(stringBuilder.toString()); + injectedBundle.outputText(stringBuilder.toString()); } #if ENABLE(FULLSCREEN_API) bool InjectedBundlePage::supportsFullScreen(WKBundlePageRef pageRef, WKFullScreenKeyboardRequestType requestType) { - if (InjectedBundle::shared().testRunner()->shouldDumpFullScreenCallbacks()) - InjectedBundle::shared().outputText("supportsFullScreen() == true\n"); + auto& injectedBundle = InjectedBundle::singleton(); + if (injectedBundle.testRunner()->shouldDumpFullScreenCallbacks()) + injectedBundle.outputText("supportsFullScreen() == true\n"); return true; } void InjectedBundlePage::enterFullScreenForElement(WKBundlePageRef pageRef, WKBundleNodeHandleRef elementRef) { - if (InjectedBundle::shared().testRunner()->shouldDumpFullScreenCallbacks()) - InjectedBundle::shared().outputText("enterFullScreenForElement()\n"); + auto& injectedBundle = InjectedBundle::singleton(); + if (injectedBundle.testRunner()->shouldDumpFullScreenCallbacks()) + injectedBundle.outputText("enterFullScreenForElement()\n"); - if (!InjectedBundle::shared().testRunner()->hasCustomFullScreenBehavior()) { + if (!injectedBundle.testRunner()->hasCustomFullScreenBehavior()) { WKBundlePageWillEnterFullScreen(pageRef); WKBundlePageDidEnterFullScreen(pageRef); } @@ -1740,10 +1871,11 @@ void InjectedBundlePage::enterFullScreenForElement(WKBundlePageRef pageRef, WKBu void InjectedBundlePage::exitFullScreenForElement(WKBundlePageRef pageRef, WKBundleNodeHandleRef elementRef) { - if (InjectedBundle::shared().testRunner()->shouldDumpFullScreenCallbacks()) - InjectedBundle::shared().outputText("exitFullScreenForElement()\n"); + auto& injectedBundle = InjectedBundle::singleton(); + if (injectedBundle.testRunner()->shouldDumpFullScreenCallbacks()) + injectedBundle.outputText("exitFullScreenForElement()\n"); - if (!InjectedBundle::shared().testRunner()->hasCustomFullScreenBehavior()) { + if (!injectedBundle.testRunner()->hasCustomFullScreenBehavior()) { WKBundlePageWillExitFullScreen(pageRef); WKBundlePageDidExitFullScreen(pageRef); } @@ -1751,22 +1883,25 @@ void InjectedBundlePage::exitFullScreenForElement(WKBundlePageRef pageRef, WKBun void InjectedBundlePage::beganEnterFullScreen(WKBundlePageRef, WKRect, WKRect) { - if (InjectedBundle::shared().testRunner()->shouldDumpFullScreenCallbacks()) - InjectedBundle::shared().outputText("beganEnterFullScreen()\n"); + auto& injectedBundle = InjectedBundle::singleton(); + if (injectedBundle.testRunner()->shouldDumpFullScreenCallbacks()) + injectedBundle.outputText("beganEnterFullScreen()\n"); } void InjectedBundlePage::beganExitFullScreen(WKBundlePageRef, WKRect, WKRect) { - if (InjectedBundle::shared().testRunner()->shouldDumpFullScreenCallbacks()) - InjectedBundle::shared().outputText("beganExitFullScreen()\n"); + auto& injectedBundle = InjectedBundle::singleton(); + if (injectedBundle.testRunner()->shouldDumpFullScreenCallbacks()) + injectedBundle.outputText("beganExitFullScreen()\n"); } void InjectedBundlePage::closeFullScreen(WKBundlePageRef pageRef) { - if (InjectedBundle::shared().testRunner()->shouldDumpFullScreenCallbacks()) - InjectedBundle::shared().outputText("closeFullScreen()\n"); + auto& injectedBundle = InjectedBundle::singleton(); + if (injectedBundle.testRunner()->shouldDumpFullScreenCallbacks()) + injectedBundle.outputText("closeFullScreen()\n"); - if (!InjectedBundle::shared().testRunner()->hasCustomFullScreenBehavior()) { + if (!injectedBundle.testRunner()->hasCustomFullScreenBehavior()) { WKBundlePageWillExitFullScreen(pageRef); WKBundlePageDidExitFullScreen(pageRef); } @@ -1862,31 +1997,37 @@ void InjectedBundlePage::dumpBackForwardList(StringBuilder& stringBuilder) stringBuilder.appendLiteral("===============================================\n"); } -#if !PLATFORM(MAC) +#if !PLATFORM(COCOA) void InjectedBundlePage::platformDidStartProvisionalLoadForFrame(WKBundleFrameRef) { } + +String InjectedBundlePage::platformResponseMimeType(WKURLResponseRef) +{ + return String(); +} #endif void InjectedBundlePage::frameDidChangeLocation(WKBundleFrameRef frame, bool shouldDump) { - if (frame != InjectedBundle::shared().topLoadingFrame()) + auto& injectedBundle = InjectedBundle::singleton(); + if (frame != injectedBundle.topLoadingFrame()) return; - InjectedBundle::shared().setTopLoadingFrame(0); + injectedBundle.setTopLoadingFrame(nullptr); - if (InjectedBundle::shared().testRunner()->waitToDump()) + if (injectedBundle.testRunner()->waitToDump()) return; - if (InjectedBundle::shared().shouldProcessWorkQueue()) { - InjectedBundle::shared().processWorkQueue(); + if (injectedBundle.shouldProcessWorkQueue()) { + injectedBundle.processWorkQueue(); return; } if (shouldDump) - InjectedBundle::shared().page()->dump(); + injectedBundle.page()->dump(); else - InjectedBundle::shared().done(); + injectedBundle.done(); } } // namespace WTR diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h index f01b50b54..746fc33c5 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h +++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h @@ -26,9 +26,9 @@ #ifndef InjectedBundlePage_h #define InjectedBundlePage_h -#include <WebKit2/WKBundlePage.h> -#include <WebKit2/WKBundleScriptWorld.h> -#include <WebKit2/WKRetainPtr.h> +#include <WebKit/WKBundlePage.h> +#include <WebKit/WKBundleScriptWorld.h> +#include <WebKit/WKRetainPtr.h> #include <wtf/text/WTFString.h> namespace WTR { @@ -169,6 +169,7 @@ private: void dumpDOMAsWebArchive(WKBundleFrameRef, WTF::StringBuilder&); void platformDidStartProvisionalLoadForFrame(WKBundleFrameRef); + String platformResponseMimeType(WKURLResponseRef); void frameDidChangeLocation(WKBundleFrameRef, bool shouldDump = false); diff --git a/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp b/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp index 2b30f5df6..6f7eb0c07 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010, 2011, 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2010-2017 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,20 +33,22 @@ #include "StringFunctions.h" #include "TestController.h" #include <JavaScriptCore/JSCTestRunnerUtils.h> -#include <WebKit2/WKBundle.h> -#include <WebKit2/WKBundleBackForwardList.h> -#include <WebKit2/WKBundleFrame.h> -#include <WebKit2/WKBundleFramePrivate.h> -#include <WebKit2/WKBundleInspector.h> -#include <WebKit2/WKBundleNodeHandlePrivate.h> -#include <WebKit2/WKBundlePage.h> -#include <WebKit2/WKBundlePagePrivate.h> -#include <WebKit2/WKBundlePrivate.h> -#include <WebKit2/WKBundleScriptWorld.h> -#include <WebKit2/WKData.h> -#include <WebKit2/WKRetainPtr.h> -#include <WebKit2/WKSerializedScriptValue.h> -#include <WebKit2/WebKit2_C.h> +#include <WebCore/ResourceLoadObserver.h> +#include <WebKit/WKBundle.h> +#include <WebKit/WKBundleBackForwardList.h> +#include <WebKit/WKBundleFrame.h> +#include <WebKit/WKBundleFramePrivate.h> +#include <WebKit/WKBundleInspector.h> +#include <WebKit/WKBundleNodeHandlePrivate.h> +#include <WebKit/WKBundlePage.h> +#include <WebKit/WKBundlePagePrivate.h> +#include <WebKit/WKBundlePrivate.h> +#include <WebKit/WKBundleScriptWorld.h> +#include <WebKit/WKData.h> +#include <WebKit/WKPagePrivate.h> +#include <WebKit/WKRetainPtr.h> +#include <WebKit/WKSerializedScriptValue.h> +#include <WebKit/WebKit2_C.h> #include <wtf/CurrentTime.h> #include <wtf/HashMap.h> #include <wtf/StdLibExtras.h> @@ -55,11 +57,9 @@ namespace WTR { -const double TestRunner::waitToDumpWatchdogTimerInterval = 30; - -PassRefPtr<TestRunner> TestRunner::create() +Ref<TestRunner> TestRunner::create() { - return adoptRef(new TestRunner); + return adoptRef(*new TestRunner); } TestRunner::TestRunner() @@ -93,10 +93,14 @@ TestRunner::TestRunner() , m_policyDelegatePermissive(false) , m_globalFlag(false) , m_customFullScreenBehavior(false) + , m_timeout(30000) , m_databaseDefaultQuota(-1) , m_databaseMaxQuota(-1) , m_userStyleSheetEnabled(false) , m_userStyleSheetLocation(adoptWK(WKStringCreateWithUTF8CString(""))) +#if PLATFORM(GTK) + , m_waitToDumpWatchdogTimer(RunLoop::main(), this, &TestRunner::waitToDumpWatchdogTimerFired) +#endif { platformInitialize(); } @@ -112,7 +116,7 @@ JSClassRef TestRunner::wrapperClass() void TestRunner::display() { - WKBundlePageRef page = InjectedBundle::shared().page()->page(); + WKBundlePageRef page = InjectedBundle::singleton().page()->page(); WKBundlePageForceRepaint(page); WKBundlePageSetTracksRepaints(page, true); WKBundlePageResetTrackedRepaints(page); @@ -130,7 +134,7 @@ void TestRunner::setCustomPolicyDelegate(bool enabled, bool permissive) m_policyDelegateEnabled = enabled; m_policyDelegatePermissive = permissive; - InjectedBundle::shared().setCustomPolicyDelegate(enabled, permissive); + InjectedBundle::singleton().setCustomPolicyDelegate(enabled, permissive); } void TestRunner::waitForPolicyDelegate() @@ -139,42 +143,58 @@ void TestRunner::waitForPolicyDelegate() waitUntilDone(); } +void TestRunner::waitUntilDownloadFinished() +{ + m_shouldFinishAfterDownload = true; + waitUntilDone(); +} + void TestRunner::waitUntilDone() { m_waitToDump = true; - if (InjectedBundle::shared().useWaitToDumpWatchdogTimer()) + if (InjectedBundle::singleton().useWaitToDumpWatchdogTimer()) initializeWaitToDumpWatchdogTimerIfNeeded(); } void TestRunner::waitToDumpWatchdogTimerFired() { invalidateWaitToDumpWatchdogTimer(); - InjectedBundle::shared().outputText("FAIL: Timed out waiting for notifyDone to be called\n\n"); - InjectedBundle::shared().done(); + auto& injectedBundle = InjectedBundle::singleton(); +#if PLATFORM(COCOA) + char buffer[1024]; + snprintf(buffer, sizeof(buffer), "#PID UNRESPONSIVE - %s (pid %d)\n", getprogname(), getpid()); + injectedBundle.outputText(buffer); +#endif + injectedBundle.outputText("FAIL: Timed out waiting for notifyDone to be called\n\n"); + injectedBundle.done(); } void TestRunner::notifyDone() { - if (!InjectedBundle::shared().isTestRunning()) + auto& injectedBundle = InjectedBundle::singleton(); + if (!injectedBundle.isTestRunning()) return; - if (m_waitToDump && !InjectedBundle::shared().topLoadingFrame()) - InjectedBundle::shared().page()->dump(); + if (m_waitToDump && !injectedBundle.topLoadingFrame()) + injectedBundle.page()->dump(); + + // We don't call invalidateWaitToDumpWatchdogTimer() here, even if we continue to wait for a load to finish. + // The test is still subject to timeout checking - it is better to detect an async timeout inside WebKitTestRunner + // than to let webkitpy do that, because WebKitTestRunner will dump partial results. m_waitToDump = false; } -void TestRunner::setCustomTimeout(int timeout) +unsigned TestRunner::imageCountInGeneralPasteboard() const { - m_timeout = timeout; + return InjectedBundle::singleton().imageCountInGeneralPasteboard(); } void TestRunner::addUserScript(JSStringRef source, bool runAtStart, bool allFrames) { WKRetainPtr<WKStringRef> sourceWK = toWK(source); - WKRetainPtr<WKBundleScriptWorldRef> scriptWorld(AdoptWK, WKBundleScriptWorldCreateWorld()); - WKBundleAddUserScript(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), scriptWorld.get(), sourceWK.get(), 0, 0, 0, + WKBundlePageAddUserScript(InjectedBundle::singleton().page()->page(), sourceWK.get(), (runAtStart ? kWKInjectAtDocumentStart : kWKInjectAtDocumentEnd), (allFrames ? kWKInjectInAllFrames : kWKInjectInTopFrameOnly)); } @@ -182,27 +202,27 @@ void TestRunner::addUserScript(JSStringRef source, bool runAtStart, bool allFram void TestRunner::addUserStyleSheet(JSStringRef source, bool allFrames) { WKRetainPtr<WKStringRef> sourceWK = toWK(source); - WKRetainPtr<WKBundleScriptWorldRef> scriptWorld(AdoptWK, WKBundleScriptWorldCreateWorld()); - WKBundleAddUserStyleSheet(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), scriptWorld.get(), sourceWK.get(), 0, 0, 0, + WKBundlePageAddUserStyleSheet(InjectedBundle::singleton().page()->page(), sourceWK.get(), (allFrames ? kWKInjectInAllFrames : kWKInjectInTopFrameOnly)); } void TestRunner::keepWebHistory() { - WKBundleSetShouldTrackVisitedLinks(InjectedBundle::shared().bundle(), true); + InjectedBundle::singleton().postSetAddsVisitedLinks(true); } void TestRunner::execCommand(JSStringRef name, JSStringRef argument) { - WKBundlePageExecuteEditingCommand(InjectedBundle::shared().page()->page(), toWK(name).get(), toWK(argument).get()); + WKBundlePageExecuteEditingCommand(InjectedBundle::singleton().page()->page(), toWK(name).get(), toWK(argument).get()); } bool TestRunner::findString(JSStringRef target, JSValueRef optionsArrayAsValue) { WKFindOptions options = 0; - WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page()); JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame); JSRetainPtr<JSStringRef> lengthPropertyName(Adopt, JSStringCreateWithUTF8CString("length")); JSObjectRef optionsArray = JSValueToObject(context, optionsArrayAsValue, 0); @@ -233,37 +253,42 @@ bool TestRunner::findString(JSStringRef target, JSValueRef optionsArrayAsValue) } } - return WKBundlePageFindString(InjectedBundle::shared().page()->page(), toWK(target).get(), options); + return WKBundlePageFindString(injectedBundle.page()->page(), toWK(target).get(), options); } void TestRunner::clearAllDatabases() { - WKBundleClearAllDatabases(InjectedBundle::shared().bundle()); + WKBundleClearAllDatabases(InjectedBundle::singleton().bundle()); + + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("DeleteAllIndexedDatabases")); + WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(true)); + + WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr); } void TestRunner::setDatabaseQuota(uint64_t quota) { - return WKBundleSetDatabaseQuota(InjectedBundle::shared().bundle(), quota); + return WKBundleSetDatabaseQuota(InjectedBundle::singleton().bundle(), quota); } void TestRunner::clearAllApplicationCaches() { - WKBundleClearApplicationCache(InjectedBundle::shared().bundle()); + WKBundlePageClearApplicationCache(InjectedBundle::singleton().page()->page()); } void TestRunner::clearApplicationCacheForOrigin(JSStringRef origin) { - WKBundleClearApplicationCacheForOrigin(InjectedBundle::shared().bundle(), toWK(origin).get()); + WKBundlePageClearApplicationCacheForOrigin(InjectedBundle::singleton().page()->page(), toWK(origin).get()); } void TestRunner::setAppCacheMaximumSize(uint64_t size) { - WKBundleSetAppCacheMaximumSize(InjectedBundle::shared().bundle(), size); + WKBundlePageSetAppCacheMaximumSize(InjectedBundle::singleton().page()->page(), size); } long long TestRunner::applicationCacheDiskUsageForOrigin(JSStringRef origin) { - return WKBundleGetAppCacheUsageForOrigin(InjectedBundle::shared().bundle(), toWK(origin).get()); + return WKBundlePageGetAppCacheUsageForOrigin(InjectedBundle::singleton().page()->page(), toWK(origin).get()); } void TestRunner::disallowIncreaseForApplicationCacheQuota() @@ -275,21 +300,24 @@ static inline JSValueRef stringArrayToJS(JSContextRef context, WKArrayRef string { const size_t count = WKArrayGetSize(strings); - auto jsStringsArray = std::make_unique<JSValueRef[]>(count); + JSValueRef arrayResult = JSObjectMakeArray(context, 0, 0, 0); + JSObjectRef arrayObj = JSValueToObject(context, arrayResult, 0); for (size_t i = 0; i < count; ++i) { WKStringRef stringRef = static_cast<WKStringRef>(WKArrayGetItemAtIndex(strings, i)); JSRetainPtr<JSStringRef> stringJS = toJS(stringRef); - jsStringsArray[i] = JSValueMakeString(context, stringJS.get()); + JSObjectSetPropertyAtIndex(context, arrayObj, i, JSValueMakeString(context, stringJS.get()), 0); } - return JSObjectMakeArray(context, count, jsStringsArray.get(), 0); + return arrayResult; } JSValueRef TestRunner::originsWithApplicationCache() { - WKRetainPtr<WKArrayRef> origins(AdoptWK, WKBundleCopyOriginsWithApplicationCache(InjectedBundle::shared().bundle())); + WKBundlePageRef page = InjectedBundle::singleton().page()->page(); + + WKRetainPtr<WKArrayRef> origins(AdoptWK, WKBundlePageCopyOriginsWithApplicationCache(page)); - WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(page); JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame); return stringArrayToJS(context, origins.get()); @@ -297,70 +325,174 @@ JSValueRef TestRunner::originsWithApplicationCache() bool TestRunner::isCommandEnabled(JSStringRef name) { - return WKBundlePageIsEditingCommandEnabled(InjectedBundle::shared().page()->page(), toWK(name).get()); + return WKBundlePageIsEditingCommandEnabled(InjectedBundle::singleton().page()->page(), toWK(name).get()); } void TestRunner::setCanOpenWindows(bool) { - // It's not clear if or why any tests require opening windows be forbidden. - // For now, just ignore this setting, and if we find later it's needed we can add it. + // The test plugins/get-url-with-blank-target.html requires that the embedding client forbid + // opening windows (by omitting a call to this function) so as to test that NPN_GetURL() + // with a blank target will return an error. + // + // It is not clear if we should implement this functionality or remove it and plugins/get-url-with-blank-target.html + // per the remark in <https://trac.webkit.org/changeset/64504/trunk/LayoutTests/platform/mac-wk2/Skipped>. + // For now, just ignore this setting. } void TestRunner::setXSSAuditorEnabled(bool enabled) { WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitXSSAuditorEnabled")); - WKBundleOverrideBoolPreferenceForTestRunner(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), key.get(), enabled); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled); +} + +void TestRunner::setShadowDOMEnabled(bool enabled) +{ + WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitShadowDOMEnabled")); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled); +} + +void TestRunner::setCustomElementsEnabled(bool enabled) +{ + WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitCustomElementsEnabled")); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled); +} + +void TestRunner::setSubtleCryptoEnabled(bool enabled) +{ + WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitSubtleCryptoEnabled")); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled); +} + +void TestRunner::setMediaStreamEnabled(bool enabled) +{ + WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitMediaStreamEnabled")); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled); +} + +void TestRunner::setPeerConnectionEnabled(bool enabled) +{ + WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitPeerConnectionEnabled")); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled); +} + +void TestRunner::setModernMediaControlsEnabled(bool enabled) +{ + WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitModernMediaControlsEnabled")); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled); +} + +void TestRunner::setWebGL2Enabled(bool enabled) +{ + WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitWebGL2Enabled")); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled); +} + +void TestRunner::setFetchAPIEnabled(bool enabled) +{ + WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitFetchAPIEnabled")); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled); +} + +void TestRunner::setDownloadAttributeEnabled(bool enabled) +{ + WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitDownloadAttributeEnabled")); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled); +} + +void TestRunner::setEncryptedMediaAPIEnabled(bool enabled) +{ + WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitEncryptedMediaAPIEnabled")); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled); +} + +void TestRunner::setAllowsAnySSLCertificate(bool enabled) +{ + InjectedBundle::singleton().setAllowsAnySSLCertificate(enabled); } void TestRunner::setAllowUniversalAccessFromFileURLs(bool enabled) { - WKBundleSetAllowUniversalAccessFromFileURLs(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), enabled); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleSetAllowUniversalAccessFromFileURLs(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled); } void TestRunner::setAllowFileAccessFromFileURLs(bool enabled) { - WKBundleSetAllowFileAccessFromFileURLs(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), enabled); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleSetAllowFileAccessFromFileURLs(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled); } +void TestRunner::setNeedsStorageAccessFromFileURLsQuirk(bool needsQuirk) +{ + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleSetAllowStorageAccessFromFileURLS(injectedBundle.bundle(), injectedBundle.pageGroup(), needsQuirk); +} + void TestRunner::setPluginsEnabled(bool enabled) { - WKBundleSetPluginsEnabled(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), enabled); + WKRetainPtr<WKStringRef> key(AdoptWK, WKStringCreateWithUTF8CString("WebKitPluginsEnabled")); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), key.get(), enabled); } void TestRunner::setJavaScriptCanAccessClipboard(bool enabled) { - WKBundleSetJavaScriptCanAccessClipboard(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), enabled); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleSetJavaScriptCanAccessClipboard(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled); } void TestRunner::setPrivateBrowsingEnabled(bool enabled) { - WKBundleSetPrivateBrowsingEnabled(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), enabled); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleSetPrivateBrowsingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled); } +void TestRunner::setUseDashboardCompatibilityMode(bool enabled) +{ +#if ENABLE(DASHBOARD_SUPPORT) + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleSetUseDashboardCompatibilityMode(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled); +#endif +} + void TestRunner::setPopupBlockingEnabled(bool enabled) { - WKBundleSetPopupBlockingEnabled(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), enabled); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleSetPopupBlockingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled); } void TestRunner::setAuthorAndUserStylesEnabled(bool enabled) { - WKBundleSetAuthorAndUserStylesEnabled(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), enabled); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleSetAuthorAndUserStylesEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled); } void TestRunner::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains) { - WKBundleAddOriginAccessWhitelistEntry(InjectedBundle::shared().bundle(), toWK(sourceOrigin).get(), toWK(destinationProtocol).get(), toWK(destinationHost).get(), allowDestinationSubdomains); + WKBundleAddOriginAccessWhitelistEntry(InjectedBundle::singleton().bundle(), toWK(sourceOrigin).get(), toWK(destinationProtocol).get(), toWK(destinationHost).get(), allowDestinationSubdomains); } void TestRunner::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains) { - WKBundleRemoveOriginAccessWhitelistEntry(InjectedBundle::shared().bundle(), toWK(sourceOrigin).get(), toWK(destinationProtocol).get(), toWK(destinationHost).get(), allowDestinationSubdomains); + WKBundleRemoveOriginAccessWhitelistEntry(InjectedBundle::singleton().bundle(), toWK(sourceOrigin).get(), toWK(destinationProtocol).get(), toWK(destinationHost).get(), allowDestinationSubdomains); } bool TestRunner::isPageBoxVisible(int pageIndex) { - WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); - return WKBundleIsPageBoxVisible(InjectedBundle::shared().bundle(), mainFrame, pageIndex); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page()); + return WKBundleIsPageBoxVisible(injectedBundle.bundle(), mainFrame, pageIndex); } void TestRunner::setValueForUser(JSContextRef context, JSValueRef element, JSStringRef value) @@ -374,21 +506,22 @@ void TestRunner::setValueForUser(JSContextRef context, JSValueRef element, JSStr void TestRunner::setAudioResult(JSContextRef context, JSValueRef data) { + auto& injectedBundle = InjectedBundle::singleton(); // FIXME (123058): Use a JSC API to get buffer contents once such is exposed. - WKRetainPtr<WKDataRef> audioData(AdoptWK, WKBundleCreateWKDataFromUInt8Array(InjectedBundle::shared().bundle(), context, data)); - InjectedBundle::shared().setAudioResult(audioData.get()); + WKRetainPtr<WKDataRef> audioData(AdoptWK, WKBundleCreateWKDataFromUInt8Array(injectedBundle.bundle(), context, data)); + injectedBundle.setAudioResult(audioData.get()); m_whatToDump = Audio; m_dumpPixels = false; } unsigned TestRunner::windowCount() { - return InjectedBundle::shared().pageCount(); + return InjectedBundle::singleton().pageCount(); } void TestRunner::clearBackForwardList() { - WKBundleBackForwardListClear(WKBundlePageGetBackForwardList(InjectedBundle::shared().page()->page())); + WKBundleBackForwardListClear(WKBundlePageGetBackForwardList(InjectedBundle::singleton().page()->page())); } // Object Creation @@ -400,24 +533,18 @@ void TestRunner::makeWindowObject(JSContextRef context, JSObjectRef windowObject void TestRunner::showWebInspector() { -#if ENABLE(INSPECTOR) - WKBundleInspectorShow(WKBundlePageGetInspector(InjectedBundle::shared().page()->page())); -#endif // ENABLE(INSPECTOR) + WKBundleInspectorShow(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page())); } void TestRunner::closeWebInspector() { -#if ENABLE(INSPECTOR) - WKBundleInspectorClose(WKBundlePageGetInspector(InjectedBundle::shared().page()->page())); -#endif // ENABLE(INSPECTOR) + WKBundleInspectorClose(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page())); } -void TestRunner::evaluateInWebInspector(long callID, JSStringRef script) +void TestRunner::evaluateInWebInspector(JSStringRef script) { -#if ENABLE(INSPECTOR) WKRetainPtr<WKStringRef> scriptWK = toWK(script); - WKBundleInspectorEvaluateScriptForTest(WKBundlePageGetInspector(InjectedBundle::shared().page()->page()), callID, scriptWK.get()); -#endif // ENABLE(INSPECTOR) + WKBundleInspectorEvaluateScriptForTest(WKBundlePageGetInspector(InjectedBundle::singleton().page()->page()), scriptWK.get()); } typedef WTF::HashMap<unsigned, WKRetainPtr<WKBundleScriptWorldRef> > WorldMap; @@ -454,7 +581,7 @@ void TestRunner::evaluateScriptInIsolatedWorld(JSContextRef context, unsigned wo WKBundleFrameRef frame = WKBundleFrameForJavaScriptContext(context); if (!frame) - frame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); + frame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page()); JSGlobalContextRef jsContext = WKBundleFrameGetJavaScriptContextForWorld(frame, world.get()); JSEvaluateScript(jsContext, script, 0, 0, 0, 0); @@ -469,35 +596,28 @@ void TestRunner::setPOSIXLocale(JSStringRef locale) void TestRunner::setTextDirection(JSStringRef direction) { - WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page()); return WKBundleFrameSetTextDirection(mainFrame, toWK(direction).get()); } void TestRunner::setShouldStayOnPageAfterHandlingBeforeUnload(bool shouldStayOnPage) { - InjectedBundle::shared().postNewBeforeUnloadReturnValue(!shouldStayOnPage); + InjectedBundle::singleton().postNewBeforeUnloadReturnValue(!shouldStayOnPage); } void TestRunner::setDefersLoading(bool shouldDeferLoading) { - WKBundlePageSetDefersLoading(InjectedBundle::shared().page()->page(), shouldDeferLoading); + WKBundlePageSetDefersLoading(InjectedBundle::singleton().page()->page(), shouldDeferLoading); } void TestRunner::setPageVisibility(JSStringRef state) { - WKPageVisibilityState visibilityState = kWKPageVisibilityStateVisible; - - if (JSStringIsEqualToUTF8CString(state, "hidden")) - visibilityState = kWKPageVisibilityStateHidden; - else if (JSStringIsEqualToUTF8CString(state, "prerender")) - visibilityState = kWKPageVisibilityStatePrerender; - - InjectedBundle::shared().setVisibilityState(visibilityState, false); + InjectedBundle::singleton().setHidden(JSStringIsEqualToUTF8CString(state, "hidden") || JSStringIsEqualToUTF8CString(state, "prerender")); } void TestRunner::resetPageVisibility() { - InjectedBundle::shared().setVisibilityState(kWKPageVisibilityStateVisible, true); + InjectedBundle::singleton().setHidden(false); } typedef WTF::HashMap<unsigned, JSValueRef> CallbackMap; @@ -511,7 +631,13 @@ enum { AddChromeInputFieldCallbackID = 1, RemoveChromeInputFieldCallbackID, FocusWebViewCallbackID, - SetBackingScaleFactorCallbackID + SetBackingScaleFactorCallbackID, + DidBeginSwipeCallbackID, + WillEndSwipeCallbackID, + DidEndSwipeCallbackID, + DidRemoveSwipeSnapshotCallbackID, + StatisticsDidModifyDataRecordsCallbackID, + FirstUIScriptCallbackID = 100 }; static void cacheTestRunnerCallback(unsigned index, JSValueRef callback) @@ -519,50 +645,77 @@ static void cacheTestRunnerCallback(unsigned index, JSValueRef callback) if (!callback) return; - WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); + if (callbackMap().contains(index)) { + InjectedBundle::singleton().outputText(String::format("FAIL: Tried to install a second TestRunner callback for the same event (id %d)\n\n", index)); + return; + } + + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page()); JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame); JSValueProtect(context, callback); callbackMap().add(index, callback); } -static void callTestRunnerCallback(unsigned index) +static void callTestRunnerCallback(unsigned index, size_t argumentCount = 0, const JSValueRef arguments[] = nullptr) { if (!callbackMap().contains(index)) return; - WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page()); JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame); JSObjectRef callback = JSValueToObject(context, callbackMap().take(index), 0); - JSObjectCallAsFunction(context, callback, JSContextGetGlobalObject(context), 0, 0, 0); + JSObjectCallAsFunction(context, callback, JSContextGetGlobalObject(context), argumentCount, arguments, 0); JSValueUnprotect(context, callback); } +void TestRunner::clearTestRunnerCallbacks() +{ + for (auto& iter : callbackMap()) { + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page()); + JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame); + JSObjectRef callback = JSValueToObject(context, iter.value, 0); + JSValueUnprotect(context, callback); + } + + callbackMap().clear(); +} + +void TestRunner::accummulateLogsForChannel(JSStringRef) +{ + // FIXME: Implement getting the call to all processes. +} + void TestRunner::addChromeInputField(JSValueRef callback) { cacheTestRunnerCallback(AddChromeInputFieldCallbackID, callback); - InjectedBundle::shared().postAddChromeInputField(); + InjectedBundle::singleton().postAddChromeInputField(); } void TestRunner::removeChromeInputField(JSValueRef callback) { cacheTestRunnerCallback(RemoveChromeInputFieldCallbackID, callback); - InjectedBundle::shared().postRemoveChromeInputField(); + InjectedBundle::singleton().postRemoveChromeInputField(); } void TestRunner::focusWebView(JSValueRef callback) { cacheTestRunnerCallback(FocusWebViewCallbackID, callback); - InjectedBundle::shared().postFocusWebView(); + InjectedBundle::singleton().postFocusWebView(); } void TestRunner::setBackingScaleFactor(double backingScaleFactor, JSValueRef callback) { cacheTestRunnerCallback(SetBackingScaleFactorCallbackID, callback); - InjectedBundle::shared().postSetBackingScaleFactor(backingScaleFactor); + InjectedBundle::singleton().postSetBackingScaleFactor(backingScaleFactor); } void TestRunner::setWindowIsKey(bool isKey) { - InjectedBundle::shared().postSetWindowIsKey(isKey); + InjectedBundle::singleton().postSetWindowIsKey(isKey); +} + +void TestRunner::setViewSize(double width, double height) +{ + InjectedBundle::singleton().postSetViewSize(width, height); } void TestRunner::callAddChromeInputFieldCallback() @@ -592,13 +745,18 @@ static inline bool toBool(JSStringRef value) void TestRunner::overridePreference(JSStringRef preference, JSStringRef value) { + auto& injectedBundle = InjectedBundle::singleton(); // FIXME: handle non-boolean preferences. - WKBundleOverrideBoolPreferenceForTestRunner(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), toWK(preference).get(), toBool(value)); + WKBundleOverrideBoolPreferenceForTestRunner(injectedBundle.bundle(), injectedBundle.pageGroup(), toWK(preference).get(), toBool(value)); } void TestRunner::setAlwaysAcceptCookies(bool accept) { - WKBundleSetAlwaysAcceptCookies(InjectedBundle::shared().bundle(), accept); + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAlwaysAcceptCookies")); + + WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(accept)); + + WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr); } double TestRunner::preciseTime() @@ -612,7 +770,8 @@ void TestRunner::setUserStyleSheetEnabled(bool enabled) WKRetainPtr<WKStringRef> emptyUrl = adoptWK(WKStringCreateWithUTF8CString("")); WKStringRef location = enabled ? m_userStyleSheetLocation.get() : emptyUrl.get(); - WKBundleSetUserStyleSheetLocation(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), location); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleSetUserStyleSheetLocation(injectedBundle.bundle(), injectedBundle.pageGroup(), location); } void TestRunner::setUserStyleSheetLocation(JSStringRef location) @@ -625,68 +784,81 @@ void TestRunner::setUserStyleSheetLocation(JSStringRef location) void TestRunner::setSpatialNavigationEnabled(bool enabled) { - WKBundleSetSpatialNavigationEnabled(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), enabled); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleSetSpatialNavigationEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled); } void TestRunner::setTabKeyCyclesThroughElements(bool enabled) { - WKBundleSetTabKeyCyclesThroughElements(InjectedBundle::shared().bundle(), InjectedBundle::shared().page()->page(), enabled); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleSetTabKeyCyclesThroughElements(injectedBundle.bundle(), injectedBundle.page()->page(), enabled); } void TestRunner::setSerializeHTTPLoads() { - WKBundleSetSerialLoadingEnabled(InjectedBundle::shared().bundle(), true); + // WK2 doesn't reorder loads. } void TestRunner::dispatchPendingLoadRequests() { - WKBundleDispatchPendingLoadRequests(InjectedBundle::shared().bundle()); + // WK2 doesn't keep pending requests. } void TestRunner::setCacheModel(int model) { - WKBundleSetCacheModel(InjectedBundle::shared().bundle(), model); + InjectedBundle::singleton().setCacheModel(model); } void TestRunner::setAsynchronousSpellCheckingEnabled(bool enabled) { - WKBundleSetAsynchronousSpellCheckingEnabled(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), enabled); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleSetAsynchronousSpellCheckingEnabled(injectedBundle.bundle(), injectedBundle.pageGroup(), enabled); } void TestRunner::grantWebNotificationPermission(JSStringRef origin) { WKRetainPtr<WKStringRef> originWK = toWK(origin); - WKBundleSetWebNotificationPermission(InjectedBundle::shared().bundle(), InjectedBundle::shared().page()->page(), originWK.get(), true); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleSetWebNotificationPermission(injectedBundle.bundle(), injectedBundle.page()->page(), originWK.get(), true); } void TestRunner::denyWebNotificationPermission(JSStringRef origin) { WKRetainPtr<WKStringRef> originWK = toWK(origin); - WKBundleSetWebNotificationPermission(InjectedBundle::shared().bundle(), InjectedBundle::shared().page()->page(), originWK.get(), false); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleSetWebNotificationPermission(injectedBundle.bundle(), injectedBundle.page()->page(), originWK.get(), false); } void TestRunner::removeAllWebNotificationPermissions() { - WKBundleRemoveAllWebNotificationPermissions(InjectedBundle::shared().bundle(), InjectedBundle::shared().page()->page()); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleRemoveAllWebNotificationPermissions(injectedBundle.bundle(), injectedBundle.page()->page()); } void TestRunner::simulateWebNotificationClick(JSValueRef notification) { - WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page()); JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame); - uint64_t notificationID = WKBundleGetWebNotificationID(InjectedBundle::shared().bundle(), context, notification); - InjectedBundle::shared().postSimulateWebNotificationClick(notificationID); + uint64_t notificationID = WKBundleGetWebNotificationID(injectedBundle.bundle(), context, notification); + injectedBundle.postSimulateWebNotificationClick(notificationID); } void TestRunner::setGeolocationPermission(bool enabled) { // FIXME: this should be done by frame. - InjectedBundle::shared().setGeolocationPermission(enabled); + InjectedBundle::singleton().setGeolocationPermission(enabled); +} + +bool TestRunner::isGeolocationProviderActive() +{ + return InjectedBundle::singleton().isGeolocationProviderActive(); } void TestRunner::setMockGeolocationPosition(double latitude, double longitude, double accuracy, JSValueRef jsAltitude, JSValueRef jsAltitudeAccuracy, JSValueRef jsHeading, JSValueRef jsSpeed) { - WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); + auto& injectedBundle = InjectedBundle::singleton(); + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(injectedBundle.page()->page()); JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame); bool providesAltitude = false; @@ -717,38 +889,66 @@ void TestRunner::setMockGeolocationPosition(double latitude, double longitude, d speed = JSValueToNumber(context, jsSpeed, 0); } - InjectedBundle::shared().setMockGeolocationPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed); + injectedBundle.setMockGeolocationPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed); } void TestRunner::setMockGeolocationPositionUnavailableError(JSStringRef message) { WKRetainPtr<WKStringRef> messageWK = toWK(message); - InjectedBundle::shared().setMockGeolocationPositionUnavailableError(messageWK.get()); + InjectedBundle::singleton().setMockGeolocationPositionUnavailableError(messageWK.get()); +} + +void TestRunner::setUserMediaPermission(bool enabled) +{ + // FIXME: this should be done by frame. + InjectedBundle::singleton().setUserMediaPermission(enabled); +} + +void TestRunner::setUserMediaPersistentPermissionForOrigin(bool permission, JSStringRef origin, JSStringRef parentOrigin) +{ + WKRetainPtr<WKStringRef> originWK = toWK(origin); + WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin); + InjectedBundle::singleton().setUserMediaPersistentPermissionForOrigin(permission, originWK.get(), parentOriginWK.get()); +} + +unsigned TestRunner::userMediaPermissionRequestCountForOrigin(JSStringRef origin, JSStringRef parentOrigin) const +{ + WKRetainPtr<WKStringRef> originWK = toWK(origin); + WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin); + return InjectedBundle::singleton().userMediaPermissionRequestCountForOrigin(originWK.get(), parentOriginWK.get()); +} + +void TestRunner::resetUserMediaPermissionRequestCountForOrigin(JSStringRef origin, JSStringRef parentOrigin) +{ + WKRetainPtr<WKStringRef> originWK = toWK(origin); + WKRetainPtr<WKStringRef> parentOriginWK = toWK(parentOrigin); + InjectedBundle::singleton().resetUserMediaPermissionRequestCountForOrigin(originWK.get(), parentOriginWK.get()); } bool TestRunner::callShouldCloseOnWebView() { - WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page()); return WKBundleFrameCallShouldCloseOnWebView(mainFrame); } void TestRunner::queueBackNavigation(unsigned howFarBackward) { - InjectedBundle::shared().queueBackNavigation(howFarBackward); + InjectedBundle::singleton().queueBackNavigation(howFarBackward); } void TestRunner::queueForwardNavigation(unsigned howFarForward) { - InjectedBundle::shared().queueForwardNavigation(howFarForward); + InjectedBundle::singleton().queueForwardNavigation(howFarForward); } -void TestRunner::queueLoad(JSStringRef url, JSStringRef target) +void TestRunner::queueLoad(JSStringRef url, JSStringRef target, bool shouldOpenExternalURLs) { - WKRetainPtr<WKURLRef> baseURLWK(AdoptWK, WKBundleFrameCopyURL(WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()))); + auto& injectedBundle = InjectedBundle::singleton(); + WKRetainPtr<WKURLRef> baseURLWK(AdoptWK, WKBundleFrameCopyURL(WKBundlePageGetMainFrame(injectedBundle.page()->page()))); WKRetainPtr<WKURLRef> urlWK(AdoptWK, WKURLCreateWithBaseURL(baseURLWK.get(), toWTFString(toWK(url)).utf8().data())); WKRetainPtr<WKStringRef> urlStringWK(AdoptWK, WKURLCopyString(urlWK.get())); - InjectedBundle::shared().queueLoad(urlStringWK.get(), toWK(target).get()); + injectedBundle.queueLoad(urlStringWK.get(), toWK(target).get(), shouldOpenExternalURLs); } void TestRunner::queueLoadHTMLString(JSStringRef content, JSStringRef baseURL, JSStringRef unreachableURL) @@ -757,45 +957,59 @@ void TestRunner::queueLoadHTMLString(JSStringRef content, JSStringRef baseURL, J WKRetainPtr<WKStringRef> baseURLWK = baseURL ? toWK(baseURL) : WKRetainPtr<WKStringRef>(); WKRetainPtr<WKStringRef> unreachableURLWK = unreachableURL ? toWK(unreachableURL) : WKRetainPtr<WKStringRef>(); - InjectedBundle::shared().queueLoadHTMLString(contentWK.get(), baseURLWK.get(), unreachableURLWK.get()); + InjectedBundle::singleton().queueLoadHTMLString(contentWK.get(), baseURLWK.get(), unreachableURLWK.get()); } void TestRunner::queueReload() { - InjectedBundle::shared().queueReload(); + InjectedBundle::singleton().queueReload(); } void TestRunner::queueLoadingScript(JSStringRef script) { WKRetainPtr<WKStringRef> scriptWK = toWK(script); - InjectedBundle::shared().queueLoadingScript(scriptWK.get()); + InjectedBundle::singleton().queueLoadingScript(scriptWK.get()); } void TestRunner::queueNonLoadingScript(JSStringRef script) { WKRetainPtr<WKStringRef> scriptWK = toWK(script); - InjectedBundle::shared().queueNonLoadingScript(scriptWK.get()); + InjectedBundle::singleton().queueNonLoadingScript(scriptWK.get()); } +void TestRunner::setRejectsProtectionSpaceAndContinueForAuthenticationChallenges(bool value) +{ + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetRejectsProtectionSpaceAndContinueForAuthenticationChallenges")); + WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value)); + WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get()); +} + void TestRunner::setHandlesAuthenticationChallenges(bool handlesAuthenticationChallenges) { - WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetHandlesAuthenticationChallenge")); + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetHandlesAuthenticationChallenges")); WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(handlesAuthenticationChallenges)); - WKBundlePostMessage(InjectedBundle::shared().bundle(), messageName.get(), messageBody.get()); + WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get()); +} + +void TestRunner::setShouldLogCanAuthenticateAgainstProtectionSpace(bool value) +{ + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetShouldLogCanAuthenticateAgainstProtectionSpace")); + WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value)); + WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get()); } void TestRunner::setAuthenticationUsername(JSStringRef username) { WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAuthenticationUsername")); WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(username)); - WKBundlePostMessage(InjectedBundle::shared().bundle(), messageName.get(), messageBody.get()); + WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get()); } void TestRunner::setAuthenticationPassword(JSStringRef password) { WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetAuthenticationPassword")); WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(password)); - WKBundlePostMessage(InjectedBundle::shared().bundle(), messageName.get(), messageBody.get()); + WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get()); } bool TestRunner::secureEventInputIsEnabled() const @@ -803,7 +1017,7 @@ bool TestRunner::secureEventInputIsEnabled() const WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SecureEventInputIsEnabled")); WKTypeRef returnData = 0; - WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), messageName.get(), 0, &returnData); + WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), 0, &returnData); return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData)); } @@ -811,21 +1025,386 @@ void TestRunner::setBlockAllPlugins(bool shouldBlock) { WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetBlockAllPlugins")); WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(shouldBlock)); - WKBundlePostMessage(InjectedBundle::shared().bundle(), messageName.get(), messageBody.get()); + WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get()); +} + +JSValueRef TestRunner::failNextNewCodeBlock() +{ + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page()); + JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame); + return JSC::failNextNewCodeBlock(context); } JSValueRef TestRunner::numberOfDFGCompiles(JSValueRef theFunction) { - WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page()); JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame); return JSC::numberOfDFGCompiles(context, theFunction); } JSValueRef TestRunner::neverInlineFunction(JSValueRef theFunction) { - WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page()); JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame); return JSC::setNeverInline(context, theFunction); } +void TestRunner::setShouldDecideNavigationPolicyAfterDelay(bool value) +{ + m_shouldDecideNavigationPolicyAfterDelay = value; + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetShouldDecideNavigationPolicyAfterDelay")); + WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value)); + WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get()); +} + +void TestRunner::setNavigationGesturesEnabled(bool value) +{ + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetNavigationGesturesEnabled")); + WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value)); + WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get()); +} + +void TestRunner::setIgnoresViewportScaleLimits(bool value) +{ + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetIgnoresViewportScaleLimits")); + WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value)); + WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get()); +} + +void TestRunner::setShouldDownloadUndisplayableMIMETypes(bool value) +{ + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetShouldDownloadUndisplayableMIMETypes")); + WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value)); + WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get()); +} + +static unsigned nextUIScriptCallbackID() +{ + static unsigned callbackID = FirstUIScriptCallbackID; + return callbackID++; +} + +void TestRunner::runUIScript(JSStringRef script, JSValueRef callback) +{ + unsigned callbackID = nextUIScriptCallbackID(); + cacheTestRunnerCallback(callbackID, callback); + + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("RunUIProcessScript")); + + WKRetainPtr<WKMutableDictionaryRef> testDictionary(AdoptWK, WKMutableDictionaryCreate()); + + WKRetainPtr<WKStringRef> scriptKey(AdoptWK, WKStringCreateWithUTF8CString("Script")); + WKRetainPtr<WKStringRef> scriptValue(AdoptWK, WKStringCreateWithJSString(script)); + + WKRetainPtr<WKStringRef> callbackIDKey(AdoptWK, WKStringCreateWithUTF8CString("CallbackID")); + WKRetainPtr<WKUInt64Ref> callbackIDValue = adoptWK(WKUInt64Create(callbackID)); + + WKDictionarySetItem(testDictionary.get(), scriptKey.get(), scriptValue.get()); + WKDictionarySetItem(testDictionary.get(), callbackIDKey.get(), callbackIDValue.get()); + + WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), testDictionary.get()); +} + +void TestRunner::runUIScriptCallback(unsigned callbackID, JSStringRef result) +{ + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page()); + JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame); + + JSValueRef resultValue = JSValueMakeString(context, result); + callTestRunnerCallback(callbackID, 1, &resultValue); +} + +void TestRunner::installDidBeginSwipeCallback(JSValueRef callback) +{ + cacheTestRunnerCallback(DidBeginSwipeCallbackID, callback); +} + +void TestRunner::installWillEndSwipeCallback(JSValueRef callback) +{ + cacheTestRunnerCallback(WillEndSwipeCallbackID, callback); +} + +void TestRunner::installDidEndSwipeCallback(JSValueRef callback) +{ + cacheTestRunnerCallback(DidEndSwipeCallbackID, callback); +} + +void TestRunner::installDidRemoveSwipeSnapshotCallback(JSValueRef callback) +{ + cacheTestRunnerCallback(DidRemoveSwipeSnapshotCallbackID, callback); +} + +void TestRunner::callDidBeginSwipeCallback() +{ + callTestRunnerCallback(DidBeginSwipeCallbackID); +} + +void TestRunner::callWillEndSwipeCallback() +{ + callTestRunnerCallback(WillEndSwipeCallbackID); +} + +void TestRunner::callDidEndSwipeCallback() +{ + callTestRunnerCallback(DidEndSwipeCallbackID); +} + +void TestRunner::callDidRemoveSwipeSnapshotCallback() +{ + callTestRunnerCallback(DidRemoveSwipeSnapshotCallbackID); +} + +void TestRunner::setStatisticsPrevalentResource(JSStringRef hostName, bool value) +{ + Vector<WKRetainPtr<WKStringRef>> keys; + Vector<WKRetainPtr<WKTypeRef>> values; + + keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") }); + values.append({ AdoptWK, WKStringCreateWithJSString(hostName) }); + + keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") }); + values.append({ AdoptWK, WKBooleanCreate(value) }); + + Vector<WKStringRef> rawKeys; + Vector<WKTypeRef> rawValues; + rawKeys.resize(keys.size()); + rawValues.resize(values.size()); + + for (size_t i = 0; i < keys.size(); ++i) { + rawKeys[i] = keys[i].get(); + rawValues[i] = values[i].get(); + } + + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsPrevalentResource")); + WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size())); + + WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr); +} + +bool TestRunner::isStatisticsPrevalentResource(JSStringRef hostName) +{ + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsPrevalentResource")); + WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(hostName)); + WKTypeRef returnData = 0; + WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData); + return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData)); +} + +void TestRunner::setStatisticsHasHadUserInteraction(JSStringRef hostName, bool value) +{ + Vector<WKRetainPtr<WKStringRef>> keys; + Vector<WKRetainPtr<WKTypeRef>> values; + + keys.append({ AdoptWK, WKStringCreateWithUTF8CString("HostName") }); + values.append({ AdoptWK, WKStringCreateWithJSString(hostName) }); + + keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") }); + values.append({ AdoptWK, WKBooleanCreate(value) }); + + Vector<WKStringRef> rawKeys; + Vector<WKTypeRef> rawValues; + rawKeys.resize(keys.size()); + rawValues.resize(values.size()); + + for (size_t i = 0; i < keys.size(); ++i) { + rawKeys[i] = keys[i].get(); + rawValues[i] = values[i].get(); + } + + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsHasHadUserInteraction")); + WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size())); + + WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr); +} + +bool TestRunner::isStatisticsHasHadUserInteraction(JSStringRef hostName) +{ + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("IsStatisticsHasHadUserInteraction")); + WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithJSString(hostName)); + WKTypeRef returnData = 0; + WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), messageName.get(), messageBody.get(), &returnData); + return WKBooleanGetValue(static_cast<WKBooleanRef>(returnData)); +} + +void TestRunner::setStatisticsTimeToLiveUserInteraction(double seconds) +{ + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsTimeToLiveUserInteraction")); + WKRetainPtr<WKDoubleRef> messageBody(AdoptWK, WKDoubleCreate(seconds)); + WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr); +} + +void TestRunner::installStatisticsDidModifyDataRecordsCallback(JSValueRef callback) +{ + cacheTestRunnerCallback(StatisticsDidModifyDataRecordsCallbackID, callback); +} + +void TestRunner::statisticsDidModifyDataRecordsCallback() +{ + callTestRunnerCallback(StatisticsDidModifyDataRecordsCallbackID); +} + +void TestRunner::statisticsFireDataModificationHandler() +{ + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsFireDataModificationHandler")); + WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr); +} + +void TestRunner::setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool value) +{ + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsNotifyPagesWhenDataRecordsWereScanned")); + WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value)); + WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr); +} + +void TestRunner::setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(bool value) +{ + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsShouldClassifyResourcesBeforeDataRecordsRemoval")); + WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value)); + WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr); +} + +void TestRunner::setStatisticsMinimumTimeBetweeenDataRecordsRemoval(double seconds) +{ + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetStatisticsMinimumTimeBetweeenDataRecordsRemoval")); + WKRetainPtr<WKDoubleRef> messageBody(AdoptWK, WKDoubleCreate(seconds)); + WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr); +} + +void TestRunner::statisticsResetToConsistentState() +{ + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsResetToConsistentState")); + WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr); +} + +#if PLATFORM(MAC) +void TestRunner::connectMockGamepad(unsigned index) +{ + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ConnectMockGamepad")); + WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(index)); + + WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr); +} + +void TestRunner::disconnectMockGamepad(unsigned index) +{ + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("DisconnectMockGamepad")); + WKRetainPtr<WKTypeRef> messageBody(AdoptWK, WKUInt64Create(index)); + + WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr); +} + +void TestRunner::setMockGamepadDetails(unsigned index, JSStringRef gamepadID, unsigned axisCount, unsigned buttonCount) +{ + Vector<WKRetainPtr<WKStringRef>> keys; + Vector<WKRetainPtr<WKTypeRef>> values; + + keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadID") }); + values.append(toWK(gamepadID)); + + keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") }); + values.append({ AdoptWK, WKUInt64Create(index) }); + + keys.append({ AdoptWK, WKStringCreateWithUTF8CString("AxisCount") }); + values.append({ AdoptWK, WKUInt64Create(axisCount) }); + + keys.append({ AdoptWK, WKStringCreateWithUTF8CString("ButtonCount") }); + values.append({ AdoptWK, WKUInt64Create(buttonCount) }); + + Vector<WKStringRef> rawKeys; + Vector<WKTypeRef> rawValues; + rawKeys.resize(keys.size()); + rawValues.resize(values.size()); + + for (size_t i = 0; i < keys.size(); ++i) { + rawKeys[i] = keys[i].get(); + rawValues[i] = values[i].get(); + } + + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadDetails")); + WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size())); + + WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr); +} + +void TestRunner::setMockGamepadAxisValue(unsigned index, unsigned axisIndex, double value) +{ + Vector<WKRetainPtr<WKStringRef>> keys; + Vector<WKRetainPtr<WKTypeRef>> values; + + keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") }); + values.append({ AdoptWK, WKUInt64Create(index) }); + + keys.append({ AdoptWK, WKStringCreateWithUTF8CString("AxisIndex") }); + values.append({ AdoptWK, WKUInt64Create(axisIndex) }); + + keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") }); + values.append({ AdoptWK, WKDoubleCreate(value) }); + + Vector<WKStringRef> rawKeys; + Vector<WKTypeRef> rawValues; + rawKeys.resize(keys.size()); + rawValues.resize(values.size()); + + for (size_t i = 0; i < keys.size(); ++i) { + rawKeys[i] = keys[i].get(); + rawValues[i] = values[i].get(); + } + + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadAxisValue")); + WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size())); + + WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr); +} + +void TestRunner::setMockGamepadButtonValue(unsigned index, unsigned buttonIndex, double value) +{ + Vector<WKRetainPtr<WKStringRef>> keys; + Vector<WKRetainPtr<WKTypeRef>> values; + + keys.append({ AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex") }); + values.append({ AdoptWK, WKUInt64Create(index) }); + + keys.append({ AdoptWK, WKStringCreateWithUTF8CString("ButtonIndex") }); + values.append({ AdoptWK, WKUInt64Create(buttonIndex) }); + + keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Value") }); + values.append({ AdoptWK, WKDoubleCreate(value) }); + + Vector<WKStringRef> rawKeys; + Vector<WKTypeRef> rawValues; + rawKeys.resize(keys.size()); + rawValues.resize(values.size()); + + for (size_t i = 0; i < keys.size(); ++i) { + rawKeys[i] = keys[i].get(); + rawValues[i] = values[i].get(); + } + + WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("SetMockGamepadButtonValue")); + WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size())); + + WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr); +} +#else +void TestRunner::connectMockGamepad(unsigned) +{ +} + +void TestRunner::disconnectMockGamepad(unsigned) +{ +} + +void TestRunner::setMockGamepadDetails(unsigned, JSStringRef, unsigned, unsigned) +{ +} + +void TestRunner::setMockGamepadAxisValue(unsigned, unsigned, double) +{ +} + +void TestRunner::setMockGamepadButtonValue(unsigned, unsigned, double) +{ +} +#endif // PLATFORM(MAC) + } // namespace WTR diff --git a/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h b/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h index cefb6a5d1..764c9e4a9 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h +++ b/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010, 2011, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2010-2017 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,28 +23,28 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef TestRunner_h -#define TestRunner_h +#pragma once #include "JSWrappable.h" +#include "StringFunctions.h" #include <JavaScriptCore/JSRetainPtr.h> -#include <WebKit2/WKBundleScriptWorld.h> -#include <WebKit2/WKRetainPtr.h> +#include <WebKit/WKBundleScriptWorld.h> +#include <WebKit/WKRetainPtr.h> #include <string> -#include <wtf/PassRefPtr.h> +#include <wtf/Ref.h> +#include <wtf/text/WTFString.h> -#if PLATFORM(MAC) +#if PLATFORM(COCOA) #include <wtf/RetainPtr.h> #include <CoreFoundation/CFRunLoop.h> typedef RetainPtr<CFRunLoopTimerRef> PlatformTimerRef; #elif PLATFORM(GTK) -typedef unsigned int PlatformTimerRef; +#include <wtf/RunLoop.h> +namespace WTR { +class TestRunner; +typedef RunLoop::Timer<TestRunner> PlatformTimerRef; +} #elif PLATFORM(EFL) -#if USE(EO) -typedef struct _Eo_Opaque Ecore_Timer; -#else -typedef struct _Ecore_Timer Ecore_Timer; -#endif typedef Ecore_Timer* PlatformTimerRef; #endif @@ -52,7 +52,7 @@ namespace WTR { class TestRunner : public JSWrappable { public: - static PassRefPtr<TestRunner> create(); + static Ref<TestRunner> create(); virtual ~TestRunner(); // JSWrappable @@ -60,13 +60,19 @@ public: void makeWindowObject(JSContextRef, JSObjectRef windowObject, JSValueRef* exception); + bool isWebKit2() const { return true; } + // The basics. + WKURLRef testURL() const { return m_testURL.get(); } + void setTestURL(WKURLRef url) { m_testURL = url; } void dumpAsText(bool dumpPixels); void waitForPolicyDelegate(); void dumpChildFramesAsText() { m_whatToDump = AllFramesText; } + void waitUntilDownloadFinished(); void waitUntilDone(); void notifyDone(); double preciseTime(); + double timeout() { return m_timeout; } // Other dumping. void dumpBackForwardList() { m_shouldDumpBackForwardListsForAllWindows = true; } @@ -84,6 +90,7 @@ public: void dumpApplicationCacheDelegateCallbacks() { m_dumpApplicationCacheDelegateCallbacks = true; } void dumpDatabaseCallbacks() { m_dumpDatabaseCallbacks = true; } void dumpDOMAsWebArchive() { m_whatToDump = DOMAsWebArchive; } + void dumpPolicyDelegateCallbacks() { m_dumpPolicyCallbacks = true; } void setShouldDumpFrameLoadCallbacks(bool value) { m_dumpFrameLoadCallbacks = value; } void setShouldDumpProgressFinishedCallback(bool value) { m_dumpProgressFinishedCallback = value; } @@ -94,11 +101,18 @@ public: void setCanOpenWindows(bool); void setCloseRemainingWindowsWhenComplete(bool value) { m_shouldCloseExtraWindows = value; } void setXSSAuditorEnabled(bool); + void setShadowDOMEnabled(bool); + void setCustomElementsEnabled(bool); + void setModernMediaControlsEnabled(bool); + void setWebGL2Enabled(bool); + void setFetchAPIEnabled(bool); void setAllowUniversalAccessFromFileURLs(bool); void setAllowFileAccessFromFileURLs(bool); + void setNeedsStorageAccessFromFileURLsQuirk(bool); void setPluginsEnabled(bool); void setJavaScriptCanAccessClipboard(bool); void setPrivateBrowsingEnabled(bool); + void setUseDashboardCompatibilityMode(bool); void setPopupBlockingEnabled(bool); void setAuthorAndUserStylesEnabled(bool); void setCustomPolicyDelegate(bool enabled, bool permissive = false); @@ -112,6 +126,12 @@ public: void dispatchPendingLoadRequests(); void setCacheModel(int); void setAsynchronousSpellCheckingEnabled(bool); + void setDownloadAttributeEnabled(bool); + void setAllowsAnySSLCertificate(bool); + void setEncryptedMediaAPIEnabled(bool); + void setSubtleCryptoEnabled(bool); + void setMediaStreamEnabled(bool); + void setPeerConnectionEnabled(bool); // Special DOM functions. void clearBackForwardList(); @@ -151,7 +171,9 @@ public: void setPrinting() { m_isPrinting = true; } // Authentication + void setRejectsProtectionSpaceAndContinueForAuthenticationChallenges(bool); void setHandlesAuthenticationChallenges(bool); + void setShouldLogCanAuthenticateAgainstProtectionSpace(bool); void setAuthenticationUsername(JSStringRef); void setAuthenticationPassword(JSStringRef); @@ -181,6 +203,7 @@ public: bool shouldDumpApplicationCacheDelegateCallbacks() const { return m_dumpApplicationCacheDelegateCallbacks; } bool shouldDumpDatabaseCallbacks() const { return m_dumpDatabaseCallbacks; } bool shouldDumpSelectionRect() const { return m_dumpSelectionRect; } + bool shouldDumpPolicyCallbacks() const { return m_dumpPolicyCallbacks; } bool isPolicyDelegateEnabled() const { return m_policyDelegateEnabled; } bool isPolicyDelegatePermissive() const { return m_policyDelegatePermissive; } @@ -188,6 +211,7 @@ public: bool waitToDump() const { return m_waitToDump; } void waitToDumpWatchdogTimerFired(); void invalidateWaitToDumpWatchdogTimer(); + bool shouldFinishAfterDownload() const { return m_shouldFinishAfterDownload; } bool shouldAllowEditing() const { return m_shouldAllowEditing; } @@ -198,7 +222,8 @@ public: void showWebInspector(); void closeWebInspector(); - void evaluateInWebInspector(long callId, JSStringRef script); + void evaluateInWebInspector(JSStringRef script); + JSRetainPtr<JSStringRef> inspectorTestStubURL(); void setPOSIXLocale(JSStringRef); @@ -206,6 +231,8 @@ public: void setWillSendRequestReturnsNull(bool f) { m_willSendRequestReturnsNull = f; } bool willSendRequestReturnsNullOnRedirect() const { return m_willSendRequestReturnsNullOnRedirect; } void setWillSendRequestReturnsNullOnRedirect(bool f) { m_willSendRequestReturnsNullOnRedirect = f; } + void setWillSendRequestAddsHTTPBody(JSStringRef body) { m_willSendRequestHTTPBody = toWTFString(toWK(body)); } + String willSendRequestHTTPBody() const { return m_willSendRequestHTTPBody; } void setTextDirection(JSStringRef); @@ -232,6 +259,8 @@ public: void setWindowIsKey(bool); + void setViewSize(double width, double height); + void callAddChromeInputFieldCallback(); void callRemoveChromeInputFieldCallback(); void callFocusWebViewCallback(); @@ -247,45 +276,98 @@ public: bool hasCustomFullScreenBehavior() const { return m_customFullScreenBehavior; } // Web notifications. - void grantWebNotificationPermission(JSStringRef origin); - void denyWebNotificationPermission(JSStringRef origin); - void removeAllWebNotificationPermissions(); - void simulateWebNotificationClick(JSValueRef notification); + static void grantWebNotificationPermission(JSStringRef origin); + static void denyWebNotificationPermission(JSStringRef origin); + static void removeAllWebNotificationPermissions(); + static void simulateWebNotificationClick(JSValueRef notification); // Geolocation. void setGeolocationPermission(bool); void setMockGeolocationPosition(double latitude, double longitude, double accuracy, JSValueRef altitude, JSValueRef altitudeAccuracy, JSValueRef heading, JSValueRef speed); void setMockGeolocationPositionUnavailableError(JSStringRef message); + bool isGeolocationProviderActive(); + + // MediaStream + void setUserMediaPermission(bool); + void setUserMediaPersistentPermissionForOrigin(bool permission, JSStringRef origin, JSStringRef parentOrigin); + unsigned userMediaPermissionRequestCountForOrigin(JSStringRef origin, JSStringRef parentOrigin) const; + void resetUserMediaPermissionRequestCountForOrigin(JSStringRef origin, JSStringRef parentOrigin); void setPageVisibility(JSStringRef state); void resetPageVisibility(); bool callShouldCloseOnWebView(); - void setCustomTimeout(int duration); + void setCustomTimeout(int duration) { m_timeout = duration; } // Work queue. void queueBackNavigation(unsigned howFarBackward); void queueForwardNavigation(unsigned howFarForward); - void queueLoad(JSStringRef url, JSStringRef target); + void queueLoad(JSStringRef url, JSStringRef target, bool shouldOpenExternalURLs); void queueLoadHTMLString(JSStringRef content, JSStringRef baseURL, JSStringRef unreachableURL); void queueReload(); void queueLoadingScript(JSStringRef script); void queueNonLoadingScript(JSStringRef script); bool secureEventInputIsEnabled() const; - + + JSValueRef failNextNewCodeBlock(); JSValueRef numberOfDFGCompiles(JSValueRef theFunction); JSValueRef neverInlineFunction(JSValueRef theFunction); -private: - static const double waitToDumpWatchdogTimerInterval; + bool shouldDecideNavigationPolicyAfterDelay() const { return m_shouldDecideNavigationPolicyAfterDelay; } + void setShouldDecideNavigationPolicyAfterDelay(bool); + void setNavigationGesturesEnabled(bool); + void setIgnoresViewportScaleLimits(bool); + void setShouldDownloadUndisplayableMIMETypes(bool); + + void runUIScript(JSStringRef script, JSValueRef callback); + void runUIScriptCallback(unsigned callbackID, JSStringRef result); + + void installDidBeginSwipeCallback(JSValueRef); + void installWillEndSwipeCallback(JSValueRef); + void installDidEndSwipeCallback(JSValueRef); + void installDidRemoveSwipeSnapshotCallback(JSValueRef); + void callDidBeginSwipeCallback(); + void callWillEndSwipeCallback(); + void callDidEndSwipeCallback(); + void callDidRemoveSwipeSnapshotCallback(); + + void clearTestRunnerCallbacks(); + void accummulateLogsForChannel(JSStringRef channel); + + unsigned imageCountInGeneralPasteboard() const; + + // Gamepads + void connectMockGamepad(unsigned index); + void disconnectMockGamepad(unsigned index); + void setMockGamepadDetails(unsigned index, JSStringRef gamepadID, unsigned axisCount, unsigned buttonCount); + void setMockGamepadAxisValue(unsigned index, unsigned axisIndex, double value); + void setMockGamepadButtonValue(unsigned index, unsigned buttonIndex, double value); + + // Resource Load Statistics + void installStatisticsDidModifyDataRecordsCallback(JSValueRef callback); + void statisticsDidModifyDataRecordsCallback(); + void statisticsFireDataModificationHandler(); + void setStatisticsPrevalentResource(JSStringRef hostName, bool value); + bool isStatisticsPrevalentResource(JSStringRef hostName); + void setStatisticsHasHadUserInteraction(JSStringRef hostName, bool value); + bool isStatisticsHasHadUserInteraction(JSStringRef hostName); + void setStatisticsTimeToLiveUserInteraction(double seconds); + void setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool); + void setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(bool); + void setStatisticsMinimumTimeBetweeenDataRecordsRemoval(double); + void statisticsResetToConsistentState(); + +private: TestRunner(); void platformInitialize(); void initializeWaitToDumpWatchdogTimerIfNeeded(); + WKRetainPtr<WKURLRef> m_testURL; // Set by InjectedBundlePage once provisional load starts. + WhatToDump m_whatToDump; bool m_shouldDumpAllFrameScrollPositions; bool m_shouldDumpBackForwardListsForAllWindows; @@ -306,6 +388,7 @@ private: bool m_dumpWillCacheResponse; bool m_dumpApplicationCacheDelegateCallbacks; bool m_dumpDatabaseCallbacks; + bool m_dumpPolicyCallbacks { false }; bool m_disallowIncreaseForApplicationCacheQuota; bool m_waitToDump; // True if waitUntilDone() has been called, but notifyDone() has not yet been called. bool m_testRepaint; @@ -315,6 +398,7 @@ private: bool m_willSendRequestReturnsNull; bool m_willSendRequestReturnsNullOnRedirect; bool m_shouldStopProvisionalFrameLoads; + String m_willSendRequestHTTPBody; bool m_policyDelegateEnabled; bool m_policyDelegatePermissive; @@ -327,12 +411,17 @@ private: double m_databaseDefaultQuota; double m_databaseMaxQuota; + bool m_shouldDecideNavigationPolicyAfterDelay { false }; + bool m_shouldFinishAfterDownload { false }; + bool m_userStyleSheetEnabled; WKRetainPtr<WKStringRef> m_userStyleSheetLocation; + WKRetainPtr<WKArrayRef> m_allowedHosts; + + size_t m_userMediaPermissionRequestCount { 0 }; + PlatformTimerRef m_waitToDumpWatchdogTimer; }; } // namespace WTR - -#endif // TestRunner_h diff --git a/Tools/WebKitTestRunner/InjectedBundle/TextInputController.cpp b/Tools/WebKitTestRunner/InjectedBundle/TextInputController.cpp index 0087aa301..2e304e28c 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/TextInputController.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/TextInputController.cpp @@ -30,13 +30,13 @@ #include "InjectedBundlePage.h" #include "JSTextInputController.h" #include "StringFunctions.h" -#include <WebKit2/WKBundlePagePrivate.h> +#include <WebKit/WKBundlePagePrivate.h> namespace WTR { -PassRefPtr<TextInputController> TextInputController::create() +Ref<TextInputController> TextInputController::create() { - return adoptRef(new TextInputController); + return adoptRef(*new TextInputController); } TextInputController::TextInputController() @@ -59,22 +59,22 @@ void TextInputController::makeWindowObject(JSContextRef context, JSObjectRef win void TextInputController::setMarkedText(JSStringRef text, int from, int length) { - WKBundlePageSetComposition(InjectedBundle::shared().page()->page(), toWK(text).get(), from, length); + WKBundlePageSetComposition(InjectedBundle::singleton().page()->page(), toWK(text).get(), from, length); } bool TextInputController::hasMarkedText() { - return WKBundlePageHasComposition(InjectedBundle::shared().page()->page()); + return WKBundlePageHasComposition(InjectedBundle::singleton().page()->page()); } void TextInputController::unmarkText() { - WKBundlePageConfirmComposition(InjectedBundle::shared().page()->page()); + WKBundlePageConfirmComposition(InjectedBundle::singleton().page()->page()); } void TextInputController::insertText(JSStringRef text) { - WKBundlePageConfirmCompositionWithText(InjectedBundle::shared().page()->page(), toWK(text).get()); + WKBundlePageConfirmCompositionWithText(InjectedBundle::singleton().page()->page(), toWK(text).get()); } } // namespace WTR diff --git a/Tools/WebKitTestRunner/InjectedBundle/TextInputController.h b/Tools/WebKitTestRunner/InjectedBundle/TextInputController.h index 71a043752..ed174816f 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/TextInputController.h +++ b/Tools/WebKitTestRunner/InjectedBundle/TextInputController.h @@ -23,17 +23,16 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef TextInputController_h -#define TextInputController_h +#pragma once #include "JSWrappable.h" -#include <wtf/PassRefPtr.h> +#include <wtf/Ref.h> namespace WTR { class TextInputController : public JSWrappable { public: - static PassRefPtr<TextInputController> create(); + static Ref<TextInputController> create(); virtual ~TextInputController(); // JSWrappable @@ -51,5 +50,3 @@ private: }; } // namespace WTR - -#endif // TextInputController_h diff --git a/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityControllerAtk.cpp b/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityControllerAtk.cpp index 3573a2a5c..a1a554a9d 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityControllerAtk.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityControllerAtk.cpp @@ -33,35 +33,14 @@ #include "InjectedBundle.h" #include "InjectedBundlePage.h" -#include <WebKit2/WKBundlePagePrivate.h> +#include <WebKit/WKBundlePagePrivate.h> #include <atk/atk.h> #include <cstdio> -#include <wtf/gobject/GUniquePtr.h> +#include <wtf/glib/GUniquePtr.h> #include <wtf/text/StringBuilder.h> namespace WTR { -void AccessibilityController::logAccessibilityEvents() -{ - // Ensure no callbacks are connected before. - resetToConsistentState(); - - // Ensure that accessibility is initialized for the WebView by querying for - // the root accessible object, which will create the full hierarchy. - rootElement(); - - if (!m_globalNotificationHandler) - m_globalNotificationHandler = AccessibilityNotificationHandler::create(); - m_globalNotificationHandler->logAccessibilityEvents(); - - // Ensure the Atk interface types are registered, otherwise - // the AtkDocument signal handlers below won't get registered. - GObject* dummyAxObject = G_OBJECT(g_object_new(ATK_TYPE_OBJECT, nullptr)); - AtkObject* dummyNoOpAxObject = atk_no_op_object_new(dummyAxObject); - g_object_unref(G_OBJECT(dummyNoOpAxObject)); - g_object_unref(dummyAxObject); -} - void AccessibilityController::resetToConsistentState() { m_globalNotificationHandler = nullptr; @@ -97,9 +76,9 @@ static AtkObject* childElementById(AtkObject* parent, const char* id) return nullptr; } -PassRefPtr<AccessibilityUIElement> AccessibilityController::accessibleElementById(JSStringRef id) +RefPtr<AccessibilityUIElement> AccessibilityController::accessibleElementById(JSStringRef id) { - AtkObject* root = ATK_OBJECT(WKAccessibilityRootObject(InjectedBundle::shared().page()->page())); + AtkObject* root = ATK_OBJECT(WKAccessibilityRootObject(InjectedBundle::singleton().page()->page())); if (!root) return nullptr; @@ -120,17 +99,17 @@ JSRetainPtr<JSStringRef> AccessibilityController::platformName() return platformName; } -PassRefPtr<AccessibilityUIElement> AccessibilityController::rootElement() +Ref<AccessibilityUIElement> AccessibilityController::rootElement() { - WKBundlePageRef page = InjectedBundle::shared().page()->page(); + WKBundlePageRef page = InjectedBundle::singleton().page()->page(); void* root = WKAccessibilityRootObject(page); return AccessibilityUIElement::create(static_cast<AtkObject*>(root)); } -PassRefPtr<AccessibilityUIElement> AccessibilityController::focusedElement() +Ref<AccessibilityUIElement> AccessibilityController::focusedElement() { - WKBundlePageRef page = InjectedBundle::shared().page()->page(); + WKBundlePageRef page = InjectedBundle::singleton().page()->page(); void* root = WKAccessibilityFocusedObject(page); return AccessibilityUIElement::create(static_cast<AtkObject*>(root)); diff --git a/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.cpp b/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.cpp index b6af081c2..bb2280877 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.cpp @@ -25,12 +25,12 @@ #include "InjectedBundle.h" #include "InjectedBundlePage.h" #include "JSWrapper.h" -#include <WebKit2/WKBundleFrame.h> -#include <WebKit2/WKBundlePage.h> -#include <WebKit2/WKBundlePagePrivate.h> +#include <WebKit/WKBundleFrame.h> +#include <WebKit/WKBundlePage.h> +#include <WebKit/WKBundlePagePrivate.h> #include <wtf/HashMap.h> #include <wtf/Vector.h> -#include <wtf/gobject/GUniquePtr.h> +#include <wtf/glib/GUniquePtr.h> #include <wtf/text/CString.h> #include <wtf/text/WTFString.h> @@ -43,29 +43,6 @@ typedef HashMap<AtkObject*, AccessibilityNotificationHandler*> NotificationHandl WTF::Vector<unsigned> listenerIds; NotificationHandlersMap notificationHandlers; AccessibilityNotificationHandler* globalNotificationHandler = nullptr; -bool loggingAccessibilityEvents = false; - -void printAccessibilityEvent(AtkObject* accessible, const char* signalName, const char* signalValue) -{ - // Do not handle state-change:defunct signals, as the AtkObject - // associated to them will not be valid at this point already. - if (!signalName || !g_strcmp0(signalName, "state-change:defunct")) - return; - - if (!accessible || !ATK_IS_OBJECT(accessible)) - return; - - const char* objectName = atk_object_get_name(accessible); - AtkRole objectRole = atk_object_get_role(accessible); - - // Try to always provide a name to be logged for the object. - if (!objectName || *objectName == '\0') - objectName = "(No name)"; - - GUniquePtr<char> signalNameAndValue(signalValue ? g_strdup_printf("%s = %s", signalName, signalValue) : g_strdup(signalName)); - GUniquePtr<char> accessibilityEventString(g_strdup_printf("Accessibility object emitted \"%s\" / Name: \"%s\" / Role: %d\n", signalNameAndValue.get(), objectName, objectRole)); - InjectedBundle::shared().outputText(String::fromUTF8(accessibilityEventString.get())); -} gboolean axObjectEventListener(GSignalInvocationHint* signalHint, unsigned numParamValues, const GValue* paramValues, gpointer data) { @@ -78,7 +55,7 @@ gboolean axObjectEventListener(GSignalInvocationHint* signalHint, unsigned numPa return true; #if PLATFORM(GTK) || PLATFORM(EFL) - WKBundlePageRef page = InjectedBundle::shared().page()->page(); + WKBundlePageRef page = InjectedBundle::singleton().page()->page(); WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(page); JSContextRef jsContext = WKBundleFrameGetJavaScriptContext(mainFrame); #else @@ -86,47 +63,39 @@ gboolean axObjectEventListener(GSignalInvocationHint* signalHint, unsigned numPa #endif GSignalQuery signalQuery; - GUniquePtr<char> signalName; - GUniquePtr<char> signalValue; const char* notificationName = nullptr; Vector<JSValueRef> extraArgs; g_signal_query(signalHint->signal_id, &signalQuery); if (!g_strcmp0(signalQuery.signal_name, "state-change")) { - signalName.reset(g_strdup_printf("state-change:%s", g_value_get_string(¶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, "selection-changed")) { + notificationName = "AXSelectedChildrenChanged"; } else if (!g_strcmp0(signalQuery.signal_name, "children-changed")) { const gchar* childrenChangedDetail = g_quark_to_string(signalHint->detail); - signalName.reset(g_strdup_printf("children-changed:%s", childrenChangedDetail)); - signalValue.reset(g_strdup_printf("%d", g_value_get_uint(¶mValues[1]))); notificationName = !g_strcmp0(childrenChangedDetail, "add") ? "AXChildrenAdded" : "AXChildrenRemoved"; + gpointer child = g_value_get_pointer(¶mValues[2]); + if (ATK_IS_OBJECT(child)) + extraArgs.append(toJS(jsContext, WTF::getPtr(WTR::AccessibilityUIElement::create(ATK_OBJECT(child))))); } else if (!g_strcmp0(signalQuery.signal_name, "property-change")) { - signalName.reset(g_strdup_printf("property-change:%s", g_quark_to_string(signalHint->detail))); if (!g_strcmp0(g_quark_to_string(signalHint->detail), "accessible-value")) notificationName = "AXValueChanged"; } else if (!g_strcmp0(signalQuery.signal_name, "load-complete")) notificationName = "AXLoadComplete"; else if (!g_strcmp0(signalQuery.signal_name, "text-caret-moved")) { notificationName = "AXTextCaretMoved"; - signalName.reset(g_strdup(signalQuery.signal_name)); - signalValue.reset(g_strdup_printf("%d", g_value_get_int(¶mValues[1]))); + GUniquePtr<char> signalValue(g_strdup_printf("%d", g_value_get_int(¶mValues[1]))); JSRetainPtr<JSStringRef> jsSignalValue(Adopt, JSStringCreateWithUTF8CString(signalValue.get())); extraArgs.append(JSValueMakeString(jsContext, jsSignalValue.get())); - } else - signalName.reset(g_strdup(signalQuery.signal_name)); - - if (loggingAccessibilityEvents) - printAccessibilityEvent(accessible, signalName.get(), signalValue.get()); + } else if (!g_strcmp0(signalQuery.signal_name, "text-insert") || !g_strcmp0(signalQuery.signal_name, "text-remove")) + notificationName = "AXTextChanged"; if (!jsContext) return true; @@ -174,12 +143,6 @@ AccessibilityNotificationHandler::~AccessibilityNotificationHandler() disconnectAccessibilityCallbacks(); } -void AccessibilityNotificationHandler::logAccessibilityEvents() -{ - connectAccessibilityCallbacks(); - loggingAccessibilityEvents = true; -} - void AccessibilityNotificationHandler::setNotificationFunctionCallback(JSValueRef notificationFunctionCallback) { if (!notificationFunctionCallback) { @@ -191,7 +154,7 @@ void AccessibilityNotificationHandler::setNotificationFunctionCallback(JSValueRe m_notificationFunctionCallback = notificationFunctionCallback; #if PLATFORM(GTK) || PLATFORM(EFL) - WKBundlePageRef page = InjectedBundle::shared().page()->page(); + WKBundlePageRef page = InjectedBundle::singleton().page()->page(); WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(page); JSContextRef jsContext = WKBundleFrameGetJavaScriptContext(mainFrame); #else @@ -222,7 +185,7 @@ void AccessibilityNotificationHandler::setNotificationFunctionCallback(JSValueRe void AccessibilityNotificationHandler::removeAccessibilityNotificationHandler() { #if PLATFORM(GTK) || PLATFORM(EFL) - WKBundlePageRef page = InjectedBundle::shared().page()->page(); + WKBundlePageRef page = InjectedBundle::singleton().page()->page(); WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(page); JSContextRef jsContext = WKBundleFrameGetJavaScriptContext(mainFrame); #else @@ -257,7 +220,10 @@ void AccessibilityNotificationHandler::connectAccessibilityCallbacks() "ATK:AtkObject:property-change", "ATK:AtkObject:visible-data-changed", "ATK:AtkDocument:load-complete", + "ATK:AtkSelection:selection-changed", "ATK:AtkText:text-caret-moved", + "ATK:AtkText:text-insert", + "ATK:AtkText:text-remove", 0 }; @@ -271,7 +237,7 @@ void AccessibilityNotificationHandler::connectAccessibilityCallbacks() unsigned id = atk_add_global_event_listener(axObjectEventListener, *signalName); if (!id) { String message = String::format("atk_add_global_event_listener failed for signal %s\n", *signalName); - InjectedBundle::shared().outputText(message); + InjectedBundle::singleton().outputText(message); continue; } diff --git a/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.h b/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.h index 3443bce2c..da5d8ecdd 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.h +++ b/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.h @@ -17,32 +17,29 @@ * Boston, MA 02110-1301, USA. */ -#ifndef AccessibilityNotificationHandlerAtk_h -#define AccessibilityNotificationHandlerAtk_h +#pragma once #if HAVE(ACCESSIBILITY) #include <JavaScriptCore/JSObjectRef.h> #include <atk/atk.h> #include <atk/atkobject.h> -#include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> -#include <wtf/gobject/GRefPtr.h> +#include <wtf/glib/GRefPtr.h> namespace WTR { class AccessibilityNotificationHandler : public RefCounted<AccessibilityNotificationHandler> { public: - static PassRefPtr<AccessibilityNotificationHandler> create() + static Ref<AccessibilityNotificationHandler> create() { - return adoptRef(new AccessibilityNotificationHandler()); + return adoptRef(*new AccessibilityNotificationHandler()); } ~AccessibilityNotificationHandler(); void setPlatformElement(GRefPtr<AtkObject> platformElement) { m_platformElement = platformElement; } GRefPtr<AtkObject> platformElement() const { return m_platformElement; } void setNotificationFunctionCallback(JSValueRef); JSValueRef notificationFunctionCallback() const { return m_notificationFunctionCallback; } - void logAccessibilityEvents(); private: AccessibilityNotificationHandler(); @@ -57,5 +54,3 @@ private: } // namespace WTR #endif // HAVE(ACCESSIBILITY) - -#endif // AccessibilityNotificationHandlerAtk_h diff --git a/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp b/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp index 440377937..7ecf65a29 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp @@ -35,10 +35,13 @@ #include "NotImplemented.h" #include <JavaScriptCore/JSStringRef.h> #include <JavaScriptCore/OpaqueJSString.h> +#if ATK_CHECK_VERSION(2,11,90) +#include <WebKit/WKBundleFrame.h> +#endif #include <atk/atk.h> #include <wtf/Assertions.h> -#include <wtf/gobject/GRefPtr.h> -#include <wtf/gobject/GUniquePtr.h> +#include <wtf/glib/GRefPtr.h> +#include <wtf/glib/GUniquePtr.h> #include <wtf/text/CString.h> #include <wtf/text/StringBuilder.h> #include <wtf/text/WTFString.h> @@ -48,6 +51,13 @@ namespace WTR { namespace { +#if ATK_CHECK_VERSION(2,11,92) +enum RangeLimit { + RangeLimitMinimum, + RangeLimitMaximum +}; +#endif + enum AtkAttributeType { ObjectAttributeType, TextAttributeType @@ -61,6 +71,8 @@ enum AttributeDomain { enum AttributesIndex { // Attribute names. InvalidNameIndex = 0, + PosInSetIndex, + SetSizeIndex, PlaceholderNameIndex, SortNameIndex, @@ -76,6 +88,8 @@ enum AttributesIndex { const String attributesMap[][2] = { // Attribute names. { "AXInvalid", "invalid" }, + { "AXARIAPosInSet", "posinset" }, + { "AXARIASetSize", "setsize" }, { "AXPlaceholderValue", "placeholder-text" } , { "AXSortDirection", "sort" }, @@ -91,6 +105,7 @@ const char* landmarkStringComplementary = "AXLandmarkComplementary"; const char* landmarkStringContentinfo = "AXLandmarkContentInfo"; const char* landmarkStringMain = "AXLandmarkMain"; const char* landmarkStringNavigation = "AXLandmarkNavigation"; +const char* landmarkStringRegion = "AXLandmarkRegion"; const char* landmarkStringSearch = "AXLandmarkSearch"; #endif @@ -172,9 +187,8 @@ String getAttributeSetValueForId(AtkObject* accessible, AtkAttributeType type, S return atkAttributeValueToCoreAttributeValue(type, id, attributeValue); } -String getAtkAttributeSetAsString(AtkObject* accessible, AtkAttributeType type) +String attributeSetToString(AtkAttributeSet* attributeSet, String separator=", ") { - AtkAttributeSet* attributeSet = getAttributeSet(accessible, type); if (!attributeSet) return String(); @@ -184,13 +198,18 @@ String getAtkAttributeSetAsString(AtkObject* accessible, AtkAttributeType type) GUniquePtr<gchar> attributeData(g_strconcat(attribute->name, ":", attribute->value, NULL)); builder.append(attributeData.get()); if (attributes->next) - builder.append(", "); + builder.append(separator); } atk_attribute_set_free(attributeSet); return builder.toString(); } +String getAtkAttributeSetAsString(AtkObject* accessible, AtkAttributeType type, String separator=", ") +{ + return attributeSetToString(getAttributeSet(accessible, type), separator); +} + bool checkElementState(PlatformUIElement element, AtkStateType stateType) { if (!ATK_IS_OBJECT(element.get())) @@ -203,7 +222,10 @@ bool checkElementState(PlatformUIElement element, AtkStateType stateType) JSStringRef indexRangeInTable(PlatformUIElement element, bool isRowRange) { GUniquePtr<gchar> rangeString(g_strdup("{0, 0}")); - +#if ATK_CHECK_VERSION(2,11,90) + if (!ATK_IS_TABLE_CELL(element.get())) + return JSStringCreateWithUTF8CString(rangeString.get()); +#else if (!ATK_IS_OBJECT(element.get())) return JSStringCreateWithUTF8CString(rangeString.get()); @@ -215,11 +237,20 @@ JSStringRef indexRangeInTable(PlatformUIElement element, bool isRowRange) gint indexInParent = atk_object_get_index_in_parent(ATK_OBJECT(element.get())); if (indexInParent == -1) return JSStringCreateWithUTF8CString(rangeString.get()); +#endif - int row = -1; - int column = -1; + gint row = -1; + gint column = -1; + gint rowSpan = -1; + gint columnSpan = -1; +#if ATK_CHECK_VERSION(2,11,90) + atk_table_cell_get_row_column_span(ATK_TABLE_CELL(element.get()), &row, &column, &rowSpan, &columnSpan); +#else row = atk_table_get_row_at_index(ATK_TABLE(axTable), indexInParent); column = atk_table_get_column_at_index(ATK_TABLE(axTable), indexInParent); + rowSpan = atk_table_get_row_extent_at(ATK_TABLE(axTable), row, column); + columnSpan = atk_table_get_column_extent_at(ATK_TABLE(axTable), row, column); +#endif // Get the actual values, if row and columns are valid values. if (row != -1 && column != -1) { @@ -227,10 +258,10 @@ JSStringRef indexRangeInTable(PlatformUIElement element, bool isRowRange) int length = 0; if (isRowRange) { base = row; - length = atk_table_get_row_extent_at(ATK_TABLE(axTable), row, column); + length = rowSpan; } else { base = column; - length = atk_table_get_column_extent_at(ATK_TABLE(axTable), row, column); + length = columnSpan; } rangeString.reset(g_strdup_printf("{%d, %d}", base, length)); } @@ -243,6 +274,13 @@ void alterCurrentValue(PlatformUIElement element, int factor) if (!ATK_IS_VALUE(element.get())) return; +#if ATK_CHECK_VERSION(2,11,92) + double currentValue; + atk_value_get_value_and_text(ATK_VALUE(element.get()), ¤tValue, nullptr); + + double increment = atk_value_get_increment(ATK_VALUE(element.get())); + atk_value_set_value(ATK_VALUE(element.get()), currentValue + factor * increment); +#else GValue currentValue = G_VALUE_INIT; atk_value_get_current_value(ATK_VALUE(element.get()), ¤tValue); @@ -258,6 +296,7 @@ void alterCurrentValue(PlatformUIElement element, int factor) g_value_unset(&newValue); g_value_unset(&increment); g_value_unset(¤tValue); +#endif } gchar* replaceCharactersForResults(gchar* str) @@ -283,17 +322,19 @@ const gchar* roleToString(AtkObject* object) #if ATK_CHECK_VERSION(2, 11, 3) if (role == ATK_ROLE_LANDMARK) { String xmlRolesValue = getAttributeSetValueForId(object, ObjectAttributeType, "xml-roles"); - if (equalIgnoringCase(xmlRolesValue, "banner")) + if (equalLettersIgnoringASCIICase(xmlRolesValue, "banner")) return landmarkStringBanner; - if (equalIgnoringCase(xmlRolesValue, "complementary")) + if (equalLettersIgnoringASCIICase(xmlRolesValue, "complementary")) return landmarkStringComplementary; - if (equalIgnoringCase(xmlRolesValue, "contentinfo")) + if (equalLettersIgnoringASCIICase(xmlRolesValue, "contentinfo")) return landmarkStringContentinfo; - if (equalIgnoringCase(xmlRolesValue, "main")) + if (equalLettersIgnoringASCIICase(xmlRolesValue, "main")) return landmarkStringMain; - if (equalIgnoringCase(xmlRolesValue, "navigation")) + if (equalLettersIgnoringASCIICase(xmlRolesValue, "navigation")) return landmarkStringNavigation; - if (equalIgnoringCase(xmlRolesValue, "search")) + if (equalLettersIgnoringASCIICase(xmlRolesValue, "region")) + return landmarkStringRegion; + if (equalLettersIgnoringASCIICase(xmlRolesValue, "search")) return landmarkStringSearch; } #endif @@ -305,6 +346,8 @@ const gchar* roleToString(AtkObject* object) return "AXDialog"; case ATK_ROLE_CANVAS: return "AXCanvas"; + case ATK_ROLE_CAPTION: + return "AXCaption"; case ATK_ROLE_CHECK_BOX: return "AXCheckBox"; case ATK_ROLE_COLOR_CHOOSER: @@ -339,6 +382,8 @@ const gchar* roleToString(AtkObject* object) return "AXInvalid"; case ATK_ROLE_LABEL: return "AXLabel"; + case ATK_ROLE_LEVEL_BAR: + return "AXProgressIndicator"; case ATK_ROLE_LINK: return "AXLink"; case ATK_ROLE_LIST: @@ -420,6 +465,10 @@ const gchar* roleToString(AtkObject* object) #if ATK_CHECK_VERSION(2, 11, 3) case ATK_ROLE_ARTICLE: return "AXArticle"; + case ATK_ROLE_AUDIO: + return "AXAudio"; + case ATK_ROLE_BLOCK_QUOTE: + return "AXBlockquote"; case ATK_ROLE_DEFINITION: return "AXDefinition"; case ATK_ROLE_LOG: @@ -430,6 +479,8 @@ const gchar* roleToString(AtkObject* object) return "AXMath"; case ATK_ROLE_TIMER: return "AXTimer"; + case ATK_ROLE_VIDEO: + return "AXVideo"; #endif #if ATK_CHECK_VERSION(2, 11, 4) case ATK_ROLE_DESCRIPTION_LIST: @@ -439,6 +490,20 @@ const gchar* roleToString(AtkObject* object) case ATK_ROLE_DESCRIPTION_VALUE: return "AXDescriptionValue"; #endif +#if ATK_CHECK_VERSION(2, 15, 2) + case ATK_ROLE_STATIC: + return "AXStatic"; +#endif +#if ATK_CHECK_VERSION(2, 15, 4) + case ATK_ROLE_MATH_FRACTION: + return "AXMathFraction"; + case ATK_ROLE_MATH_ROOT: + return "AXMathRoot"; + case ATK_ROLE_SUBSCRIPT: + return "AXSubscript"; + case ATK_ROLE_SUPERSCRIPT: + return "AXSuperscript"; +#endif default: // We want to distinguish ATK_ROLE_UNKNOWN from a known AtkRole which // our DRT isn't properly handling. @@ -446,6 +511,19 @@ const gchar* roleToString(AtkObject* object) } } +String selectedText(AtkObject* accessible) +{ + if (!ATK_IS_TEXT(accessible)) + return String(); + + AtkText* text = ATK_TEXT(accessible); + + gint start, end; + g_free(atk_text_get_selection(text, 0, &start, &end)); + + return atk_text_get_text(text, start, end); +} + String attributesOfElement(AccessibilityUIElement* element) { StringBuilder builder; @@ -552,6 +630,53 @@ static Vector<RefPtr<AccessibilityUIElement> > getVisibleCells(AccessibilityUIEl return visibleCells; } +#if ATK_CHECK_VERSION(2,11,90) +static Vector<RefPtr<AccessibilityUIElement>> convertGPtrArrayToVector(const GPtrArray* array) +{ + Vector<RefPtr<AccessibilityUIElement>> cells; + for (guint i = 0; i < array->len; i++) { + if (AtkObject* atkObject = static_cast<AtkObject*>(g_ptr_array_index(array, i))) + cells.append(AccessibilityUIElement::create(atkObject)); + } + return cells; +} + +static JSValueRef convertToJSObjectArray(const Vector<RefPtr<AccessibilityUIElement>>& children) +{ + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page()); + JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame); + + size_t elementCount = children.size(); + auto valueElements = std::make_unique<JSValueRef[]>(elementCount); + for (size_t i = 0; i < elementCount; i++) + valueElements[i] = JSObjectMake(context, children[i]->wrapperClass(), children[i].get()); + + return JSObjectMakeArray(context, elementCount, valueElements.get(), nullptr); +} +#endif + +#if ATK_CHECK_VERSION(2,11,92) +static double rangeMinMaxValue(AtkValue* atkValue, RangeLimit rangeLimit) +{ + AtkRange* range = atk_value_get_range(atkValue); + if (!range) + return 0; + + double rangeValue = 0; + switch (rangeLimit) { + case RangeLimitMinimum: + rangeValue = atk_range_get_lower_limit(range); + break; + case RangeLimitMaximum: + rangeValue = atk_range_get_upper_limit(range); + break; + }; + + atk_range_free(range); + return rangeValue; +} +#endif + } // namespace AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element) @@ -605,7 +730,7 @@ int AccessibilityUIElement::childrenCount() return atk_object_get_n_accessible_children(ATK_OBJECT(m_element.get())); } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::elementAtPoint(int x, int y) +RefPtr<AccessibilityUIElement> AccessibilityUIElement::elementAtPoint(int x, int y) { if (!ATK_IS_COMPONENT(m_element.get())) return nullptr; @@ -630,7 +755,7 @@ unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element) return 0; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::childAtIndex(unsigned index) +RefPtr<AccessibilityUIElement> AccessibilityUIElement::childAtIndex(unsigned index) { if (!ATK_IS_OBJECT(m_element.get())) return nullptr; @@ -644,28 +769,16 @@ PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::childAtIndex(unsigned return nullptr; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::linkedUIElementAtIndex(unsigned index) -{ - // FIXME: implement - return nullptr; -} - -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index) +static RefPtr<AccessibilityUIElement> accessibilityElementAtIndex(AtkObject* element, AtkRelationType relationType, unsigned index) { - // FIXME: implement - return nullptr; -} - -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index) -{ - if (!ATK_IS_OBJECT(m_element.get())) + if (!ATK_IS_OBJECT(element)) return nullptr; - AtkRelationSet* relationSet = atk_object_ref_relation_set(ATK_OBJECT(m_element.get())); + AtkRelationSet* relationSet = atk_object_ref_relation_set(element); if (!relationSet) return nullptr; - AtkRelation* relation = atk_relation_set_get_relation_by_type(relationSet, ATK_RELATION_FLOWS_TO); + AtkRelation* relation = atk_relation_set_get_relation_by_type(relationSet, relationType); if (!relation) return nullptr; @@ -673,43 +786,80 @@ PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaFlowToElementAtIn if (!targetList || !targetList->len || index >= targetList->len) return nullptr; + AtkObject* target = static_cast<AtkObject*>(g_ptr_array_index(targetList, index)); g_object_unref(relationSet); - AtkObject* target = static_cast<AtkObject*>(g_ptr_array_index(targetList, index)); - return target ? AccessibilityUIElement::create(target) : nullptr; + return target ? AccessibilityUIElement::create(target).ptr() : nullptr; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedRowAtIndex(unsigned index) +RefPtr<AccessibilityUIElement> AccessibilityUIElement::linkedUIElementAtIndex(unsigned index) { // FIXME: implement return nullptr; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::rowAtIndex(unsigned index) +RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index) { // FIXME: implement return nullptr; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedChildAtIndex(unsigned index) const +RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index) +{ + return accessibilityElementAtIndex(m_element.get(), ATK_RELATION_FLOWS_TO, index); +} + +RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaControlsElementAtIndex(unsigned index) +{ + return accessibilityElementAtIndex(m_element.get(), ATK_RELATION_CONTROLLER_FOR, index); +} + +RefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedRowAtIndex(unsigned index) { // FIXME: implement return nullptr; } +RefPtr<AccessibilityUIElement> AccessibilityUIElement::rowAtIndex(unsigned index) +{ + // ATK doesn't have API to get an accessible row by index directly. It does, however, have + // API to get cells in the row specified by index. The parent of a cell should be the row. + AtkTable* axTable = ATK_TABLE(m_element.get()); + unsigned nColumns = columnCount(); + for (unsigned col = 0; col < nColumns; col++) { + // Find the first cell in this row that only spans one row. + if (atk_table_get_row_extent_at(axTable, index, col) == 1) { + AtkObject* cell = atk_table_ref_at(axTable, index, col); + return cell ? AccessibilityUIElement::create(atk_object_get_parent(cell)).ptr() : nullptr; + } + } + + return nullptr; +} + +RefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedChildAtIndex(unsigned index) const +{ + if (!ATK_SELECTION(m_element.get())) + return nullptr; + + GRefPtr<AtkObject> child = adoptGRef(atk_selection_ref_selection(ATK_SELECTION(m_element.get()), index)); + return child ? AccessibilityUIElement::create(child.get()).ptr() : nullptr; +} + unsigned AccessibilityUIElement::selectedChildrenCount() const { - // FIXME: implement - return 0; + if (!ATK_IS_SELECTION(m_element.get())) + return 0; + return atk_selection_get_selection_count(ATK_SELECTION(m_element.get())); } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedRowAtIndex(unsigned index) +RefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedRowAtIndex(unsigned index) { // FIXME: implement return nullptr; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::titleUIElement() +RefPtr<AccessibilityUIElement> AccessibilityUIElement::titleUIElement() { if (!ATK_IS_OBJECT(m_element.get())) return nullptr; @@ -730,19 +880,19 @@ PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::titleUIElement() } g_object_unref(set); - return target ? AccessibilityUIElement::create(target) : nullptr; + return target ? AccessibilityUIElement::create(target).ptr() : nullptr; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::parentElement() +RefPtr<AccessibilityUIElement> AccessibilityUIElement::parentElement() { if (!ATK_IS_OBJECT(m_element.get())) return nullptr; AtkObject* parent = atk_object_get_parent(ATK_OBJECT(m_element.get())); - return parent ? AccessibilityUIElement::create(parent) : nullptr; + return parent ? AccessibilityUIElement::create(parent).ptr() : nullptr; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedByRow() +RefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedByRow() { // FIXME: implement return nullptr; @@ -786,7 +936,13 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::stringAttributeValue(JSStringRe String atkAttributeName = coreAttributeToAtkAttribute(attribute); - // Try object attributes first. + // The value of AXSelectedText is not exposed through any AtkAttribute. + if (atkAttributeName == "AXSelectedText") { + String string = selectedText(m_element.get()); + return JSStringCreateWithUTF8CString(string.utf8().data()); + } + + // Try object attributes before text attributes. String attributeValue = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, atkAttributeName); // Try text attributes if the requested one was not found and we have an AtkText object. @@ -812,7 +968,19 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::stringAttributeValue(JSStringRe double AccessibilityUIElement::numberAttributeValue(JSStringRef attribute) { - // FIXME: implement + if (!ATK_IS_OBJECT(m_element.get())) + return 0; + + String atkAttributeName = coreAttributeToAtkAttribute(attribute); + if (atkAttributeName.isEmpty()) + return 0; + + if (atkAttributeName == "setsize" || atkAttributeName == "posinset") { + String attributeValue = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, atkAttributeName); + if (!attributeValue.isEmpty()) + return attributeValue.toDouble(); + } + return 0; } @@ -824,25 +992,87 @@ JSValueRef AccessibilityUIElement::uiElementArrayAttributeValue(JSStringRef attr JSValueRef AccessibilityUIElement::rowHeaders() const { - // FIXME: implement +#if ATK_CHECK_VERSION(2,11,90) + if (!ATK_IS_TABLE_CELL(m_element.get())) + return nullptr; + + GRefPtr<GPtrArray> array = adoptGRef(atk_table_cell_get_row_header_cells(ATK_TABLE_CELL(m_element.get()))); + if (!array) + return nullptr; + + Vector<RefPtr<AccessibilityUIElement>> rows = convertGPtrArrayToVector(array.get()); + return convertToJSObjectArray(rows); +#else return nullptr; +#endif } JSValueRef AccessibilityUIElement::columnHeaders() const { - // FIXME: implement +#if ATK_CHECK_VERSION(2,11,90) + if (!ATK_IS_TABLE_CELL(m_element.get()) && !ATK_IS_TABLE(m_element.get())) + return nullptr; + + Vector<RefPtr<AccessibilityUIElement>> columns; + if (ATK_IS_TABLE_CELL(m_element.get())) { + GRefPtr<GPtrArray> array = adoptGRef(atk_table_cell_get_column_header_cells(ATK_TABLE_CELL(m_element.get()))); + if (!array) + return nullptr; + + columns = convertGPtrArrayToVector(array.get()); + } else + columns = getColumnHeaders(ATK_TABLE(m_element.get())); + return convertToJSObjectArray(columns); +#else return nullptr; +#endif } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementAttributeValue(JSStringRef attribute) const +RefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementAttributeValue(JSStringRef attribute) const { - // FIXME: implement + if (!ATK_IS_OBJECT(m_element.get())) + return nullptr; + + // ATK does not have this API. So we're "faking it" here on a case-by-case basis. + String attributeString = jsStringToWTFString(attribute); + AtkRole role = atk_object_get_role(ATK_OBJECT(m_element.get())); + if (role == ATK_ROLE_SPIN_BUTTON && const_cast<AccessibilityUIElement*>(this)->childrenCount() == 2) { + if (attributeString == "AXDecrementButton") + return const_cast<AccessibilityUIElement*>(this)->childAtIndex(0); + if (attributeString == "AXIncrementButton") + return const_cast<AccessibilityUIElement*>(this)->childAtIndex(1); + } + return nullptr; } bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute) { - // FIXME: implement + if (!ATK_IS_OBJECT(m_element.get())) + return false; + + String attributeString = jsStringToWTFString(attribute); + if (attributeString == "AXElementBusy") + return checkElementState(m_element.get(), ATK_STATE_BUSY); + if (attributeString == "AXChecked") + return checkElementState(m_element.get(), ATK_STATE_CHECKED); + if (attributeString == "AXEnabled") + return checkElementState(m_element.get(), ATK_STATE_ENABLED); + if (attributeString == "AXExpanded") + return checkElementState(m_element.get(), ATK_STATE_EXPANDED); + if (attributeString == "AXFocused") + return checkElementState(m_element.get(), ATK_STATE_FOCUSED); + if (attributeString == "AXInvalid") + return checkElementState(m_element.get(), ATK_STATE_INVALID); + if (attributeString == "AXMultiSelectable") + return checkElementState(m_element.get(), ATK_STATE_MULTISELECTABLE); + if (attributeString == "AXRequired") + return checkElementState(m_element.get(), ATK_STATE_REQUIRED); + if (attributeString == "AXSelected") + return checkElementState(m_element.get(), ATK_STATE_SELECTED); + if (attributeString == "AXVisited") + return checkElementState(m_element.get(), ATK_STATE_VISITED); + return false; } @@ -852,8 +1082,51 @@ bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute) return false; String attributeString = jsStringToWTFString(attribute); - if (attributeString == "AXValue") - return checkElementState(m_element.get(), ATK_STATE_EDITABLE); + if (attributeString != "AXValue") + return false; + + // ATK does not have a single state or property to indicate whether or not the value + // of an accessible object can be set. ATs look at several states and properties based + // on the type of object. If nothing explicitly indicates the value can or cannot be + // set, ATs make role- and interface-based decisions. We'll do something similar here. + + // This state is expected to be present only for text widgets and contenteditable elements. + if (checkElementState(m_element.get(), ATK_STATE_EDITABLE)) + return true; + +#if ATK_CHECK_VERSION(2,11,2) + // This state is applicable to checkboxes, radiobuttons, switches, etc. + if (checkElementState(m_element.get(), ATK_STATE_CHECKABLE)) + return true; +#endif + +#if ATK_CHECK_VERSION(2,15,3) + // This state is expected to be present only for controls and only if explicitly set. + if (checkElementState(m_element.get(), ATK_STATE_READ_ONLY)) + return false; +#endif + + // We expose an object attribute to ATs when there is an author-provided ARIA property + // and also when there is a supported ARIA role but no author-provided value. + String isReadOnly = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, "readonly"); + if (!isReadOnly.isEmpty()) + return isReadOnly == "true" ? false : true; + + // If we have a native listbox or combobox and the value can be set, the options should + // have ATK_STATE_SELECTABLE. + AtkRole role = atk_object_get_role(ATK_OBJECT(m_element.get())); + if (role == ATK_ROLE_LIST_BOX || role == ATK_ROLE_COMBO_BOX) { + if (GRefPtr<AtkObject> child = adoptGRef(atk_object_ref_accessible_child(ATK_OBJECT(m_element.get()), 0))) { + if (atk_object_get_role(ATK_OBJECT(child.get())) == ATK_ROLE_MENU) + child = adoptGRef(atk_object_ref_accessible_child(ATK_OBJECT(child.get()), 0)); + return child && checkElementState(child.get(), ATK_STATE_SELECTABLE); + } + } + + // If we have a native element which exposes a range whose value can be set, it should + // be focusable and have a true range. + if (ATK_IS_VALUE(m_element.get()) && checkElementState(m_element.get(), ATK_STATE_FOCUSABLE)) + return minValue() != maxValue(); return false; } @@ -898,7 +1171,18 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::subrole() JSRetainPtr<JSStringRef> AccessibilityUIElement::roleDescription() { - // FIXME: implement + String roleDescription = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, "roledescription"); + GUniquePtr<gchar> axRoleDescription(g_strdup_printf("AXRoleDescription: %s", roleDescription.utf8().data())); + + return JSStringCreateWithUTF8CString(axRoleDescription.get()); +} + +JSRetainPtr<JSStringRef> AccessibilityUIElement::computedRoleString() +{ + String role = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, "computed-role"); + if (!role.isEmpty()) + return JSStringCreateWithUTF8CString(role.utf8().data()); + return JSStringCreateWithCharacters(0, 0); } @@ -976,15 +1260,15 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::helpText() const AtkRelationSet* relationSet = atk_object_ref_relation_set(ATK_OBJECT(m_element.get())); if (!relationSet) - return nullptr; + return JSStringCreateWithCharacters(0, 0); AtkRelation* relation = atk_relation_set_get_relation_by_type(relationSet, ATK_RELATION_DESCRIBED_BY); if (!relation) - return nullptr; + return JSStringCreateWithCharacters(0, 0); GPtrArray* targetList = atk_relation_get_target(relation); if (!targetList || !targetList->len) - return nullptr; + return JSStringCreateWithCharacters(0, 0); StringBuilder builder; builder.append("AXHelp: "); @@ -1008,8 +1292,12 @@ double AccessibilityUIElement::x() if (!ATK_IS_COMPONENT(m_element.get())) return 0; - int x, y; - atk_component_get_position(ATK_COMPONENT(m_element.get()), &x, &y, ATK_XY_SCREEN); + int x; +#if ATK_CHECK_VERSION(2,11,90) + atk_component_get_extents(ATK_COMPONENT(m_element.get()), &x, nullptr, nullptr, nullptr, ATK_XY_SCREEN); +#else + atk_component_get_position(ATK_COMPONENT(m_element.get()), &x, nullptr, ATK_XY_SCREEN); +#endif return x; } @@ -1018,8 +1306,12 @@ double AccessibilityUIElement::y() if (!ATK_IS_COMPONENT(m_element.get())) return 0; - int x, y; - atk_component_get_position(ATK_COMPONENT(m_element.get()), &x, &y, ATK_XY_SCREEN); + int y; +#if ATK_CHECK_VERSION(2,11,90) + atk_component_get_extents(ATK_COMPONENT(m_element.get()), nullptr, &y, nullptr, nullptr, ATK_XY_SCREEN); +#else + atk_component_get_position(ATK_COMPONENT(m_element.get()), nullptr, &y, ATK_XY_SCREEN); +#endif return y; } @@ -1028,8 +1320,12 @@ double AccessibilityUIElement::width() if (!ATK_IS_COMPONENT(m_element.get())) return 0; - int width, height; - atk_component_get_size(ATK_COMPONENT(m_element.get()), &width, &height); + int width; +#if ATK_CHECK_VERSION(2,11,90) + atk_component_get_extents(ATK_COMPONENT(m_element.get()), nullptr, nullptr, &width, nullptr, ATK_XY_WINDOW); +#else + atk_component_get_size(ATK_COMPONENT(m_element.get()), &width, nullptr); +#endif return width; } @@ -1038,8 +1334,12 @@ double AccessibilityUIElement::height() if (!ATK_IS_COMPONENT(m_element.get())) return 0; - int width, height; - atk_component_get_size(ATK_COMPONENT(m_element.get()), &width, &height); + int height; +#if ATK_CHECK_VERSION(2,11,90) + atk_component_get_extents(ATK_COMPONENT(m_element.get()), nullptr, nullptr, nullptr, &height, ATK_XY_WINDOW); +#else + atk_component_get_size(ATK_COMPONENT(m_element.get()), nullptr, &height); +#endif return height; } @@ -1048,11 +1348,13 @@ double AccessibilityUIElement::clickPointX() if (!ATK_IS_COMPONENT(m_element.get())) return 0; - int x, y; - atk_component_get_position(ATK_COMPONENT(m_element.get()), &x, &y, ATK_XY_WINDOW); - - int width, height; - atk_component_get_size(ATK_COMPONENT(m_element.get()), &width, &height); + int x, width; +#if ATK_CHECK_VERSION(2,11,90) + atk_component_get_extents(ATK_COMPONENT(m_element.get()), &x, nullptr, &width, nullptr, ATK_XY_WINDOW); +#else + atk_component_get_position(ATK_COMPONENT(m_element.get()), &x, nullptr, ATK_XY_WINDOW); + atk_component_get_size(ATK_COMPONENT(m_element.get()), &width, nullptr); +#endif return x + width / 2.0; } @@ -1062,11 +1364,13 @@ double AccessibilityUIElement::clickPointY() if (!ATK_IS_COMPONENT(m_element.get())) return 0; - int x, y; - atk_component_get_position(ATK_COMPONENT(m_element.get()), &x, &y, ATK_XY_WINDOW); - - int width, height; - atk_component_get_size(ATK_COMPONENT(m_element.get()), &width, &height); + int y, height; +#if ATK_CHECK_VERSION(2,11,90) + atk_component_get_extents(ATK_COMPONENT(m_element.get()), nullptr, &y, nullptr, &height, ATK_XY_WINDOW); +#else + atk_component_get_position(ATK_COMPONENT(m_element.get()), nullptr, &y, ATK_XY_WINDOW); + atk_component_get_size(ATK_COMPONENT(m_element.get()), nullptr, &height); +#endif return y + height / 2.0; } @@ -1077,11 +1381,17 @@ double AccessibilityUIElement::intValue() const return 0; if (ATK_IS_VALUE(m_element.get())) { +#if ATK_CHECK_VERSION(2,11,92) + double value; + atk_value_get_value_and_text(ATK_VALUE(m_element.get()), &value, nullptr); + return value; +#else GValue value = G_VALUE_INIT; atk_value_get_current_value(ATK_VALUE(m_element.get()), &value); if (!G_VALUE_HOLDS_FLOAT(&value)) return 0; return g_value_get_float(&value); +#endif } // Consider headings as an special case when returning the "int value" of @@ -1102,13 +1412,16 @@ double AccessibilityUIElement::minValue() { if (!ATK_IS_VALUE(m_element.get())) return 0; - +#if ATK_CHECK_VERSION(2,11,92) + return rangeMinMaxValue(ATK_VALUE(m_element.get()), RangeLimitMinimum); +#else GValue value = G_VALUE_INIT; atk_value_get_minimum_value(ATK_VALUE(m_element.get()), &value); if (!G_VALUE_HOLDS_FLOAT(&value)) return 0; return g_value_get_float(&value); +#endif } double AccessibilityUIElement::maxValue() @@ -1116,18 +1429,23 @@ double AccessibilityUIElement::maxValue() if (!ATK_IS_VALUE(m_element.get())) return 0; +#if ATK_CHECK_VERSION(2,11,92) + return rangeMinMaxValue(ATK_VALUE(m_element.get()), RangeLimitMaximum); +#else GValue value = G_VALUE_INIT; atk_value_get_maximum_value(ATK_VALUE(m_element.get()), &value); if (!G_VALUE_HOLDS_FLOAT(&value)) return 0; return g_value_get_float(&value); +#endif } JSRetainPtr<JSStringRef> AccessibilityUIElement::valueDescription() { - // FIXME: implement - return JSStringCreateWithCharacters(0, 0); + String valueText = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, "valuetext"); + GUniquePtr<gchar> valueDescription(g_strdup_printf("AXValueDescription: %s", valueText.utf8().data())); + return JSStringCreateWithUTF8CString(valueDescription.get()); } int AccessibilityUIElement::insertionPointLineNumber() @@ -1142,7 +1460,7 @@ bool AccessibilityUIElement::isPressActionSupported() return false; const gchar* actionName = atk_action_get_name(ATK_ACTION(m_element.get()), 0); - return equalIgnoringCase(actionName, String("press")) || equalIgnoringCase(actionName, String("jump")); + return equalLettersIgnoringASCIICase(String(actionName), "press") || equalLettersIgnoringASCIICase(String(actionName), "jump"); } bool AccessibilityUIElement::isIncrementActionSupported() @@ -1242,8 +1560,16 @@ int AccessibilityUIElement::lineForIndex(int index) JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForLine(int line) { - // FIXME: implement - return JSStringCreateWithCharacters(0, 0); + if (!ATK_IS_TEXT(m_element.get())) + return JSStringCreateWithCharacters(0, 0); + + AtkText* text = ATK_TEXT(m_element.get()); + gint startOffset = 0, endOffset = 0; + for (int i = 0; i <= line; ++i) + atk_text_get_string_at_offset(text, endOffset, ATK_TEXT_GRANULARITY_LINE, &startOffset, &endOffset); + + GUniquePtr<gchar> range(g_strdup_printf("{%d, %d}", startOffset, endOffset - startOffset)); + return JSStringCreateWithUTF8CString(range.get()); } JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForPosition(int x, int y) @@ -1254,8 +1580,14 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForPosition(int x, int y) JSRetainPtr<JSStringRef> AccessibilityUIElement::boundsForRange(unsigned location, unsigned length) { - // FIXME: implement - return JSStringCreateWithCharacters(0, 0); + if (!ATK_IS_TEXT(m_element.get())) + return JSStringCreateWithCharacters(0, 0); + + AtkTextRectangle rect; + atk_text_get_range_extents(ATK_TEXT(m_element.get()), location, location + length, ATK_XY_WINDOW, &rect); + + GUniquePtr<gchar> bounds(g_strdup_printf("{%d, %d, %d, %d}", rect.x, rect.y, rect.width, rect.height)); + return JSStringCreateWithUTF8CString(bounds.get()); } JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForRange(unsigned location, unsigned length) @@ -1269,8 +1601,29 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForRange(unsigned locatio JSRetainPtr<JSStringRef> AccessibilityUIElement::attributedStringForRange(unsigned location, unsigned length) { - // FIXME: implement - return JSStringCreateWithCharacters(0, 0); + if (!ATK_IS_TEXT(m_element.get())) + return JSStringCreateWithCharacters(0, 0); + + StringBuilder builder; + + // The default text attributes apply to the entire element. + builder.append("\n\tDefault text attributes:\n\t\t"); + builder.append(attributeSetToString(getAttributeSet(m_element.get(), TextAttributeType), "\n\t\t")); + + // The attribute run provides attributes specific to the range of text at the specified offset. + AtkAttributeSet* attributeSet; + AtkText* text = ATK_TEXT(m_element.get()); + gint start = 0, end = 0; + for (int i = location; i < location + length; i = end) { + AtkAttributeSet* attributeSet = atk_text_get_run_attributes(text, i, &start, &end); + GUniquePtr<gchar> substring(replaceCharactersForResults(atk_text_get_text(text, start, end))); + builder.append(String::format("\n\tRange attributes for '%s':\n\t\t", substring.get())); + builder.append(attributeSetToString(attributeSet, "\n\t\t")); + } + + atk_attribute_set_free(attributeSet); + + return JSStringCreateWithUTF8CString(builder.toString().utf8().data()); } bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location, unsigned length) @@ -1279,13 +1632,19 @@ bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location return false; } -unsigned AccessibilityUIElement::uiElementCountForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly) +unsigned AccessibilityUIElement::uiElementCountForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly) { // FIXME: implement return 0; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly) +RefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly) +{ + // FIXME: implement + return nullptr; +} + +JSRetainPtr<JSStringRef> AccessibilityUIElement::selectTextWithCriteria(JSContextRef context, JSStringRef ambiguityResolution, JSValueRef searchStrings, JSStringRef replacementString, JSStringRef activity) { // FIXME: implement return nullptr; @@ -1370,7 +1729,7 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::columnIndexRange() return indexRangeInTable(m_element.get(), false); } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::cellForColumnAndRow(unsigned col, unsigned row) +RefPtr<AccessibilityUIElement> AccessibilityUIElement::cellForColumnAndRow(unsigned col, unsigned row) { if (!ATK_IS_TABLE(m_element.get())) return nullptr; @@ -1378,16 +1737,16 @@ PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::cellForColumnAndRow(u // Adopt the AtkObject representing the cell because // at_table_ref_at() transfers full ownership. GRefPtr<AtkObject> foundCell = adoptGRef(atk_table_ref_at(ATK_TABLE(m_element.get()), row, col)); - return foundCell ? AccessibilityUIElement::create(foundCell.get()) : nullptr; + return foundCell ? AccessibilityUIElement::create(foundCell.get()).ptr() : nullptr; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::horizontalScrollbar() const +RefPtr<AccessibilityUIElement> AccessibilityUIElement::horizontalScrollbar() const { // FIXME: implement return nullptr; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::verticalScrollbar() const +RefPtr<AccessibilityUIElement> AccessibilityUIElement::verticalScrollbar() const { // FIXME: implement return nullptr; @@ -1445,6 +1804,30 @@ void AccessibilityUIElement::setSelectedChild(AccessibilityUIElement* element) c // FIXME: implement } +void AccessibilityUIElement::setSelectedChildAtIndex(unsigned index) const +{ + if (!ATK_IS_SELECTION(m_element.get())) + return; + + atk_selection_add_selection(ATK_SELECTION(m_element.get()), index); +} + +void AccessibilityUIElement::removeSelectionAtIndex(unsigned index) const +{ + if (!ATK_IS_SELECTION(m_element.get())) + return; + + atk_selection_remove_selection(ATK_SELECTION(m_element.get()), index); +} + +void AccessibilityUIElement::clearSelectedChildren() const +{ + if (!ATK_IS_SELECTION(m_element.get())) + return; + + atk_selection_clear_selection(ATK_SELECTION(m_element.get())); +} + JSRetainPtr<JSStringRef> AccessibilityUIElement::accessibilityValue() const { // FIXME: implement @@ -1457,7 +1840,7 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::documentEncoding() return JSStringCreateWithCharacters(0, 0); AtkRole role = atk_object_get_role(ATK_OBJECT(m_element.get())); - if (role != ATK_ROLE_DOCUMENT_FRAME) + if (role != ATK_ROLE_DOCUMENT_WEB) return JSStringCreateWithCharacters(0, 0); return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element.get()), "Encoding")); @@ -1469,7 +1852,7 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::documentURI() return JSStringCreateWithCharacters(0, 0); AtkRole role = atk_object_get_role(ATK_OBJECT(m_element.get())); - if (role != ATK_ROLE_DOCUMENT_FRAME) + if (role != ATK_ROLE_DOCUMENT_WEB) return JSStringCreateWithCharacters(0, 0); return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element.get()), "URI")); @@ -1552,13 +1935,23 @@ bool AccessibilityUIElement::isIgnored() const return false; } +bool AccessibilityUIElement::isSingleLine() const +{ + return checkElementState(m_element.get(), ATK_STATE_SINGLE_LINE); +} + +bool AccessibilityUIElement::isMultiLine() const +{ + return checkElementState(m_element.get(), ATK_STATE_MULTI_LINE); +} + bool AccessibilityUIElement::hasPopup() const { if (!ATK_IS_OBJECT(m_element.get())) return false; String hasPopupValue = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, "haspopup"); - return equalIgnoringCase(hasPopupValue, "true"); + return equalLettersIgnoringASCIICase(hasPopupValue, "true"); } void AccessibilityUIElement::takeFocus() @@ -1582,7 +1975,13 @@ void AccessibilityUIElement::removeSelection() } // Text markers -PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForElement(AccessibilityUIElement* element) +RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::lineTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker) +{ + // FIXME: implement + return nullptr; +} + +RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForElement(AccessibilityUIElement* element) { // FIXME: implement return nullptr; @@ -1594,13 +1993,13 @@ int AccessibilityUIElement::textMarkerRangeLength(AccessibilityTextMarkerRange* return 0; } -PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousTextMarker(AccessibilityTextMarker* textMarker) +RefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousTextMarker(AccessibilityTextMarker* textMarker) { // FIXME: implement return nullptr; } -PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextTextMarker(AccessibilityTextMarker* textMarker) +RefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextTextMarker(AccessibilityTextMarker* textMarker) { // FIXME: implement return nullptr; @@ -1612,43 +2011,43 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForTextMarkerRange(Access return JSStringCreateWithCharacters(0, 0); } -PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker) +RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker) { // FIXME: implement return nullptr; } -PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range) +RefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range) { // FIXME: implement return nullptr; } -PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range) +RefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range) { // FIXME: implement return nullptr; } -PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForBounds(int x, int y, int width, int height) +RefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForBounds(int x, int y, int width, int height) { // FIXME: implement return nullptr; } -PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForBounds(int x, int y, int width, int height) +RefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForBounds(int x, int y, int width, int height) { // FIXME: implement return nullptr; } -PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForPoint(int x, int y) +RefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForPoint(int x, int y) { // FIXME: implement return nullptr; } -PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::accessibilityElementForTextMarker(AccessibilityTextMarker* marker) +RefPtr<AccessibilityUIElement> AccessibilityUIElement::accessibilityElementForTextMarker(AccessibilityTextMarker* marker) { // FIXME: implement return nullptr; @@ -1672,28 +2071,43 @@ bool AccessibilityUIElement::isTextMarkerValid(AccessibilityTextMarker* textMark return false; } -PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForIndex(int textIndex) +RefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForIndex(int textIndex) { // FIXME: implement return nullptr; } -PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarker() +RefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarker() { // FIXME: implement return nullptr; } -PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarker() +RefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarker() { // FIXME: implement return nullptr; } +bool AccessibilityUIElement::setSelectedVisibleTextRange(AccessibilityTextMarkerRange*) +{ + return false; +} + void AccessibilityUIElement::scrollToMakeVisible() { // FIXME: implement } + +void AccessibilityUIElement::scrollToGlobalPoint(int x, int y) +{ + // FIXME: implement +} + +void AccessibilityUIElement::scrollToMakeVisibleWithSubFocus(int x, int y, int width, int height) +{ + // FIXME: implement +} JSRetainPtr<JSStringRef> AccessibilityUIElement::supportedActions() const { diff --git a/Tools/WebKitTestRunner/InjectedBundle/gtk/ActivateFontsGtk.cpp b/Tools/WebKitTestRunner/InjectedBundle/gtk/ActivateFontsGtk.cpp index 7c9dab7b9..496c1bcbf 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/gtk/ActivateFontsGtk.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/gtk/ActivateFontsGtk.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2005, 2006 Apple Inc. All rights reserved. * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) * Copyright (C) 2010 Igalia S.L. * @@ -12,7 +12,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -34,8 +34,8 @@ #include "InjectedBundleUtilities.h" #include <fontconfig/fontconfig.h> #include <gtk/gtk.h> -#include <wtf/gobject/GUniquePtr.h> -#include <wtf/gobject/GlibUtilities.h> +#include <wtf/glib/GLibUtilities.h> +#include <wtf/glib/GUniquePtr.h> namespace WTR { @@ -68,7 +68,7 @@ CString getOutputDir() static CString getFontsPath() { CString webkitOutputDir = getOutputDir(); - GUniquePtr<char> fontsPath(g_build_filename(webkitOutputDir.data(), "Dependencies", "Root", "webkitgtk-test-fonts", nullptr)); + GUniquePtr<char> fontsPath(g_build_filename(webkitOutputDir.data(), "DependenciesGTK", "Root", "webkitgtk-test-fonts", nullptr)); if (g_file_test(fontsPath.get(), static_cast<GFileTest>(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) return fontsPath.get(); diff --git a/Tools/WebKitTestRunner/InjectedBundle/gtk/InjectedBundleUtilities.cpp b/Tools/WebKitTestRunner/InjectedBundle/gtk/InjectedBundleUtilities.cpp index febdaad19..afbd3f74a 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/gtk/InjectedBundleUtilities.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/gtk/InjectedBundleUtilities.cpp @@ -10,7 +10,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -30,8 +30,8 @@ #include "InjectedBundleUtilities.h" #include <gtk/gtk.h> -#include <wtf/gobject/GUniquePtr.h> -#include <wtf/gobject/GlibUtilities.h> +#include <wtf/glib/GLibUtilities.h> +#include <wtf/glib/GUniquePtr.h> namespace WTR { diff --git a/Tools/WebKitTestRunner/InjectedBundle/gtk/InjectedBundleUtilities.h b/Tools/WebKitTestRunner/InjectedBundle/gtk/InjectedBundleUtilities.h index 50f89dead..4062c6d44 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/gtk/InjectedBundleUtilities.h +++ b/Tools/WebKitTestRunner/InjectedBundle/gtk/InjectedBundleUtilities.h @@ -10,7 +10,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * diff --git a/Tools/WebKitTestRunner/InjectedBundle/gtk/TestRunnerGtk.cpp b/Tools/WebKitTestRunner/InjectedBundle/gtk/TestRunnerGtk.cpp index 254374884..a9f7f409c 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/gtk/TestRunnerGtk.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/gtk/TestRunnerGtk.cpp @@ -30,37 +30,25 @@ #include "InjectedBundle.h" #include "InjectedBundleUtilities.h" #include <glib.h> -#include <wtf/gobject/GUniquePtr.h> +#include <wtf/glib/GUniquePtr.h> namespace WTR { -static gboolean waitToDumpWatchdogTimerCallback(gpointer) -{ - InjectedBundle::shared().testRunner()->waitToDumpWatchdogTimerFired(); - return FALSE; -} - void TestRunner::platformInitialize() { - m_waitToDumpWatchdogTimer = 0; } void TestRunner::invalidateWaitToDumpWatchdogTimer() { - if (!m_waitToDumpWatchdogTimer) - return; - g_source_remove(m_waitToDumpWatchdogTimer); - m_waitToDumpWatchdogTimer = 0; + m_waitToDumpWatchdogTimer.stop(); } void TestRunner::initializeWaitToDumpWatchdogTimerIfNeeded() { - if (m_waitToDumpWatchdogTimer) + if (m_waitToDumpWatchdogTimer.isActive()) return; - m_waitToDumpWatchdogTimer = g_timeout_add(waitToDumpWatchdogTimerInterval * 1000, - waitToDumpWatchdogTimerCallback, 0); - g_source_set_name_by_id(m_waitToDumpWatchdogTimer, "[WebKit] waitToDumpWatchdogTimerCallback"); + m_waitToDumpWatchdogTimer.startOneShot(m_timeout / 1000.0); } JSRetainPtr<JSStringRef> TestRunner::pathToLocalResource(JSStringRef url) @@ -78,4 +66,9 @@ JSRetainPtr<JSStringRef> TestRunner::pathToLocalResource(JSStringRef url) return JSStringCreateWithUTF8CString(testURI.get()); } +JSRetainPtr<JSStringRef> TestRunner::inspectorTestStubURL() +{ + return JSStringCreateWithUTF8CString("resource:///org/webkitgtk/inspector/UserInterface/TestStub.html"); +} + } // namespace WTR diff --git a/Tools/WebKitTestRunner/Options.cpp b/Tools/WebKitTestRunner/Options.cpp index 8fa6e6e0f..53f0253ac 100644 --- a/Tools/WebKitTestRunner/Options.cpp +++ b/Tools/WebKitTestRunner/Options.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2013 University of Szeged. All rights reserved. * Copyright (C) 2013 Samsung Electronics. All rights reserved. + * Copyright (C) 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,10 +32,8 @@ namespace WTR { -Options::Options(double defaultLongTimeout, double defaultShortTimeout) - : longTimeout(defaultLongTimeout) - , shortTimeout(defaultShortTimeout) - , useWaitToDumpWatchdogTimer(true) +Options::Options() + : useWaitToDumpWatchdogTimer(true) , forceNoTimeout(false) , verbose(false) , gcBetweenTests(false) @@ -43,28 +42,13 @@ Options::Options(double defaultLongTimeout, double defaultShortTimeout) , forceComplexText(false) , shouldUseAcceleratedDrawing(false) , shouldUseRemoteLayerTree(false) - , defaultLongTimeout(defaultLongTimeout) - , defaultShortTimeout(defaultShortTimeout) + , shouldShowWebView(false) { } -bool handleOptionTimeout(Options& options, const char*, const char* argument) -{ - options.longTimeout = atoi(argument); - // Scale up the short timeout to match. - options.shortTimeout = options.defaultShortTimeout * options.longTimeout / options.defaultLongTimeout; - return true; -} - bool handleOptionNoTimeout(Options& options, const char*, const char*) { options.useWaitToDumpWatchdogTimer = false; - return true; -} - -bool handleOptionNoTimeoutAtAll(Options& options, const char*, const char*) -{ - options.useWaitToDumpWatchdogTimer = false; options.forceNoTimeout = true; return true; } @@ -111,6 +95,18 @@ bool handleOptionRemoteLayerTree(Options& options, const char*, const char*) return true; } +bool handleOptionShowWebView(Options& options, const char*, const char*) +{ + options.shouldShowWebView = true; + return true; +} + +bool handleOptionAllowedHost(Options& options, const char*, const char* host) +{ + options.allowedHosts.push_back(host); + return true; +} + bool handleOptionUnmatched(Options& options, const char* option, const char*) { if (option[0] && option[1] && option[0] == '-' && option[1] == '-') @@ -122,9 +118,7 @@ bool handleOptionUnmatched(Options& options, const char* option, const char*) OptionsHandler::OptionsHandler(Options& o) : options(o) { - optionList.append(Option("--timeout", "Sets long timeout to <param> and scales short timeout.", handleOptionTimeout, true)); - optionList.append(Option("--no-timeout", "Disables timeout.", handleOptionNoTimeout)); - optionList.append(Option("--no-timeout-at-all", "Disables all timeouts.", handleOptionNoTimeoutAtAll)); + optionList.append(Option("--no-timeout", "Disables all timeouts.", handleOptionNoTimeout)); optionList.append(Option("--verbose", "Turns on messages.", handleOptionVerbose)); optionList.append(Option("--gc-between-tests", "Garbage collection between tests.", handleOptionGcBetweenTests)); optionList.append(Option("--pixel-tests", "Check pixels.", handleOptionPixelTests)); @@ -133,6 +127,9 @@ OptionsHandler::OptionsHandler(Options& o) optionList.append(Option("--complex-text", "Force complex tests.", handleOptionComplexText)); optionList.append(Option("--accelerated-drawing", "Use accelerated drawing.", handleOptionAcceleratedDrawing)); optionList.append(Option("--remote-layer-tree", "Use remote layer tree.", handleOptionRemoteLayerTree)); + optionList.append(Option("--allowed-host", "Allows access to the specified host from tests.", handleOptionAllowedHost, true)); + optionList.append(Option("--show-webview", "Show the WebView during test runs (for Debugging)", handleOptionShowWebView)); + optionList.append(Option(0, 0, handleOptionUnmatched)); } diff --git a/Tools/WebKitTestRunner/Options.h b/Tools/WebKitTestRunner/Options.h index a89d25c77..5549fe464 100644 --- a/Tools/WebKitTestRunner/Options.h +++ b/Tools/WebKitTestRunner/Options.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2013 University of Szeged. All rights reserved. * Copyright (C) 2013 Samsung Electronics. All rights reserved. + * Copyright (C) 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -36,9 +37,7 @@ namespace WTR { struct Options { - Options(double, double); - double longTimeout; - double shortTimeout; + Options(); bool useWaitToDumpWatchdogTimer; bool forceNoTimeout; bool verbose; @@ -48,9 +47,9 @@ struct Options { bool forceComplexText; bool shouldUseAcceleratedDrawing; bool shouldUseRemoteLayerTree; + bool shouldShowWebView; std::vector<std::string> paths; - double defaultLongTimeout; - double defaultShortTimeout; + std::vector<std::string> allowedHosts; }; class Option { diff --git a/Tools/WebKitTestRunner/PixelDumpSupport.cpp b/Tools/WebKitTestRunner/PixelDumpSupport.cpp index 76974737f..37b3047cb 100644 --- a/Tools/WebKitTestRunner/PixelDumpSupport.cpp +++ b/Tools/WebKitTestRunner/PixelDumpSupport.cpp @@ -10,7 +10,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * diff --git a/Tools/WebKitTestRunner/PixelDumpSupport.h b/Tools/WebKitTestRunner/PixelDumpSupport.h index 41c6e38ea..324667f10 100644 --- a/Tools/WebKitTestRunner/PixelDumpSupport.h +++ b/Tools/WebKitTestRunner/PixelDumpSupport.h @@ -10,7 +10,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * diff --git a/Tools/WebKitTestRunner/PlatformGTK.cmake b/Tools/WebKitTestRunner/PlatformGTK.cmake new file mode 100644 index 000000000..af53e220d --- /dev/null +++ b/Tools/WebKitTestRunner/PlatformGTK.cmake @@ -0,0 +1,60 @@ +add_custom_target(WebKitTestRunner-forwarding-headers + COMMAND ${PERL_EXECUTABLE} ${WEBKIT2_DIR}/Scripts/generate-forwarding-headers.pl --include-path ${WEBKIT_TESTRUNNER_DIR} --include-path ${WEBKIT_TESTRUNNER_SHARED_DIR} --output ${FORWARDING_HEADERS_DIR} --platform gtk --platform soup +) + +set(ForwardingHeadersForWebKitTestRunner_NAME WebKitTestRunner-forwarding-headers) + +list(APPEND WebKitTestRunner_SOURCES + ${WEBKIT_TESTRUNNER_DIR}/cairo/TestInvocationCairo.cpp + + ${WEBKIT_TESTRUNNER_DIR}/gtk/EventSenderProxyGtk.cpp + ${WEBKIT_TESTRUNNER_DIR}/gtk/PlatformWebViewGtk.cpp + ${WEBKIT_TESTRUNNER_DIR}/gtk/TestControllerGtk.cpp + ${WEBKIT_TESTRUNNER_DIR}/gtk/main.cpp +) + +list(APPEND WebKitTestRunner_INCLUDE_DIRECTORIES + ${FORWARDING_HEADERS_DIR} +) + +list(APPEND WebKitTestRunner_SYSTEM_INCLUDE_DIRECTORIES + ${ATK_INCLUDE_DIRS} + ${CAIRO_INCLUDE_DIRS} + ${GTK3_INCLUDE_DIRS} + ${GLIB_INCLUDE_DIRS} +) + +list(APPEND WebKitTestRunner_LIBRARIES + ${ATK_LIBRARIES} + ${CAIRO_LIBRARIES} + ${GTK3_LIBRARIES} + ${GLIB_LIBRARIES} + WTF + WebCore + WebCorePlatformGTK +) + +set(WebKitTestRunnerInjectedBundle_LIBRARIES + ${ATK_LIBRARIES} + ${FONTCONFIG_LIBRARIES} + ${GLIB_LIBRARIES} + ${GTK3_LIBRARIES} + WebCoreTestSupport + WebKit2 +) + +list(APPEND WebKitTestRunnerInjectedBundle_SOURCES + ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/atk/AccessibilityControllerAtk.cpp + ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/atk/AccessibilityNotificationHandlerAtk.cpp + ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/atk/AccessibilityUIElementAtk.cpp + + ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/gtk/ActivateFontsGtk.cpp + ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/gtk/InjectedBundleGtk.cpp + ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/gtk/InjectedBundleUtilities.cpp + ${WEBKIT_TESTRUNNER_INJECTEDBUNDLE_DIR}/gtk/TestRunnerGtk.cpp +) + +add_definitions( + -DFONTS_CONF_DIR="${TOOLS_DIR}/WebKitTestRunner/gtk/fonts" + -DTOP_LEVEL_DIR="${CMAKE_SOURCE_DIR}" +) diff --git a/Tools/WebKitTestRunner/PlatformWebView.h b/Tools/WebKitTestRunner/PlatformWebView.h index fa8d1236c..aa0ab2e49 100644 --- a/Tools/WebKitTestRunner/PlatformWebView.h +++ b/Tools/WebKitTestRunner/PlatformWebView.h @@ -26,29 +26,28 @@ #ifndef PlatformWebView_h #define PlatformWebView_h -#include <WebKit2/WKRetainPtr.h> +#include "TestOptions.h" +#include <WebKit/WKRetainPtr.h> -#if defined(__APPLE__) && __APPLE__ -#ifdef __OBJC__ -@class WKView; -@class WebKitTestRunnerWindow; +#if PLATFORM(COCOA) && !defined(BUILDING_GTK__) +#include <WebKit/WKFoundation.h> +OBJC_CLASS NSView; +OBJC_CLASS UIView; +OBJC_CLASS TestRunnerWKWebView; +OBJC_CLASS WKWebViewConfiguration; +OBJC_CLASS WebKitTestRunnerWindow; + +#if WK_API_ENABLED +typedef TestRunnerWKWebView *PlatformWKView; #else -class WKView; -class WebKitTestRunnerWindow; +typedef NSView *PlatformWKView; #endif -typedef WKView* PlatformWKView; -typedef WebKitTestRunnerWindow* PlatformWindow; +typedef WebKitTestRunnerWindow *PlatformWindow; #elif defined(BUILDING_GTK__) typedef struct _GtkWidget GtkWidget; typedef WKViewRef PlatformWKView; typedef GtkWidget* PlatformWindow; #elif PLATFORM(EFL) -typedef struct _Ecore_Evas Ecore_Evas; -#if USE(EO) -typedef struct _Eo_Opaque Evas_Object; -#else -typedef struct _Evas_Object Evas_Object; -#endif typedef Evas_Object* PlatformWKView; typedef Ecore_Evas* PlatformWindow; #endif @@ -57,43 +56,60 @@ namespace WTR { class PlatformWebView { public: - PlatformWebView(WKContextRef, WKPageGroupRef, WKPageRef relatedPage, WKDictionaryRef options = 0); +#if PLATFORM(COCOA) + PlatformWebView(WKWebViewConfiguration*, const TestOptions&); +#else + PlatformWebView(WKPageConfigurationRef, const TestOptions&); +#endif ~PlatformWebView(); WKPageRef page(); PlatformWKView platformView() { return m_view; } PlatformWindow platformWindow() { return m_window; } - void resizeTo(unsigned width, unsigned height); - void focus(); + static PlatformWindow keyWindow(); - // Window snapshot is always enabled by default on all other platform. - static bool windowSnapshotEnabled() { return true; } + enum class WebViewSizingMode { + Default, + HeightRespectsStatusBar + }; + + void resizeTo(unsigned width, unsigned height, WebViewSizingMode = WebViewSizingMode::Default); + void focus(); WKRect windowFrame(); - void setWindowFrame(WKRect); + void setWindowFrame(WKRect, WebViewSizingMode = WebViewSizingMode::Default); void didInitializeClients(); void addChromeInputField(); void removeChromeInputField(); void makeWebViewFirstResponder(); - void setWindowIsKey(bool isKey) { m_windowIsKey = isKey; } + void setWindowIsKey(bool); bool windowIsKey() const { return m_windowIsKey; } + + void removeFromWindow(); + void addToWindow(); -#if PLATFORM(MAC) || PLATFORM(EFL) - bool viewSupportsOptions(WKDictionaryRef) const; -#else - bool viewSupportsOptions(WKDictionaryRef) const { return true; } -#endif + bool viewSupportsOptions(const TestOptions&) const; WKRetainPtr<WKImageRef> windowSnapshotImage(); - WKDictionaryRef options() const { return m_options.get(); } + const TestOptions& options() const { return m_options; } + + void changeWindowScaleIfNeeded(float newScale); + void setNavigationGesturesEnabled(bool); + +#if PLATFORM(GTK) + void dismissAllPopupMenus(); +#endif private: + void forceWindowFramesChanged(); + PlatformWKView m_view; PlatformWindow m_window; bool m_windowIsKey; - WKRetainPtr<WKDictionaryRef> m_options; + const TestOptions m_options; + #if PLATFORM(EFL) bool m_usingFixedLayout; #endif diff --git a/Tools/WebKitTestRunner/StringFunctions.h b/Tools/WebKitTestRunner/StringFunctions.h index 551d86740..752731cbf 100644 --- a/Tools/WebKitTestRunner/StringFunctions.h +++ b/Tools/WebKitTestRunner/StringFunctions.h @@ -29,12 +29,12 @@ #include <JavaScriptCore/JSRetainPtr.h> #include <JavaScriptCore/JavaScript.h> +#include <WebKit/WKRetainPtr.h> +#include <WebKit/WKString.h> +#include <WebKit/WKStringPrivate.h> +#include <WebKit/WKURL.h> #include <sstream> #include <string> -#include <WebKit2/WKRetainPtr.h> -#include <WebKit2/WKString.h> -#include <WebKit2/WKStringPrivate.h> -#include <WebKit2/WKURL.h> #include <wtf/Platform.h> #include <wtf/StdLibExtras.h> #include <wtf/Vector.h> @@ -87,7 +87,7 @@ inline WTF::String toWTFString(WKStringRef string) { size_t bufferSize = WKStringGetMaximumUTF8CStringSize(string); auto buffer = std::make_unique<char[]>(bufferSize); - size_t stringLength = WKStringGetUTF8CString(string, buffer.get(), bufferSize); + size_t stringLength = WKStringGetUTF8CStringNonStrict(string, buffer.get(), bufferSize); return WTF::String::fromUTF8WithLatin1Fallback(buffer.get(), stringLength - 1); } diff --git a/Tools/WebKitTestRunner/TestController.cpp b/Tools/WebKitTestRunner/TestController.cpp index 397815e63..df5392e74 100644 --- a/Tools/WebKitTestRunner/TestController.cpp +++ b/Tools/WebKitTestRunner/TestController.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010, 2014-2017 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,33 +31,55 @@ #include "PlatformWebView.h" #include "StringFunctions.h" #include "TestInvocation.h" -#include <WebKit2/WKAuthenticationChallenge.h> -#include <WebKit2/WKAuthenticationDecisionListener.h> -#include <WebKit2/WKContextPrivate.h> -#include <WebKit2/WKCredential.h> -#include <WebKit2/WKIconDatabase.h> -#include <WebKit2/WKNotification.h> -#include <WebKit2/WKNotificationManager.h> -#include <WebKit2/WKNotificationPermissionRequest.h> -#include <WebKit2/WKNumber.h> -#include <WebKit2/WKPageGroup.h> -#include <WebKit2/WKPagePrivate.h> -#include <WebKit2/WKPreferencesPrivate.h> -#include <WebKit2/WKRetainPtr.h> +#include "WebCoreTestSupport.h" +#include <WebCore/UUID.h> +#include <WebKit/WKArray.h> +#include <WebKit/WKAuthenticationChallenge.h> +#include <WebKit/WKAuthenticationDecisionListener.h> +#include <WebKit/WKContextConfigurationRef.h> +#include <WebKit/WKContextPrivate.h> +#include <WebKit/WKCookieManager.h> +#include <WebKit/WKCredential.h> +#include <WebKit/WKFrameHandleRef.h> +#include <WebKit/WKFrameInfoRef.h> +#include <WebKit/WKIconDatabase.h> +#include <WebKit/WKNavigationResponseRef.h> +#include <WebKit/WKNotification.h> +#include <WebKit/WKNotificationManager.h> +#include <WebKit/WKNotificationPermissionRequest.h> +#include <WebKit/WKNumber.h> +#include <WebKit/WKOpenPanelResultListener.h> +#include <WebKit/WKPageGroup.h> +#include <WebKit/WKPageInjectedBundleClient.h> +#include <WebKit/WKPagePrivate.h> +#include <WebKit/WKPluginInformation.h> +#include <WebKit/WKPreferencesRefPrivate.h> +#include <WebKit/WKProtectionSpace.h> +#include <WebKit/WKResourceLoadStatisticsManager.h> +#include <WebKit/WKRetainPtr.h> +#include <WebKit/WKSecurityOriginRef.h> +#include <WebKit/WKTextChecker.h> +#include <WebKit/WKUserMediaPermissionCheck.h> #include <algorithm> #include <cstdio> #include <ctype.h> +#include <fstream> +#include <runtime/InitializeThreading.h> #include <stdlib.h> #include <string> -#include <wtf/PassOwnPtr.h> +#include <unistd.h> +#include <wtf/CryptographicallyRandomNumber.h> +#include <wtf/HexNumber.h> +#include <wtf/MainThread.h> +#include <wtf/RefCounted.h> +#include <wtf/RunLoop.h> +#include <wtf/SetForScope.h> #include <wtf/text/CString.h> +#include <wtf/text/WTFString.h> -#if PLATFORM(MAC) -#include <WebKit2/WKPagePrivateMac.h> -#endif - -#if !PLATFORM(MAC) -#include <WebKit2/WKTextChecker.h> +#if PLATFORM(COCOA) +#include <WebKit/WKContextPrivateMac.h> +#include <WebKit/WKPagePrivateMac.h> #endif namespace WTR { @@ -68,12 +90,9 @@ const unsigned TestController::viewHeight = 600; const unsigned TestController::w3cSVGViewWidth = 480; const unsigned TestController::w3cSVGViewHeight = 360; -// defaultLongTimeout + defaultShortTimeout should be less than 80, -// the default timeout value of the test harness so we can detect an -// unresponsive web process. -static const double defaultLongTimeout = 60; -static const double defaultShortTimeout = 15; -static const double defaultNoTimeout = -1; +const double TestController::defaultShortTimeout = 5.0; + +const double TestController::noTimeout = -1; static WKURLRef blankURL() { @@ -81,40 +100,21 @@ static WKURLRef blankURL() return staticBlankURL; } +static WKDataRef copyWebCryptoMasterKey(WKPageRef, const void*) +{ + // Any 128 bit key would do, all we need for testing is to implement the callback. + return WKDataCreate((const uint8_t*)"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 16); +} + static TestController* controller; -TestController& TestController::shared() +TestController& TestController::singleton() { ASSERT(controller); return *controller; } TestController::TestController(int argc, const char* argv[]) - : m_verbose(false) - , m_printSeparators(false) - , m_usingServerMode(false) - , m_gcBetweenTests(false) - , m_shouldDumpPixelsForAllTests(false) - , m_state(Initial) - , m_doneResetting(false) - , m_longTimeout(defaultLongTimeout) - , m_shortTimeout(defaultShortTimeout) - , m_noTimeout(defaultNoTimeout) - , m_useWaitToDumpWatchdogTimer(true) - , m_forceNoTimeout(false) - , m_timeout(0) - , m_didPrintWebProcessCrashedMessage(false) - , m_shouldExitWhenWebProcessCrashes(true) - , m_beforeUnloadReturnValue(true) - , m_isGeolocationPermissionSet(false) - , m_isGeolocationPermissionAllowed(false) - , m_policyDelegateEnabled(false) - , m_policyDelegatePermissive(false) - , m_handlesAuthenticationChallenges(false) - , m_shouldBlockAllPlugins(false) - , m_forceComplexText(false) - , m_shouldUseAcceleratedDrawing(false) - , m_shouldUseRemoteLayerTree(false) { initialize(argc, argv); controller = this; @@ -124,7 +124,9 @@ TestController::TestController(int argc, const char* argv[]) TestController::~TestController() { - WKIconDatabaseClose(WKContextGetIconDatabase(m_context.get())); + // The context will be null if WebKitTestRunner was in server mode, but ran no tests. + if (m_context) + WKIconDatabaseClose(WKContextGetIconDatabase(m_context.get())); platformDestroy(); } @@ -144,7 +146,13 @@ static void setWindowFrame(WKPageRef page, WKRect frame, const void* clientInfo) static bool runBeforeUnloadConfirmPanel(WKPageRef page, WKStringRef message, WKFrameRef frame, const void*) { printf("CONFIRM NAVIGATION: %s\n", toSTD(message).c_str()); - return TestController::shared().beforeUnloadReturnValue(); + return TestController::singleton().beforeUnloadReturnValue(); +} + +static void runOpenPanel(WKPageRef page, WKFrameRef frame, WKOpenPanelParametersRef parameters, WKOpenPanelResultListenerRef resultListenerRef, const void*) +{ + printf("OPEN FILE PANEL\n"); + WKOpenPanelResultListenerCancel(resultListenerRef); } void TestController::runModal(WKPageRef page, const void* clientInfo) @@ -177,34 +185,44 @@ static void unfocus(WKPageRef page, const void* clientInfo) static void decidePolicyForGeolocationPermissionRequest(WKPageRef, WKFrameRef, WKSecurityOriginRef, WKGeolocationPermissionRequestRef permissionRequest, const void* clientInfo) { - TestController::shared().handleGeolocationPermissionRequest(permissionRequest); + TestController::singleton().handleGeolocationPermissionRequest(permissionRequest); } -int TestController::getCustomTimeout() +static void decidePolicyForUserMediaPermissionRequest(WKPageRef, WKFrameRef frame, WKSecurityOriginRef userMediaDocumentOrigin, WKSecurityOriginRef topLevelDocumentOrigin, WKUserMediaPermissionRequestRef permissionRequest, const void* clientInfo) { - return m_timeout; + TestController::singleton().handleUserMediaPermissionRequest(frame, userMediaDocumentOrigin, topLevelDocumentOrigin, permissionRequest); } -WKPageRef TestController::createOtherPage(WKPageRef oldPage, WKURLRequestRef, WKDictionaryRef, WKEventModifiers, WKEventMouseButton, const void* clientInfo) +static void checkUserMediaPermissionForOrigin(WKPageRef, WKFrameRef frame, WKSecurityOriginRef userMediaDocumentOrigin, WKSecurityOriginRef topLevelDocumentOrigin, WKUserMediaPermissionCheckRef checkRequest, const void*) +{ + TestController::singleton().handleCheckOfUserMediaPermissionForOrigin(frame, userMediaDocumentOrigin, topLevelDocumentOrigin, checkRequest); +} + +static void requestPointerLock(WKPageRef page, const void*) +{ + WKPageDidAllowPointerLock(page); +} + +WKPageRef TestController::createOtherPage(WKPageRef oldPage, WKPageConfigurationRef configuration, WKNavigationActionRef navigationAction, WKWindowFeaturesRef windowFeatures, const void *clientInfo) { PlatformWebView* parentView = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo)); - PlatformWebView* view = new PlatformWebView(WKPageGetContext(oldPage), WKPageGetPageGroup(oldPage), oldPage, parentView->options()); + PlatformWebView* view = platformCreateOtherPage(parentView, configuration, parentView->options()); WKPageRef newPage = view->page(); view->resizeTo(800, 600); - WKPageUIClientV2 otherPageUIClient = { - { 2, view }, + WKPageUIClientV8 otherPageUIClient = { + { 8, view }, 0, // createNewPage_deprecatedForUseWithV0 0, // showPage closeOtherPage, 0, // takeFocus focus, unfocus, - 0, // runJavaScriptAlert - 0, // runJavaScriptConfirm - 0, // runJavaScriptPrompt + 0, // runJavaScriptAlert_deprecatedForUseWithV0 + 0, // runJavaScriptAlert_deprecatedForUseWithV0 + 0, // runJavaScriptAlert_deprecatedForUseWithV0 0, // setStatusText 0, // mouseDidMoveOverElement_deprecatedForUseWithV0 0, // missingPluginButtonClicked @@ -224,7 +242,7 @@ WKPageRef TestController::createOtherPage(WKPageRef oldPage, WKURLRequestRef, WK 0, // didDraw 0, // pageDidScroll 0, // exceededDatabaseQuota - 0, // runOpenPanel + runOpenPanel, decidePolicyForGeolocationPermissionRequest, 0, // headerHeight 0, // footerHeight @@ -235,18 +253,66 @@ WKPageRef TestController::createOtherPage(WKPageRef oldPage, WKURLRequestRef, WK 0, // didCompleteRubberBandForMainFrame 0, // saveDataToFileInDownloadsFolder 0, // shouldInterruptJavaScript - createOtherPage, + 0, // createNewPage_deprecatedForUseWithV1 0, // mouseDidMoveOverElement 0, // decidePolicyForNotificationPermissionRequest 0, // unavailablePluginButtonClicked_deprecatedForUseWithV1 0, // showColorPicker 0, // hideColorPicker 0, // unavailablePluginButtonClicked + 0, // pinnedStateDidChange + 0, // didBeginTrackingPotentialLongMousePress + 0, // didRecognizeLongMousePress + 0, // didCancelTrackingPotentialLongMousePress + 0, // isPlayingAudioDidChange + decidePolicyForUserMediaPermissionRequest, + 0, // didClickAutofillButton + 0, // runJavaScriptAlert + 0, // runJavaScriptConfirm + 0, // runJavaScriptPrompt + 0, // mediaSessionMetadataDidChange + createOtherPage, + 0, // runJavaScriptAlert + 0, // runJavaScriptConfirm + 0, // runJavaScriptPrompt + checkUserMediaPermissionForOrigin, + 0, // runBeforeUnloadConfirmPanel + 0, // fullscreenMayReturnToInline + requestPointerLock, + 0, }; WKPageSetPageUIClient(newPage, &otherPageUIClient.base); + + WKPageNavigationClientV0 pageNavigationClient = { + { 0, &TestController::singleton() }, + decidePolicyForNavigationAction, + decidePolicyForNavigationResponse, + decidePolicyForPluginLoad, + 0, // didStartProvisionalNavigation + 0, // didReceiveServerRedirectForProvisionalNavigation + 0, // didFailProvisionalNavigation + 0, // didCommitNavigation + 0, // didFinishNavigation + 0, // didFailNavigation + 0, // didFailProvisionalLoadInSubframe + 0, // didFinishDocumentLoad + 0, // didSameDocumentNavigation + 0, // renderingProgressDidChange + canAuthenticateAgainstProtectionSpace, + didReceiveAuthenticationChallenge, + processDidCrash, + copyWebCryptoMasterKey, + didBeginNavigationGesture, + willEndNavigationGesture, + didEndNavigationGesture, + didRemoveNavigationGestureSnapshot + }; + WKPageSetPageNavigationClient(newPage, &pageNavigationClient.base); view->didInitializeClients(); + TestController::singleton().updateWindowScaleForTest(view, *TestController::singleton().m_currentInvocation); + WKRetain(newPage); return newPage; } @@ -262,12 +328,14 @@ const char* TestController::libraryPathForTesting() return platformLibraryPathForTesting(); } - void TestController::initialize(int argc, const char* argv[]) { + JSC::initializeThreading(); + RunLoop::initializeMainRunLoop(); + platformInitialize(); - Options options(defaultLongTimeout, defaultShortTimeout); + Options options; OptionsHandler optionsHandler(options); if (argc < 2) { @@ -277,8 +345,6 @@ void TestController::initialize(int argc, const char* argv[]) if (!optionsHandler.parse(argc, argv)) exit(1); - m_longTimeout = options.longTimeout; - m_shortTimeout = options.shortTimeout; m_useWaitToDumpWatchdogTimer = options.useWaitToDumpWatchdogTimer; m_forceNoTimeout = options.forceNoTimeout; m_verbose = options.verbose; @@ -288,6 +354,8 @@ void TestController::initialize(int argc, const char* argv[]) m_shouldUseAcceleratedDrawing = options.shouldUseAcceleratedDrawing; m_shouldUseRemoteLayerTree = options.shouldUseRemoteLayerTree; m_paths = options.paths; + m_allowedHosts = options.allowedHosts; + m_shouldShowWebView = options.shouldShowWebView; if (options.printSupportedFeatures) { // FIXME: On Windows, DumpRenderTree uses this to expose whether it supports 3d @@ -305,32 +373,50 @@ void TestController::initialize(int argc, const char* argv[]) initializeInjectedBundlePath(); initializeTestPluginDirectory(); +#if PLATFORM(MAC) + WebCoreTestSupport::installMockGamepadProvider(); +#endif WKRetainPtr<WKStringRef> pageGroupIdentifier(AdoptWK, WKStringCreateWithUTF8CString("WebKitTestRunnerPageGroup")); m_pageGroup.adopt(WKPageGroupCreateWithIdentifier(pageGroupIdentifier.get())); +} - m_context.adopt(WKContextCreateWithInjectedBundlePath(injectedBundlePath())); - m_geolocationProvider = adoptPtr(new GeolocationProviderMock(m_context.get())); - -#if PLATFORM(IOS) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED > 1080) - WKContextSetUsesNetworkProcess(m_context.get(), true); - WKContextSetProcessModel(m_context.get(), kWKProcessModelMultipleSecondaryProcesses); -#endif +WKRetainPtr<WKContextConfigurationRef> TestController::generateContextConfiguration() const +{ + auto configuration = adoptWK(WKContextConfigurationCreate()); + WKContextConfigurationSetInjectedBundlePath(configuration.get(), injectedBundlePath()); + WKContextConfigurationSetFullySynchronousModeIsAllowedForTesting(configuration.get(), true); if (const char* dumpRenderTreeTemp = libraryPathForTesting()) { String temporaryFolder = String::fromUTF8(dumpRenderTreeTemp); - // WebCore::pathByAppendingComponent is not used here because of the namespace, - // which leads us to this ugly #ifdef and file path concatenation. const char separator = '/'; - WKContextSetApplicationCacheDirectory(m_context.get(), toWK(temporaryFolder + separator + "ApplicationCache").get()); - WKContextSetDatabaseDirectory(m_context.get(), toWK(temporaryFolder + separator + "Databases").get()); - WKContextSetLocalStorageDirectory(m_context.get(), toWK(temporaryFolder + separator + "LocalStorage").get()); - WKContextSetDiskCacheDirectory(m_context.get(), toWK(temporaryFolder + separator + "Cache").get()); - WKContextSetCookieStorageDirectory(m_context.get(), toWK(temporaryFolder + separator + "Cookies").get()); - WKContextSetIconDatabasePath(m_context.get(), toWK(temporaryFolder + separator + "IconDatabase" + separator + "WebpageIcons.db").get()); + WKContextConfigurationSetApplicationCacheDirectory(configuration.get(), toWK(temporaryFolder + separator + "ApplicationCache").get()); + WKContextConfigurationSetDiskCacheDirectory(configuration.get(), toWK(temporaryFolder + separator + "Cache").get()); + WKContextConfigurationSetIndexedDBDatabaseDirectory(configuration.get(), toWK(temporaryFolder + separator + "Databases" + separator + "IndexedDB").get()); + WKContextConfigurationSetLocalStorageDirectory(configuration.get(), toWK(temporaryFolder + separator + "LocalStorage").get()); + WKContextConfigurationSetWebSQLDatabaseDirectory(configuration.get(), toWK(temporaryFolder + separator + "Databases" + separator + "WebSQL").get()); + WKContextConfigurationSetMediaKeysStorageDirectory(configuration.get(), toWK(temporaryFolder + separator + "MediaKeys").get()); + } + return configuration; +} + +WKRetainPtr<WKPageConfigurationRef> TestController::generatePageConfiguration(WKContextConfigurationRef configuration) +{ + m_context = platformAdjustContext(adoptWK(WKContextCreateWithConfiguration(configuration)).get(), configuration); + + m_geolocationProvider = std::make_unique<GeolocationProviderMock>(m_context.get()); + + if (const char* dumpRenderTreeTemp = libraryPathForTesting()) { + String temporaryFolder = String::fromUTF8(dumpRenderTreeTemp); + + // FIXME: This should be migrated to WKContextConfigurationRef. + // Disable icon database to avoid fetching <http://127.0.0.1:8000/favicon.ico> and making tests flaky. + // Invividual tests can enable it using testRunner.setIconDatabaseEnabled, although it's not currently supported in WebKitTestRunner. + WKContextSetIconDatabasePath(m_context.get(), toWK(emptyString()).get()); } + WKContextSetDiskCacheSpeculativeValidationEnabled(m_context.get(), true); WKContextUseTestingNetworkSession(m_context.get()); WKContextSetCacheModel(m_context.get(), kWKCacheModelDocumentBrowser); @@ -340,10 +426,30 @@ void TestController::initialize(int argc, const char* argv[]) { 1, this }, didReceiveMessageFromInjectedBundle, didReceiveSynchronousMessageFromInjectedBundle, - 0 // getInjectedBundleInitializationUserData + getInjectedBundleInitializationUserData, }; WKContextSetInjectedBundleClient(m_context.get(), &injectedBundleClient.base); + WKContextClientV2 contextClient = { + { 2, this }, + 0, // plugInAutoStartOriginHashesChanged + networkProcessDidCrash, + 0, // plugInInformationBecameAvailable + 0, // copyWebCryptoMasterKey + databaseProcessDidCrash, + }; + WKContextSetClient(m_context.get(), &contextClient.base); + + WKContextHistoryClientV0 historyClient = { + { 0, this }, + didNavigateWithNavigationData, + didPerformClientRedirect, + didPerformServerRedirect, + didUpdateHistoryTitle, + 0, // populateVisitedLinks + }; + WKContextSetHistoryClient(m_context.get(), &historyClient.base); + WKNotificationManagerRef notificationManager = WKContextGetNotificationManager(m_context.get()); WKNotificationProviderV0 notificationKit = m_webNotificationProvider.provider(); WKNotificationManagerSetProvider(notificationManager, ¬ificationKit.base); @@ -354,34 +460,40 @@ void TestController::initialize(int argc, const char* argv[]) if (m_forceComplexText) WKContextSetAlwaysUsesComplexTextCodePath(m_context.get(), true); - // Some preferences (notably mock scroll bars setting) currently cannot be re-applied to an existing view, so we need to set them now. - resetPreferencesToConsistentValues(); - - WKRetainPtr<WKMutableDictionaryRef> viewOptions; - if (m_shouldUseRemoteLayerTree) { - viewOptions = adoptWK(WKMutableDictionaryCreate()); - WKRetainPtr<WKStringRef> useRemoteLayerTreeKey = adoptWK(WKStringCreateWithUTF8CString("RemoteLayerTree")); - WKRetainPtr<WKBooleanRef> useRemoteLayerTreeValue = adoptWK(WKBooleanCreate(m_shouldUseRemoteLayerTree)); - WKDictionarySetItem(viewOptions.get(), useRemoteLayerTreeKey.get(), useRemoteLayerTreeValue.get()); - } - - createWebViewWithOptions(viewOptions.get()); + auto pageConfiguration = adoptWK(WKPageConfigurationCreate()); + WKPageConfigurationSetContext(pageConfiguration.get(), m_context.get()); + WKPageConfigurationSetPageGroup(pageConfiguration.get(), m_pageGroup.get()); + WKPageConfigurationSetUserContentController(pageConfiguration.get(), adoptWK(WKUserContentControllerCreate()).get()); + return pageConfiguration; } -void TestController::createWebViewWithOptions(WKDictionaryRef options) +void TestController::createWebViewWithOptions(const TestOptions& options) { - m_mainWebView = adoptPtr(new PlatformWebView(m_context.get(), m_pageGroup.get(), 0, options)); - WKPageUIClientV2 pageUIClient = { - { 2, m_mainWebView.get() }, + auto contextConfiguration = generateContextConfiguration(); + + WKRetainPtr<WKMutableArrayRef> overrideLanguages = adoptWK(WKMutableArrayCreate()); + for (auto& language : options.overrideLanguages) + WKArrayAppendItem(overrideLanguages.get(), adoptWK(WKStringCreateWithUTF8CString(language.utf8().data())).get()); + WKContextConfigurationSetOverrideLanguages(contextConfiguration.get(), overrideLanguages.get()); + + auto configuration = generatePageConfiguration(contextConfiguration.get()); + + // Some preferences (notably mock scroll bars setting) currently cannot be re-applied to an existing view, so we need to set them now. + // FIXME: Migrate these preferences to WKContextConfigurationRef. + resetPreferencesToConsistentValues(options); + + platformCreateWebView(configuration.get(), options); + WKPageUIClientV8 pageUIClient = { + { 8, m_mainWebView.get() }, 0, // createNewPage_deprecatedForUseWithV0 0, // showPage 0, // close 0, // takeFocus focus, unfocus, - 0, // runJavaScriptAlert - 0, // runJavaScriptConfirm - 0, // runJavaScriptPrompt + 0, // runJavaScriptAlert_deprecatedForUseWithV0 + 0, // runJavaScriptAlert_deprecatedForUseWithV0 + 0, // runJavaScriptAlert_deprecatedForUseWithV0 0, // setStatusText 0, // mouseDidMoveOverElement_deprecatedForUseWithV0 0, // missingPluginButtonClicked @@ -401,7 +513,7 @@ void TestController::createWebViewWithOptions(WKDictionaryRef options) 0, // didDraw 0, // pageDidScroll 0, // exceededDatabaseQuota, - 0, // runOpenPanel + runOpenPanel, decidePolicyForGeolocationPermissionRequest, 0, // headerHeight 0, // footerHeight @@ -412,98 +524,128 @@ void TestController::createWebViewWithOptions(WKDictionaryRef options) 0, // didCompleteRubberBandForMainFrame 0, // saveDataToFileInDownloadsFolder 0, // shouldInterruptJavaScript - createOtherPage, + 0, // createNewPage_deprecatedForUseWithV1 0, // mouseDidMoveOverElement decidePolicyForNotificationPermissionRequest, // decidePolicyForNotificationPermissionRequest 0, // unavailablePluginButtonClicked_deprecatedForUseWithV1 0, // showColorPicker 0, // hideColorPicker unavailablePluginButtonClicked, + 0, // pinnedStateDidChange + 0, // didBeginTrackingPotentialLongMousePress + 0, // didRecognizeLongMousePress + 0, // didCancelTrackingPotentialLongMousePress + 0, // isPlayingAudioDidChange + decidePolicyForUserMediaPermissionRequest, + 0, // didClickAutofillButton + 0, // runJavaScriptAlert + 0, // runJavaScriptConfirm + 0, // runJavaScriptPrompt + 0, // mediaSessionMetadataDidChange + createOtherPage, + 0, // runJavaScriptAlert + 0, // runJavaScriptConfirm + 0, // runJavaScriptPrompt + checkUserMediaPermissionForOrigin, + 0, // runBeforeUnloadConfirmPanel + 0, // fullscreenMayReturnToInline + requestPointerLock, + 0, }; WKPageSetPageUIClient(m_mainWebView->page(), &pageUIClient.base); - WKPageLoaderClientV4 pageLoaderClient = { - { 4, this }, - 0, // didStartProvisionalLoadForFrame - 0, // didReceiveServerRedirectForProvisionalLoadForFrame - 0, // didFailProvisionalLoadWithErrorForFrame - didCommitLoadForFrame, - 0, // didFinishDocumentLoadForFrame - didFinishLoadForFrame, - 0, // didFailLoadWithErrorForFrame - 0, // didSameDocumentNavigationForFrame - 0, // didReceiveTitleForFrame - 0, // didFirstLayoutForFrame - 0, // didFirstVisuallyNonEmptyLayoutForFrame - 0, // didRemoveFrameFromHierarchy - 0, // didFailToInitializePlugin - 0, // didDisplayInsecureContentForFrame - 0, // canAuthenticateAgainstProtectionSpaceInFrame - didReceiveAuthenticationChallengeInFrame, // didReceiveAuthenticationChallengeInFrame - 0, // didStartProgress - 0, // didChangeProgress - 0, // didFinishProgress - 0, // didBecomeUnresponsive - 0, // didBecomeResponsive + WKPageNavigationClientV0 pageNavigationClient = { + { 0, this }, + decidePolicyForNavigationAction, + decidePolicyForNavigationResponse, + decidePolicyForPluginLoad, + 0, // didStartProvisionalNavigation + 0, // didReceiveServerRedirectForProvisionalNavigation + 0, // didFailProvisionalNavigation + didCommitNavigation, + didFinishNavigation, + 0, // didFailNavigation + 0, // didFailProvisionalLoadInSubframe + 0, // didFinishDocumentLoad + 0, // didSameDocumentNavigation + 0, // renderingProgressDidChange + canAuthenticateAgainstProtectionSpace, + didReceiveAuthenticationChallenge, processDidCrash, - 0, // didChangeBackForwardList - 0, // shouldGoToBackForwardListItem - 0, // didRunInsecureContentForFrame - 0, // didDetectXSSForFrame - 0, // didNewFirstVisuallyNonEmptyLayout_unavailable - 0, // willGoToBackForwardListItem - 0, // interactionOccurredWhileProcessUnresponsive - 0, // pluginDidFail_deprecatedForUseWithV1 - 0, // didReceiveIntentForFrame - 0, // registerIntentServiceForFrame - 0, // didLayout - 0, // pluginLoadPolicy_deprecatedForUseWithV2 - 0, // pluginDidFail - pluginLoadPolicy, // pluginLoadPolicy - 0, // webGLLoadPolicy + copyWebCryptoMasterKey, + didBeginNavigationGesture, + willEndNavigationGesture, + didEndNavigationGesture, + didRemoveNavigationGestureSnapshot }; - WKPageSetPageLoaderClient(m_mainWebView->page(), &pageLoaderClient.base); - - WKPagePolicyClientV1 pagePolicyClient = { - { 1, this }, - 0, // decidePolicyForNavigationAction_deprecatedForUseWithV0 - 0, // decidePolicyForNewWindowAction - 0, // decidePolicyForResponse_deprecatedForUseWithV0 - 0, // unableToImplementPolicy - decidePolicyForNavigationAction, - decidePolicyForResponse, + WKPageSetPageNavigationClient(m_mainWebView->page(), &pageNavigationClient.base); + + WKContextDownloadClientV0 downloadClient = { + { 0, this }, + downloadDidStart, + 0, // didReceiveAuthenticationChallenge + 0, // didReceiveResponse + 0, // didReceiveData + 0, // shouldDecodeSourceDataOfMIMEType + decideDestinationWithSuggestedFilename, + 0, // didCreateDestination + downloadDidFinish, + downloadDidFail, + downloadDidCancel, + 0 // processDidCrash; + }; + WKContextSetDownloadClient(context(), &downloadClient.base); + + // this should just be done on the page? + WKPageInjectedBundleClientV0 injectedBundleClient = { + { 0, this }, + didReceivePageMessageFromInjectedBundle, + didReceiveSynchronousPageMessageFromInjectedBundle }; - WKPageSetPagePolicyClient(m_mainWebView->page(), &pagePolicyClient.base); + WKPageSetPageInjectedBundleClient(m_mainWebView->page(), &injectedBundleClient.base); m_mainWebView->didInitializeClients(); + + // Generally, the tests should default to running at 1x. updateWindowScaleForTest() will adjust the scale to + // something else for specific tests that need to run at a different window scale. + m_mainWebView->changeWindowScaleIfNeeded(1); } -void TestController::ensureViewSupportsOptions(WKDictionaryRef options) +void TestController::ensureViewSupportsOptionsForTest(const TestInvocation& test) { - if (m_mainWebView && !m_mainWebView->viewSupportsOptions(options)) { - WKPageSetPageUIClient(m_mainWebView->page(), 0); - WKPageSetPageLoaderClient(m_mainWebView->page(), 0); - WKPageSetPagePolicyClient(m_mainWebView->page(), 0); + auto options = test.options(); + + if (m_mainWebView) { + if (m_mainWebView->viewSupportsOptions(options)) + return; + + WKPageSetPageUIClient(m_mainWebView->page(), nullptr); + WKPageSetPageNavigationClient(m_mainWebView->page(), nullptr); WKPageClose(m_mainWebView->page()); - - m_mainWebView = nullptr; - createWebViewWithOptions(options); - resetStateToConsistentValues(); + m_mainWebView = nullptr; } + + createWebViewWithOptions(options); + + if (!resetStateToConsistentValues(options)) + TestInvocation::dumpWebProcessUnresponsiveness("<unknown> - TestController::run - Failed to reset state to consistent values\n"); } -void TestController::resetPreferencesToConsistentValues() +void TestController::resetPreferencesToConsistentValues(const TestOptions& options) { // Reset preferences - WKPreferencesRef preferences = WKPageGroupGetPreferences(m_pageGroup.get()); + WKPreferencesRef preferences = platformPreferences(); WKPreferencesResetTestRunnerOverrides(preferences); + WKPreferencesEnableAllExperimentalFeatures(preferences); + WKPreferencesSetPageVisibilityBasedProcessSuppressionEnabled(preferences, false); WKPreferencesSetOfflineWebApplicationCacheEnabled(preferences, true); WKPreferencesSetFontSmoothingLevel(preferences, kWKFontSmoothingLevelNoSubpixelAntiAliasing); WKPreferencesSetXSSAuditorEnabled(preferences, false); WKPreferencesSetWebAudioEnabled(preferences, true); + WKPreferencesSetMediaStreamEnabled(preferences, true); WKPreferencesSetDeveloperExtrasEnabled(preferences, true); - WKPreferencesSetJavaScriptExperimentsEnabled(preferences, true); + WKPreferencesSetJavaScriptRuntimeFlags(preferences, kWKJavaScriptRuntimeFlagsAllEnabled); WKPreferencesSetJavaScriptCanOpenWindowsAutomatically(preferences, true); WKPreferencesSetJavaScriptCanAccessClipboard(preferences, true); WKPreferencesSetDOMPasteAllowed(preferences, true); @@ -518,7 +660,14 @@ void TestController::resetPreferencesToConsistentValues() WKPreferencesSetArtificialPluginInitializationDelayEnabled(preferences, false); WKPreferencesSetTabToLinksEnabled(preferences, false); WKPreferencesSetInteractiveFormValidationEnabled(preferences, true); - WKPreferencesSetMockScrollbarsEnabled(preferences, true); + + WKPreferencesSetMockScrollbarsEnabled(preferences, options.useMockScrollbars); + WKPreferencesSetNeedsSiteSpecificQuirks(preferences, options.needsSiteSpecificQuirks); + WKPreferencesSetIntersectionObserverEnabled(preferences, options.enableIntersectionObserver); + WKPreferencesSetModernMediaControlsEnabled(preferences, options.enableModernMediaControls); + + static WKStringRef defaultTextEncoding = WKStringCreateWithUTF8CString("ISO-8859-1"); + WKPreferencesSetDefaultTextEncodingName(preferences, defaultTextEncoding); static WKStringRef standardFontFamily = WKStringCreateWithUTF8CString("Times"); static WKStringRef cursiveFontFamily = WKStringCreateWithUTF8CString("Apple Chancery"); @@ -528,6 +677,7 @@ void TestController::resetPreferencesToConsistentValues() static WKStringRef sansSerifFontFamily = WKStringCreateWithUTF8CString("Helvetica"); static WKStringRef serifFontFamily = WKStringCreateWithUTF8CString("Times"); + WKPreferencesSetMinimumFontSize(preferences, 0); WKPreferencesSetStandardFontFamily(preferences, standardFontFamily); WKPreferencesSetCursiveFontFamily(preferences, cursiveFontFamily); WKPreferencesSetFantasyFontFamily(preferences, fantasyFontFamily); @@ -535,21 +685,40 @@ void TestController::resetPreferencesToConsistentValues() WKPreferencesSetPictographFontFamily(preferences, pictographFontFamily); WKPreferencesSetSansSerifFontFamily(preferences, sansSerifFontFamily); WKPreferencesSetSerifFontFamily(preferences, serifFontFamily); - WKPreferencesSetScreenFontSubstitutionEnabled(preferences, true); WKPreferencesSetAsynchronousSpellCheckingEnabled(preferences, false); #if ENABLE(WEB_AUDIO) WKPreferencesSetMediaSourceEnabled(preferences, true); #endif + WKPreferencesSetHiddenPageDOMTimerThrottlingEnabled(preferences, false); + WKPreferencesSetHiddenPageCSSAnimationSuspensionEnabled(preferences, false); + WKPreferencesSetAcceleratedDrawingEnabled(preferences, m_shouldUseAcceleratedDrawing); + // FIXME: We should be testing the default. + WKPreferencesSetStorageBlockingPolicy(preferences, kWKAllowAllStorage); + + WKPreferencesSetResourceTimingEnabled(preferences, true); + + WKPreferencesSetMediaPlaybackAllowsInline(preferences, true); + WKPreferencesSetInlineMediaPlaybackRequiresPlaysInlineAttribute(preferences, false); + + WKCookieManagerDeleteAllCookies(WKContextGetCookieManager(m_context.get())); + + WKPreferencesSetMockCaptureDevicesEnabled(preferences, true); + + platformResetPreferencesToConsistentValues(); } -bool TestController::resetStateToConsistentValues() +bool TestController::resetStateToConsistentValues(const TestOptions& options) { - m_state = Resetting; - + SetForScope<State> changeState(m_state, Resetting); m_beforeUnloadReturnValue = true; + // This setting differs between the antique and modern Mac WebKit2 API. + // For now, maintain the antique behavior, because some tests depend on it! + // FIXME: We should be testing the default. + WKPageSetBackgroundExtendsBeyondPage(m_mainWebView->page(), false); + WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("Reset")); WKRetainPtr<WKMutableDictionaryRef> resetMessageBody = adoptWK(WKMutableDictionaryCreate()); @@ -557,39 +726,58 @@ bool TestController::resetStateToConsistentValues() WKRetainPtr<WKBooleanRef> shouldGCValue = adoptWK(WKBooleanCreate(m_gcBetweenTests)); WKDictionarySetItem(resetMessageBody.get(), shouldGCKey.get(), shouldGCValue.get()); - WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), resetMessageBody.get()); + WKRetainPtr<WKStringRef> allowedHostsKey = adoptWK(WKStringCreateWithUTF8CString("AllowedHosts")); + WKRetainPtr<WKMutableArrayRef> allowedHostsValue = adoptWK(WKMutableArrayCreate()); + for (auto& host : m_allowedHosts) { + WKRetainPtr<WKStringRef> wkHost = adoptWK(WKStringCreateWithUTF8CString(host.c_str())); + WKArrayAppendItem(allowedHostsValue.get(), wkHost.get()); + } + WKDictionarySetItem(resetMessageBody.get(), allowedHostsKey.get(), allowedHostsValue.get()); + + WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), resetMessageBody.get()); + + WKContextSetShouldUseFontSmoothing(TestController::singleton().context(), false); - WKContextSetShouldUseFontSmoothing(TestController::shared().context(), false); + WKContextSetCacheModel(TestController::singleton().context(), kWKCacheModelDocumentBrowser); - WKContextSetCacheModel(TestController::shared().context(), kWKCacheModelDocumentBrowser); + WKContextClearCachedCredentials(TestController::singleton().context()); // FIXME: This function should also ensure that there is only one page open. // Reset the EventSender for each test. - m_eventSenderProxy = adoptPtr(new EventSenderProxy(this)); + m_eventSenderProxy = std::make_unique<EventSenderProxy>(this); // FIXME: Is this needed? Nothing in TestController changes preferences during tests, and if there is // some other code doing this, it should probably be responsible for cleanup too. - resetPreferencesToConsistentValues(); + resetPreferencesToConsistentValues(options); -#if !PLATFORM(MAC) +#if !PLATFORM(COCOA) WKTextCheckerContinuousSpellCheckingEnabledStateChanged(true); #endif - // in the case that a test using the chrome input field failed, be sure to clean up for the next test + // Make sure the view is in the window (a test can unparent it). + m_mainWebView->addToWindow(); + + // In the case that a test using the chrome input field failed, be sure to clean up for the next test. m_mainWebView->removeChromeInputField(); m_mainWebView->focus(); // Re-set to the default backing scale factor by setting the custom scale factor to 0. WKPageSetCustomBackingScaleFactor(m_mainWebView->page(), 0); + WKPageClearWheelEventTestTrigger(m_mainWebView->page()); + #if PLATFORM(EFL) - // EFL use a real window while other ports such as Qt don't. + // EFL uses a real window while other ports such as Qt don't. // In EFL, we need to resize the window to the original size after calls to window.resizeTo. WKRect rect = m_mainWebView->windowFrame(); m_mainWebView->setWindowFrame(WKRectMake(rect.origin.x, rect.origin.y, TestController::viewWidth, TestController::viewHeight)); #endif + WKPageSetMuted(m_mainWebView->page(), true); + + WKPageClearUserMediaState(m_mainWebView->page()); + // Reset notification permissions m_webNotificationProvider.reset(); @@ -598,33 +786,250 @@ bool TestController::resetStateToConsistentValues() m_isGeolocationPermissionSet = false; m_isGeolocationPermissionAllowed = false; + // Reset UserMedia permissions. + m_userMediaPermissionRequests.clear(); + m_cachedUserMediaPermissions.clear(); + m_isUserMediaPermissionSet = false; + m_isUserMediaPermissionAllowed = false; + // Reset Custom Policy Delegate. setCustomPolicyDelegate(false, false); + m_shouldDownloadUndisplayableMIMETypes = false; + m_workQueueManager.clearWorkQueue(); + m_rejectsProtectionSpaceAndContinueForAuthenticationChallenges = false; m_handlesAuthenticationChallenges = false; m_authenticationUsername = String(); m_authenticationPassword = String(); m_shouldBlockAllPlugins = false; + m_shouldLogHistoryClientCallbacks = false; + m_shouldLogCanAuthenticateAgainstProtectionSpace = false; + + setHidden(false); + + platformResetStateToConsistentValues(); + // Reset main page back to about:blank m_doneResetting = false; + m_shouldDecideNavigationPolicyAfterDelay = false; + + setNavigationGesturesEnabled(false); + + setIgnoresViewportScaleLimits(options.ignoresViewportScaleLimits); + WKPageLoadURL(m_mainWebView->page(), blankURL()); - runUntil(m_doneResetting, ShortTimeout); + runUntil(m_doneResetting, m_currentInvocation->shortTimeout()); return m_doneResetting; } -struct TestCommand { - TestCommand() : shouldDumpPixels(false), timeout(0) { } +void TestController::terminateWebContentProcess() +{ + WKPageTerminate(m_mainWebView->page()); +} - std::string pathOrURL; - bool shouldDumpPixels; - std::string expectedPixelHash; - int timeout; -}; +void TestController::reattachPageToWebProcess() +{ + // Loading a web page is the only way to reattach an existing page to a process. + m_doneResetting = false; + WKPageLoadURL(m_mainWebView->page(), blankURL()); + runUntil(m_doneResetting, m_currentInvocation->shortTimeout()); +} + +const char* TestController::webProcessName() +{ + // FIXME: Find a way to not hardcode the process name. +#if PLATFORM(COCOA) + return "com.apple.WebKit.WebContent.Development"; +#else + return "WebProcess"; +#endif +} + +const char* TestController::networkProcessName() +{ + // FIXME: Find a way to not hardcode the process name. +#if PLATFORM(COCOA) + return "com.apple.WebKit.Networking.Development"; +#else + return "NetworkProcess"; +#endif +} + +const char* TestController::databaseProcessName() +{ + // FIXME: Find a way to not hardcode the process name. +#if PLATFORM(COCOA) + return "com.apple.WebKit.Databases.Development"; +#else + return "DatabaseProcess"; +#endif +} + +static std::string testPath(WKURLRef url) +{ + auto scheme = adoptWK(WKURLCopyScheme(url)); + if (WKStringIsEqualToUTF8CStringIgnoringCase(scheme.get(), "file")) { + auto path = adoptWK(WKURLCopyPath(url)); + auto buffer = std::vector<char>(WKStringGetMaximumUTF8CStringSize(path.get())); + auto length = WKStringGetUTF8CString(path.get(), buffer.data(), buffer.size()); + return std::string(buffer.data(), length); + } + return std::string(); +} + +static WKURLRef createTestURL(const char* pathOrURL) +{ + if (strstr(pathOrURL, "http://") || strstr(pathOrURL, "https://") || strstr(pathOrURL, "file://")) + return WKURLCreateWithUTF8CString(pathOrURL); + + // Creating from filesytem path. + size_t length = strlen(pathOrURL); + if (!length) + return 0; + + const char separator = '/'; + bool isAbsolutePath = pathOrURL[0] == separator; + const char* filePrefix = "file://"; + static const size_t prefixLength = strlen(filePrefix); + + std::unique_ptr<char[]> buffer; + if (isAbsolutePath) { + buffer = std::make_unique<char[]>(prefixLength + length + 1); + strcpy(buffer.get(), filePrefix); + strcpy(buffer.get() + prefixLength, pathOrURL); + } else { + buffer = std::make_unique<char[]>(prefixLength + PATH_MAX + length + 2); // 1 for the separator + strcpy(buffer.get(), filePrefix); + if (!getcwd(buffer.get() + prefixLength, PATH_MAX)) + return 0; + size_t numCharacters = strlen(buffer.get()); + buffer[numCharacters] = separator; + strcpy(buffer.get() + numCharacters + 1, pathOrURL); + } + + return WKURLCreateWithUTF8CString(buffer.get()); +} + +static bool parseBooleanTestHeaderValue(const std::string& value) +{ + if (value == "true") + return true; + if (value == "false") + return false; + + LOG_ERROR("Found unexpected value '%s' for boolean option. Expected 'true' or 'false'.", value.c_str()); + return false; +} + +static void updateTestOptionsFromTestHeader(TestOptions& testOptions, const std::string& pathOrURL, const std::string& absolutePath) +{ + std::string filename = absolutePath; + if (filename.empty()) { + // Gross. Need to reduce conversions between all the string types and URLs. + WKRetainPtr<WKURLRef> wkURL(AdoptWK, createTestURL(pathOrURL.c_str())); + filename = testPath(wkURL.get()); + } + + if (filename.empty()) + return; + + std::string options; + std::ifstream testFile(filename.data()); + if (!testFile.good()) + return; + getline(testFile, options); + std::string beginString("webkit-test-runner [ "); + std::string endString(" ]"); + size_t beginLocation = options.find(beginString); + if (beginLocation == std::string::npos) + return; + size_t endLocation = options.find(endString, beginLocation); + if (endLocation == std::string::npos) { + LOG_ERROR("Could not find end of test header in %s", filename.c_str()); + return; + } + std::string pairString = options.substr(beginLocation + beginString.size(), endLocation - (beginLocation + beginString.size())); + size_t pairStart = 0; + while (pairStart < pairString.size()) { + size_t pairEnd = pairString.find(" ", pairStart); + if (pairEnd == std::string::npos) + pairEnd = pairString.size(); + size_t equalsLocation = pairString.find("=", pairStart); + if (equalsLocation == std::string::npos) { + LOG_ERROR("Malformed option in test header (could not find '=' character) in %s", filename.c_str()); + break; + } + auto key = pairString.substr(pairStart, equalsLocation - pairStart); + auto value = pairString.substr(equalsLocation + 1, pairEnd - (equalsLocation + 1)); + if (key == "language") + String(value.c_str()).split(",", false, testOptions.overrideLanguages); + if (key == "useThreadedScrolling") + testOptions.useThreadedScrolling = parseBooleanTestHeaderValue(value); + if (key == "useFlexibleViewport") + testOptions.useFlexibleViewport = parseBooleanTestHeaderValue(value); + if (key == "useDataDetection") + testOptions.useDataDetection = parseBooleanTestHeaderValue(value); + if (key == "useMockScrollbars") + testOptions.useMockScrollbars = parseBooleanTestHeaderValue(value); + if (key == "needsSiteSpecificQuirks") + testOptions.needsSiteSpecificQuirks = parseBooleanTestHeaderValue(value); + if (key == "ignoresViewportScaleLimits") + testOptions.ignoresViewportScaleLimits = parseBooleanTestHeaderValue(value); + if (key == "useCharacterSelectionGranularity") + testOptions.useCharacterSelectionGranularity = parseBooleanTestHeaderValue(value); + if (key == "enableIntersectionObserver") + testOptions.enableIntersectionObserver = parseBooleanTestHeaderValue(value); + if (key == "enableModernMediaControls") + testOptions.enableModernMediaControls = parseBooleanTestHeaderValue(value); + if (key == "enablePointerLock") + testOptions.enablePointerLock = parseBooleanTestHeaderValue(value); + pairStart = pairEnd + 1; + } +} + +TestOptions TestController::testOptionsForTest(const TestCommand& command) const +{ + TestOptions options(command.pathOrURL); + + options.useRemoteLayerTree = m_shouldUseRemoteLayerTree; + options.shouldShowWebView = m_shouldShowWebView; + + updatePlatformSpecificTestOptionsForTest(options, command.pathOrURL); + updateTestOptionsFromTestHeader(options, command.pathOrURL, command.absolutePath); + + return options; +} + +void TestController::updateWebViewSizeForTest(const TestInvocation& test) +{ + unsigned width = viewWidth; + unsigned height = viewHeight; + if (test.options().isSVGTest) { + width = w3cSVGViewWidth; + height = w3cSVGViewHeight; + } + + mainWebView()->resizeTo(width, height); +} + +void TestController::updateWindowScaleForTest(PlatformWebView* view, const TestInvocation& test) +{ + view->changeWindowScaleIfNeeded(test.options().deviceScaleFactor); +} + +void TestController::configureViewForTest(const TestInvocation& test) +{ + ensureViewSupportsOptionsForTest(test); + updateWebViewSizeForTest(test); + updateWindowScaleForTest(mainWebView(), test); + + platformConfigureViewForTest(test); +} class CommandTokenizer { public: @@ -696,7 +1101,11 @@ TestCommand parseInputLine(const std::string& inputLine) result.shouldDumpPixels = true; if (tokenizer.hasNext()) result.expectedPixelHash = tokenizer.next(); - } else + } else if (arg == std::string("--dump-jsconsolelog-in-stderr")) + result.dumpJSConsoleLogInStdErr = true; + else if (arg == std::string("--absolutePath")) + result.absolutePath = tokenizer.next(); + else die(inputLine); } return result; @@ -704,18 +1113,26 @@ TestCommand parseInputLine(const std::string& inputLine) bool TestController::runTest(const char* inputLine) { + WKTextCheckerSetTestingMode(true); TestCommand command = parseInputLine(std::string(inputLine)); m_state = RunningTest; + + TestOptions options = testOptionsForTest(command); + + WKRetainPtr<WKURLRef> wkURL(AdoptWK, createTestURL(command.pathOrURL.c_str())); + m_currentInvocation = std::make_unique<TestInvocation>(wkURL.get(), options); - m_currentInvocation = adoptPtr(new TestInvocation(command.pathOrURL)); if (command.shouldDumpPixels || m_shouldDumpPixelsForAllTests) m_currentInvocation->setIsPixelTest(command.expectedPixelHash); if (command.timeout > 0) m_currentInvocation->setCustomTimeout(command.timeout); + m_currentInvocation->setDumpJSConsoleLogInStdErr(command.dumpJSConsoleLogInStdErr); + + platformWillRunTest(*m_currentInvocation); m_currentInvocation->invoke(); - m_currentInvocation.clear(); + m_currentInvocation = nullptr; return true; } @@ -738,11 +1155,6 @@ void TestController::runTestingServerLoop() void TestController::run() { - if (!resetStateToConsistentValues()) { - TestInvocation::dumpWebProcessUnresponsiveness("<unknown> - TestController::run - Failed to reset state to consistent values\n"); - return; - } - if (m_usingServerMode) runTestingServerLoop(); else { @@ -753,26 +1165,10 @@ void TestController::run() } } -void TestController::runUntil(bool& done, TimeoutDuration timeoutDuration) +void TestController::runUntil(bool& done, double timeout) { - double timeout = m_noTimeout; - if (!m_forceNoTimeout) { - switch (timeoutDuration) { - case ShortTimeout: - timeout = m_shortTimeout; - break; - case LongTimeout: - timeout = m_longTimeout; - break; - case CustomTimeout: - timeout = m_timeout; - break; - case NoTimeout: - default: - timeout = m_noTimeout; - break; - } - } + if (m_forceNoTimeout) + timeout = noTimeout; platformRunUntil(done, timeout); } @@ -789,6 +1185,33 @@ void TestController::didReceiveSynchronousMessageFromInjectedBundle(WKContextRef *returnData = static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody).leakRef(); } +WKTypeRef TestController::getInjectedBundleInitializationUserData(WKContextRef, const void* clientInfo) +{ + return static_cast<TestController*>(const_cast<void*>(clientInfo))->getInjectedBundleInitializationUserData().leakRef(); +} + +// WKPageInjectedBundleClient + +void TestController::didReceivePageMessageFromInjectedBundle(WKPageRef page, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo) +{ + static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveMessageFromInjectedBundle(messageName, messageBody); +} + +void TestController::didReceiveSynchronousPageMessageFromInjectedBundle(WKPageRef page, WKStringRef messageName, WKTypeRef messageBody, WKTypeRef* returnData, const void* clientInfo) +{ + *returnData = static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody).leakRef(); +} + +void TestController::networkProcessDidCrash(WKContextRef context, const void *clientInfo) +{ + static_cast<TestController*>(const_cast<void*>(clientInfo))->networkProcessDidCrash(); +} + +void TestController::databaseProcessDidCrash(WKContextRef context, const void *clientInfo) +{ + static_cast<TestController*>(const_cast<void*>(clientInfo))->databaseProcessDidCrash(); +} + void TestController::didReceiveKeyDownMessageFromInjectedBundle(WKDictionaryRef messageBodyDictionary, bool synchronous) { WKRetainPtr<WKStringRef> keyKey = adoptWK(WKStringCreateWithUTF8CString("Key")); @@ -800,18 +1223,15 @@ void TestController::didReceiveKeyDownMessageFromInjectedBundle(WKDictionaryRef WKRetainPtr<WKStringRef> locationKey = adoptWK(WKStringCreateWithUTF8CString("Location")); unsigned location = static_cast<unsigned>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, locationKey.get())))); - if (synchronous) - WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true); - m_eventSenderProxy->keyDown(key, modifiers, location); - - if (synchronous) - WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false); } void TestController::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody) { if (WKStringIsEqualToUTF8CString(messageName, "EventSender")) { + if (m_state != RunningTest) + return; + ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID()); WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody); @@ -826,7 +1246,6 @@ void TestController::didReceiveMessageFromInjectedBundle(WKStringRef messageName WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get())))); // Forward to WebProcess - WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false); if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown")) m_eventSenderProxy->mouseDown(button, modifiers); else @@ -841,6 +1260,53 @@ void TestController::didReceiveMessageFromInjectedBundle(WKStringRef messageName return; } + if (WKStringIsEqualToUTF8CString(subMessageName, "MouseScrollBy")) { + WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X")); + double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))); + + WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y")); + double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))); + + // Forward to WebProcess + m_eventSenderProxy->mouseScrollBy(x, y); + return; + } + + if (WKStringIsEqualToUTF8CString(subMessageName, "MouseScrollByWithWheelAndMomentumPhases")) { + WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X")); + double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))); + + WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y")); + double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))); + + WKRetainPtr<WKStringRef> phaseKey = adoptWK(WKStringCreateWithUTF8CString("Phase")); + int phase = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, phaseKey.get())))); + WKRetainPtr<WKStringRef> momentumKey = adoptWK(WKStringCreateWithUTF8CString("Momentum")); + int momentum = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, momentumKey.get())))); + + // Forward to WebProcess + m_eventSenderProxy->mouseScrollByWithWheelAndMomentumPhases(x, y, phase, momentum); + + return; + } + + if (WKStringIsEqualToUTF8CString(subMessageName, "SwipeGestureWithWheelAndMomentumPhases")) { + WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X")); + double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))); + + WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y")); + double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))); + + WKRetainPtr<WKStringRef> phaseKey = adoptWK(WKStringCreateWithUTF8CString("Phase")); + int phase = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, phaseKey.get())))); + WKRetainPtr<WKStringRef> momentumKey = adoptWK(WKStringCreateWithUTF8CString("Momentum")); + int momentum = static_cast<int>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, momentumKey.get())))); + + m_eventSenderProxy->swipeGestureWithWheelAndMomentumPhases(x, y, phase, momentum); + + return; + } + ASSERT_NOT_REACHED(); } @@ -853,6 +1319,9 @@ void TestController::didReceiveMessageFromInjectedBundle(WKStringRef messageName WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody) { if (WKStringIsEqualToUTF8CString(messageName, "EventSender")) { + if (m_state != RunningTest) + return nullptr; + ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID()); WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody); @@ -873,12 +1342,10 @@ WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedB WKEventModifiers modifiers = static_cast<WKEventModifiers>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, modifiersKey.get())))); // Forward to WebProcess - WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true); if (WKStringIsEqualToUTF8CString(subMessageName, "MouseDown")) m_eventSenderProxy->mouseDown(button, modifiers); else m_eventSenderProxy->mouseUp(button, modifiers); - WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false); return 0; } @@ -890,25 +1357,39 @@ WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedB double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))); // Forward to WebProcess - WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true); m_eventSenderProxy->mouseMoveTo(x, y); - WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false); return 0; } - if (WKStringIsEqualToUTF8CString(subMessageName, "MouseScrollBy")) { - WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X")); - double x = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, xKey.get()))); +#if PLATFORM(MAC) + if (WKStringIsEqualToUTF8CString(subMessageName, "MouseForceClick")) { + m_eventSenderProxy->mouseForceClick(); + return 0; + } - WKRetainPtr<WKStringRef> yKey = adoptWK(WKStringCreateWithUTF8CString("Y")); - double y = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, yKey.get()))); + if (WKStringIsEqualToUTF8CString(subMessageName, "StartAndCancelMouseForceClick")) { + m_eventSenderProxy->startAndCancelMouseForceClick(); + return 0; + } - // Forward to WebProcess - WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true); - m_eventSenderProxy->mouseScrollBy(x, y); - WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false); + if (WKStringIsEqualToUTF8CString(subMessageName, "MouseForceDown")) { + m_eventSenderProxy->mouseForceDown(); + return 0; + } + + if (WKStringIsEqualToUTF8CString(subMessageName, "MouseForceUp")) { + m_eventSenderProxy->mouseForceUp(); + return 0; + } + + if (WKStringIsEqualToUTF8CString(subMessageName, "MouseForceChanged")) { + WKRetainPtr<WKStringRef> forceKey = adoptWK(WKStringCreateWithUTF8CString("Force")); + double force = WKDoubleGetValue(static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, forceKey.get()))); + + m_eventSenderProxy->mouseForceChanged(force); return 0; } +#endif // PLATFORM(MAC) if (WKStringIsEqualToUTF8CString(subMessageName, "ContinuousMouseScrollBy")) { WKRetainPtr<WKStringRef> xKey = adoptWK(WKStringCreateWithUTF8CString("X")); @@ -921,9 +1402,7 @@ WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedB bool paged = static_cast<bool>(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, pagedKey.get())))); // Forward to WebProcess - WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true); m_eventSenderProxy->continuousMouseScrollBy(x, y, paged); - WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false); return 0; } @@ -984,30 +1463,22 @@ WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedB } if (WKStringIsEqualToUTF8CString(subMessageName, "TouchStart")) { - WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true); m_eventSenderProxy->touchStart(); - WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false); return 0; } if (WKStringIsEqualToUTF8CString(subMessageName, "TouchMove")) { - WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true); m_eventSenderProxy->touchMove(); - WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false); return 0; } if (WKStringIsEqualToUTF8CString(subMessageName, "TouchEnd")) { - WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true); m_eventSenderProxy->touchEnd(); - WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false); return 0; } if (WKStringIsEqualToUTF8CString(subMessageName, "TouchCancel")) { - WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), true); m_eventSenderProxy->touchCancel(); - WKPageSetShouldSendEventsSynchronously(mainWebView()->page(), false); return 0; } @@ -1035,21 +1506,47 @@ WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedB return m_currentInvocation->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody); } -// WKPageLoaderClient +WKRetainPtr<WKTypeRef> TestController::getInjectedBundleInitializationUserData() +{ + return nullptr; +} -void TestController::didCommitLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef, const void* clientInfo) +// WKContextClient + +void TestController::networkProcessDidCrash() { - static_cast<TestController*>(const_cast<void*>(clientInfo))->didCommitLoadForFrame(page, frame); + pid_t pid = WKContextGetNetworkProcessIdentifier(m_context.get()); + fprintf(stderr, "#CRASHED - %s (pid %ld)\n", networkProcessName(), static_cast<long>(pid)); + exit(1); } -void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef, const void* clientInfo) +void TestController::databaseProcessDidCrash() { - static_cast<TestController*>(const_cast<void*>(clientInfo))->didFinishLoadForFrame(page, frame); + pid_t pid = WKContextGetDatabaseProcessIdentifier(m_context.get()); + fprintf(stderr, "#CRASHED - %s (pid %ld)\n", databaseProcessName(), static_cast<long>(pid)); + exit(1); } -void TestController::didReceiveAuthenticationChallengeInFrame(WKPageRef page, WKFrameRef frame, WKAuthenticationChallengeRef authenticationChallenge, const void *clientInfo) +// WKPageNavigationClient + +void TestController::didCommitNavigation(WKPageRef page, WKNavigationRef navigation, WKTypeRef, const void* clientInfo) { - static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveAuthenticationChallengeInFrame(page, frame, authenticationChallenge); + static_cast<TestController*>(const_cast<void*>(clientInfo))->didCommitNavigation(page, navigation); +} + +void TestController::didFinishNavigation(WKPageRef page, WKNavigationRef navigation, WKTypeRef, const void* clientInfo) +{ + static_cast<TestController*>(const_cast<void*>(clientInfo))->didFinishNavigation(page, navigation); +} + +bool TestController::canAuthenticateAgainstProtectionSpace(WKPageRef page, WKProtectionSpaceRef protectionSpace, const void* clientInfo) +{ + return static_cast<TestController*>(const_cast<void*>(clientInfo))->canAuthenticateAgainstProtectionSpace(page, protectionSpace); +} + +void TestController::didReceiveAuthenticationChallenge(WKPageRef page, WKAuthenticationChallengeRef authenticationChallenge, const void *clientInfo) +{ + static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveAuthenticationChallenge(page, /*frame,*/ authenticationChallenge); } void TestController::processDidCrash(WKPageRef page, const void* clientInfo) @@ -1057,52 +1554,114 @@ void TestController::processDidCrash(WKPageRef page, const void* clientInfo) static_cast<TestController*>(const_cast<void*>(clientInfo))->processDidCrash(); } -WKPluginLoadPolicy TestController::pluginLoadPolicy(WKPageRef page, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription, const void* clientInfo) +void TestController::didBeginNavigationGesture(WKPageRef page, const void *clientInfo) +{ + static_cast<TestController*>(const_cast<void*>(clientInfo))->didBeginNavigationGesture(page); +} + +void TestController::willEndNavigationGesture(WKPageRef page, WKBackForwardListItemRef backForwardListItem, const void *clientInfo) +{ + static_cast<TestController*>(const_cast<void*>(clientInfo))->willEndNavigationGesture(page, backForwardListItem); +} + +void TestController::didEndNavigationGesture(WKPageRef page, WKBackForwardListItemRef backForwardListItem, const void *clientInfo) +{ + static_cast<TestController*>(const_cast<void*>(clientInfo))->didEndNavigationGesture(page, backForwardListItem); +} + +void TestController::didRemoveNavigationGestureSnapshot(WKPageRef page, const void *clientInfo) +{ + static_cast<TestController*>(const_cast<void*>(clientInfo))->didRemoveNavigationGestureSnapshot(page); +} + +WKPluginLoadPolicy TestController::decidePolicyForPluginLoad(WKPageRef page, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription, const void* clientInfo) { - return static_cast<TestController*>(const_cast<void*>(clientInfo))->pluginLoadPolicy(page, currentPluginLoadPolicy, pluginInformation, unavailabilityDescription); + return static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForPluginLoad(page, currentPluginLoadPolicy, pluginInformation, unavailabilityDescription); } -WKPluginLoadPolicy TestController::pluginLoadPolicy(WKPageRef, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription) +WKPluginLoadPolicy TestController::decidePolicyForPluginLoad(WKPageRef, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription) { if (m_shouldBlockAllPlugins) return kWKPluginLoadPolicyBlocked; + +#if PLATFORM(MAC) + WKStringRef bundleIdentifier = (WKStringRef)WKDictionaryGetItemForKey(pluginInformation, WKPluginInformationBundleIdentifierKey()); + if (!bundleIdentifier) + return currentPluginLoadPolicy; + + if (WKStringIsEqualToUTF8CString(bundleIdentifier, "com.apple.QuickTime Plugin.plugin")) + return currentPluginLoadPolicy; + + if (WKStringIsEqualToUTF8CString(bundleIdentifier, "com.apple.testnetscapeplugin")) + return currentPluginLoadPolicy; + + RELEASE_ASSERT_NOT_REACHED(); // Please don't use any other plug-ins in tests, as they will not be installed on all machines. +#else return currentPluginLoadPolicy; +#endif } -void TestController::didCommitLoadForFrame(WKPageRef page, WKFrameRef frame) +void TestController::didCommitNavigation(WKPageRef page, WKNavigationRef navigation) { - if (!WKFrameIsMainFrame(frame)) - return; - mainWebView()->focus(); } -void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame) +bool TestController::canAuthenticateAgainstProtectionSpace(WKPageRef page, WKProtectionSpaceRef protectionSpace) { - if (m_state != Resetting) - return; + if (m_shouldLogCanAuthenticateAgainstProtectionSpace) + m_currentInvocation->outputText("canAuthenticateAgainstProtectionSpace\n"); + WKProtectionSpaceAuthenticationScheme authenticationScheme = WKProtectionSpaceGetAuthenticationScheme(protectionSpace); + + if (authenticationScheme == kWKProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested) { + std::string host = toSTD(adoptWK(WKProtectionSpaceCopyHost(protectionSpace)).get()); + return host == "localhost" || host == "127.0.0.1"; + } + + return authenticationScheme <= kWKProtectionSpaceAuthenticationSchemeHTTPDigest; +} - if (!WKFrameIsMainFrame(frame)) +void TestController::didFinishNavigation(WKPageRef page, WKNavigationRef navigation) +{ + if (m_state != Resetting) return; - WKRetainPtr<WKURLRef> wkURL(AdoptWK, WKFrameCopyURL(frame)); + WKRetainPtr<WKURLRef> wkURL(AdoptWK, WKFrameCopyURL(WKPageGetMainFrame(page))); if (!WKURLIsEqual(wkURL.get(), blankURL())) return; m_doneResetting = true; - shared().notifyDone(); + singleton().notifyDone(); } -void TestController::didReceiveAuthenticationChallengeInFrame(WKPageRef page, WKFrameRef frame, WKAuthenticationChallengeRef authenticationChallenge) +void TestController::didReceiveAuthenticationChallenge(WKPageRef page, WKAuthenticationChallengeRef authenticationChallenge) { - String message; + WKProtectionSpaceRef protectionSpace = WKAuthenticationChallengeGetProtectionSpace(authenticationChallenge); + WKAuthenticationDecisionListenerRef decisionListener = WKAuthenticationChallengeGetDecisionListener(authenticationChallenge); + + if (WKProtectionSpaceGetAuthenticationScheme(protectionSpace) == kWKProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested) { + // Any non-empty credential signals to accept the server trust. Since the cross-platform API + // doesn't expose a way to create a credential from server trust, we use a password credential. + + WKRetainPtr<WKCredentialRef> credential = adoptWK(WKCredentialCreate(toWK("accept server trust").get(), toWK("").get(), kWKCredentialPersistenceNone)); + WKAuthenticationDecisionListenerUseCredential(decisionListener, credential.get()); + return; + } + + if (m_rejectsProtectionSpaceAndContinueForAuthenticationChallenges) { + m_currentInvocation->outputText("Simulating reject protection space and continue for authentication challenge\n"); + WKAuthenticationDecisionListenerRejectProtectionSpaceAndContinue(decisionListener); + return; + } + + std::string host = toSTD(adoptWK(WKProtectionSpaceCopyHost(protectionSpace)).get()); + int port = WKProtectionSpaceGetPort(protectionSpace); + String message = String::format("%s:%d - didReceiveAuthenticationChallenge - ", host.c_str(), port); if (!m_handlesAuthenticationChallenges) - message = "<unknown> - didReceiveAuthenticationChallenge - Simulating cancelled authentication sheet\n"; + message.append("Simulating cancelled authentication sheet\n"); else - message = String::format("<unknown> - didReceiveAuthenticationChallenge - Responding with %s:%s\n", m_authenticationUsername.utf8().data(), m_authenticationPassword.utf8().data()); + message.append(String::format("Responding with %s:%s\n", m_authenticationUsername.utf8().data(), m_authenticationPassword.utf8().data())); m_currentInvocation->outputText(message); - WKAuthenticationDecisionListenerRef decisionListener = WKAuthenticationChallengeGetDecisionListener(authenticationChallenge); if (!m_handlesAuthenticationChallenges) { WKAuthenticationDecisionListenerUseCredential(decisionListener, 0); return; @@ -1113,17 +1672,103 @@ void TestController::didReceiveAuthenticationChallengeInFrame(WKPageRef page, WK WKAuthenticationDecisionListenerUseCredential(decisionListener, credential.get()); } + +// WKContextDownloadClient + +void TestController::downloadDidStart(WKContextRef context, WKDownloadRef download, const void* clientInfo) +{ + static_cast<TestController*>(const_cast<void*>(clientInfo))->downloadDidStart(context, download); +} + +WKStringRef TestController::decideDestinationWithSuggestedFilename(WKContextRef context, WKDownloadRef download, WKStringRef filename, bool* allowOverwrite, const void* clientInfo) +{ + return static_cast<TestController*>(const_cast<void*>(clientInfo))->decideDestinationWithSuggestedFilename(context, download, filename, allowOverwrite); +} + +void TestController::downloadDidFinish(WKContextRef context, WKDownloadRef download, const void* clientInfo) +{ + static_cast<TestController*>(const_cast<void*>(clientInfo))->downloadDidFinish(context, download); +} + +void TestController::downloadDidFail(WKContextRef context, WKDownloadRef download, WKErrorRef error, const void* clientInfo) +{ + static_cast<TestController*>(const_cast<void*>(clientInfo))->downloadDidFail(context, download, error); +} + +void TestController::downloadDidCancel(WKContextRef context, WKDownloadRef download, const void* clientInfo) +{ + static_cast<TestController*>(const_cast<void*>(clientInfo))->downloadDidCancel(context, download); +} + +void TestController::downloadDidStart(WKContextRef context, WKDownloadRef download) +{ + m_currentInvocation->outputText("Download started.\n"); +} + +WKStringRef TestController::decideDestinationWithSuggestedFilename(WKContextRef, WKDownloadRef, WKStringRef filename, bool*& allowOverwrite) +{ + String suggestedFilename = toWTFString(filename); + + StringBuilder builder; + builder.append("Downloading URL with suggested filename \""); + builder.append(suggestedFilename); + builder.append("\"\n"); + + m_currentInvocation->outputText(builder.toString()); + + const char* dumpRenderTreeTemp = libraryPathForTesting(); + if (!dumpRenderTreeTemp) + return nullptr; + + *allowOverwrite = true; + String temporaryFolder = String::fromUTF8(dumpRenderTreeTemp); + if (suggestedFilename.isEmpty()) + suggestedFilename = "Unknown"; + + return toWK(temporaryFolder + "/" + suggestedFilename).leakRef(); +} + +void TestController::downloadDidFinish(WKContextRef, WKDownloadRef) +{ + m_currentInvocation->outputText("Download completed.\n"); + m_currentInvocation->notifyDownloadDone(); +} + +void TestController::downloadDidFail(WKContextRef, WKDownloadRef, WKErrorRef error) +{ + String message = String::format("Download failed.\n"); + m_currentInvocation->outputText(message); + + WKRetainPtr<WKStringRef> errorDomain = adoptWK(WKErrorCopyDomain(error)); + WKRetainPtr<WKStringRef> errorDescription = adoptWK(WKErrorCopyLocalizedDescription(error)); + int errorCode = WKErrorGetErrorCode(error); + + StringBuilder errorBuilder; + errorBuilder.append("Failed: "); + errorBuilder.append(toWTFString(errorDomain)); + errorBuilder.append(", code="); + errorBuilder.appendNumber(errorCode); + errorBuilder.append(", description="); + errorBuilder.append(toWTFString(errorDescription)); + errorBuilder.append("\n"); + + m_currentInvocation->outputText(errorBuilder.toString()); + m_currentInvocation->notifyDownloadDone(); +} + +void TestController::downloadDidCancel(WKContextRef, WKDownloadRef) +{ + m_currentInvocation->outputText("Download cancelled.\n"); + m_currentInvocation->notifyDownloadDone(); +} + void TestController::processDidCrash() { // This function can be called multiple times when crash logs are being saved on Windows, so // ensure we only print the crashed message once. if (!m_didPrintWebProcessCrashedMessage) { -#if PLATFORM(MAC) pid_t pid = WKPageGetProcessIdentifier(m_mainWebView->page()); - fprintf(stderr, "#CRASHED - WebProcess (pid %ld)\n", static_cast<long>(pid)); -#else - fputs("#CRASHED - WebProcess\n", stderr); -#endif + fprintf(stderr, "#CRASHED - %s (pid %ld)\n", webProcessName(), static_cast<long>(pid)); fflush(stderr); m_didPrintWebProcessCrashedMessage = true; } @@ -1132,9 +1777,29 @@ void TestController::processDidCrash() exit(1); } +void TestController::didBeginNavigationGesture(WKPageRef) +{ + m_currentInvocation->didBeginSwipe(); +} + +void TestController::willEndNavigationGesture(WKPageRef, WKBackForwardListItemRef) +{ + m_currentInvocation->willEndSwipe(); +} + +void TestController::didEndNavigationGesture(WKPageRef, WKBackForwardListItemRef) +{ + m_currentInvocation->didEndSwipe(); +} + +void TestController::didRemoveNavigationGestureSnapshot(WKPageRef) +{ + m_currentInvocation->didRemoveSwipeSnapshot(); +} + void TestController::simulateWebNotificationClick(uint64_t notificationID) { - m_webNotificationProvider.simulateWebNotificationClick(notificationID); + m_webNotificationProvider.simulateWebNotificationClick(mainWebView()->page(), notificationID); } void TestController::setGeolocationPermission(bool enabled) @@ -1160,16 +1825,223 @@ void TestController::handleGeolocationPermissionRequest(WKGeolocationPermissionR decidePolicyForGeolocationPermissionRequestIfPossible(); } -void TestController::setCustomPolicyDelegate(bool enabled, bool permissive) +bool TestController::isGeolocationProviderActive() const { - m_policyDelegateEnabled = enabled; - m_policyDelegatePermissive = permissive; + return m_geolocationProvider->isActive(); +} + +static String originUserVisibleName(WKSecurityOriginRef origin) +{ + if (!origin) + return emptyString(); + + std::string host = toSTD(adoptWK(WKSecurityOriginCopyHost(origin))).c_str(); + std::string protocol = toSTD(adoptWK(WKSecurityOriginCopyProtocol(origin))).c_str(); + + if (!host.length() || !protocol.length()) + return emptyString(); + + unsigned short port = WKSecurityOriginGetPort(origin); + if (port) + return String::format("%s://%s:%d", protocol.c_str(), host.c_str(), port); + + return String::format("%s://%s", protocol.c_str(), host.c_str()); +} + +static String userMediaOriginHash(WKSecurityOriginRef userMediaDocumentOrigin, WKSecurityOriginRef topLevelDocumentOrigin) +{ + String userMediaDocumentOriginString = originUserVisibleName(userMediaDocumentOrigin); + String topLevelDocumentOriginString = originUserVisibleName(topLevelDocumentOrigin); + + if (topLevelDocumentOriginString.isEmpty()) + return userMediaDocumentOriginString; + + return String::format("%s-%s", userMediaDocumentOriginString.utf8().data(), topLevelDocumentOriginString.utf8().data()); +} + +static String userMediaOriginHash(WKStringRef userMediaDocumentOriginString, WKStringRef topLevelDocumentOriginString) +{ + auto userMediaDocumentOrigin = adoptWK(WKSecurityOriginCreateFromString(userMediaDocumentOriginString)); + if (!WKStringGetLength(topLevelDocumentOriginString)) + return userMediaOriginHash(userMediaDocumentOrigin.get(), nullptr); + + auto topLevelDocumentOrigin = adoptWK(WKSecurityOriginCreateFromString(topLevelDocumentOriginString)); + return userMediaOriginHash(userMediaDocumentOrigin.get(), topLevelDocumentOrigin.get()); +} + +void TestController::setUserMediaPermission(bool enabled) +{ + m_isUserMediaPermissionSet = true; + m_isUserMediaPermissionAllowed = enabled; + decidePolicyForUserMediaPermissionRequestIfPossible(); +} + +static String createCanonicalUUIDString() +{ + unsigned randomData[4]; + cryptographicallyRandomValues(reinterpret_cast<unsigned char*>(randomData), sizeof(randomData)); + + // Format as Version 4 UUID. + StringBuilder builder; + builder.reserveCapacity(36); + appendUnsignedAsHexFixedSize(randomData[0], builder, 8, Lowercase); + builder.append('-'); + appendUnsignedAsHexFixedSize(randomData[1] >> 16, builder, 4, Lowercase); + builder.appendLiteral("-4"); + appendUnsignedAsHexFixedSize(randomData[1] & 0x00000fff, builder, 3, Lowercase); + builder.append('-'); + appendUnsignedAsHexFixedSize((randomData[2] >> 30) | 0x8, builder, 1, Lowercase); + appendUnsignedAsHexFixedSize((randomData[2] >> 16) & 0x00000fff, builder, 3, Lowercase); + builder.append('-'); + appendUnsignedAsHexFixedSize(randomData[2] & 0x0000ffff, builder, 4, Lowercase); + appendUnsignedAsHexFixedSize(randomData[3], builder, 8, Lowercase); + return builder.toString(); +} + +class OriginSettings : public RefCounted<OriginSettings> { +public: + explicit OriginSettings() + { + } + + bool persistentPermission() const { return m_persistentPermission; } + void setPersistentPermission(bool permission) { m_persistentPermission = permission; } + + String persistentSalt() const { return m_persistentSalt; } + void setPersistentSalt(const String& salt) { m_persistentSalt = salt; } + + HashMap<uint64_t, String>& ephemeralSalts() { return m_ephemeralSalts; } + + void incrementRequestCount() { ++m_requestCount; } + void resetRequestCount() { m_requestCount = 0; } + unsigned requestCount() const { return m_requestCount; } + +private: + HashMap<uint64_t, String> m_ephemeralSalts; + String m_persistentSalt; + unsigned m_requestCount { 0 }; + bool m_persistentPermission { false }; +}; + +String TestController::saltForOrigin(WKFrameRef frame, String originHash) +{ + auto& settings = settingsForOrigin(originHash); + auto& ephemeralSalts = settings.ephemeralSalts(); + auto frameInfo = adoptWK(WKFrameCreateFrameInfo(frame)); + auto frameHandle = WKFrameInfoGetFrameHandleRef(frameInfo.get()); + uint64_t frameIdentifier = WKFrameHandleGetFrameID(frameHandle); + String frameSalt = ephemeralSalts.get(frameIdentifier); + + if (settings.persistentPermission()) { + if (frameSalt.length()) + return frameSalt; + + if (!settings.persistentSalt().length()) + settings.setPersistentSalt(createCanonicalUUIDString()); + + return settings.persistentSalt(); + } + + if (!frameSalt.length()) { + frameSalt = createCanonicalUUIDString(); + ephemeralSalts.add(frameIdentifier, frameSalt); + } + + return frameSalt; +} + +void TestController::setUserMediaPersistentPermissionForOrigin(bool permission, WKStringRef userMediaDocumentOriginString, WKStringRef topLevelDocumentOriginString) +{ + auto originHash = userMediaOriginHash(userMediaDocumentOriginString, topLevelDocumentOriginString); + auto& settings = settingsForOrigin(originHash); + settings.setPersistentPermission(permission); +} + +void TestController::handleCheckOfUserMediaPermissionForOrigin(WKFrameRef frame, WKSecurityOriginRef userMediaDocumentOrigin, WKSecurityOriginRef topLevelDocumentOrigin, const WKUserMediaPermissionCheckRef& checkRequest) +{ + auto originHash = userMediaOriginHash(userMediaDocumentOrigin, topLevelDocumentOrigin); + auto salt = saltForOrigin(frame, originHash); + WKRetainPtr<WKStringRef> saltString = adoptWK(WKStringCreateWithUTF8CString(salt.utf8().data())); + + WKUserMediaPermissionCheckSetUserMediaAccessInfo(checkRequest, saltString.get(), settingsForOrigin(originHash).persistentPermission()); } -void TestController::setVisibilityState(WKPageVisibilityState visibilityState, bool isInitialState) +void TestController::handleUserMediaPermissionRequest(WKFrameRef frame, WKSecurityOriginRef userMediaDocumentOrigin, WKSecurityOriginRef topLevelDocumentOrigin, WKUserMediaPermissionRequestRef request) { - setHidden(visibilityState != kWKPageVisibilityStateVisible); - WKPageSetVisibilityState(m_mainWebView->page(), visibilityState, isInitialState); + auto originHash = userMediaOriginHash(userMediaDocumentOrigin, topLevelDocumentOrigin); + m_userMediaPermissionRequests.append(std::make_pair(originHash, request)); + decidePolicyForUserMediaPermissionRequestIfPossible(); +} + +OriginSettings& TestController::settingsForOrigin(const String& originHash) +{ + RefPtr<OriginSettings> settings = m_cachedUserMediaPermissions.get(originHash); + if (!settings) { + settings = adoptRef(*new OriginSettings()); + m_cachedUserMediaPermissions.add(originHash, settings); + } + + return *settings; +} + +unsigned TestController::userMediaPermissionRequestCountForOrigin(WKStringRef userMediaDocumentOriginString, WKStringRef topLevelDocumentOriginString) +{ + auto originHash = userMediaOriginHash(userMediaDocumentOriginString, topLevelDocumentOriginString); + return settingsForOrigin(originHash).requestCount(); +} + +void TestController::resetUserMediaPermissionRequestCountForOrigin(WKStringRef userMediaDocumentOriginString, WKStringRef topLevelDocumentOriginString) +{ + auto originHash = userMediaOriginHash(userMediaDocumentOriginString, topLevelDocumentOriginString); + settingsForOrigin(originHash).resetRequestCount(); +} + +void TestController::decidePolicyForUserMediaPermissionRequestIfPossible() +{ + if (!m_isUserMediaPermissionSet) + return; + + for (auto& pair : m_userMediaPermissionRequests) { + auto originHash = pair.first; + auto request = pair.second.get(); + + auto& settings = settingsForOrigin(originHash); + settings.incrementRequestCount(); + + if (!m_isUserMediaPermissionAllowed && !settings.persistentPermission()) { + WKUserMediaPermissionRequestDeny(request, kWKPermissionDenied); + continue; + } + + WKRetainPtr<WKArrayRef> audioDeviceUIDs = adoptWK(WKUserMediaPermissionRequestAudioDeviceUIDs(request)); + WKRetainPtr<WKArrayRef> videoDeviceUIDs = adoptWK(WKUserMediaPermissionRequestVideoDeviceUIDs(request)); + + if (!WKArrayGetSize(videoDeviceUIDs.get()) && !WKArrayGetSize(audioDeviceUIDs.get())) { + WKUserMediaPermissionRequestDeny(request, kWKNoConstraints); + continue; + } + + WKRetainPtr<WKStringRef> videoDeviceUID; + if (WKArrayGetSize(videoDeviceUIDs.get())) + videoDeviceUID = reinterpret_cast<WKStringRef>(WKArrayGetItemAtIndex(videoDeviceUIDs.get(), 0)); + else + videoDeviceUID = adoptWK(WKStringCreateWithUTF8CString("")); + + WKRetainPtr<WKStringRef> audioDeviceUID; + if (WKArrayGetSize(audioDeviceUIDs.get())) + audioDeviceUID = reinterpret_cast<WKStringRef>(WKArrayGetItemAtIndex(audioDeviceUIDs.get(), 0)); + else + audioDeviceUID = adoptWK(WKStringCreateWithUTF8CString("")); + + WKUserMediaPermissionRequestAllow(request, audioDeviceUID.get(), videoDeviceUID.get()); + } + m_userMediaPermissionRequests.clear(); +} + +void TestController::setCustomPolicyDelegate(bool enabled, bool permissive) +{ + m_policyDelegateEnabled = enabled; + m_policyDelegatePermissive = permissive; } void TestController::decidePolicyForGeolocationPermissionRequestIfPossible() @@ -1189,7 +2061,7 @@ void TestController::decidePolicyForGeolocationPermissionRequestIfPossible() void TestController::decidePolicyForNotificationPermissionRequest(WKPageRef page, WKSecurityOriginRef origin, WKNotificationPermissionRequestRef request, const void*) { - TestController::shared().decidePolicyForNotificationPermissionRequest(page, origin, request); + TestController::singleton().decidePolicyForNotificationPermissionRequest(page, origin, request); } void TestController::decidePolicyForNotificationPermissionRequest(WKPageRef, WKSecurityOriginRef, WKNotificationPermissionRequestRef request) @@ -1202,37 +2074,219 @@ void TestController::unavailablePluginButtonClicked(WKPageRef, WKPluginUnavailab printf("MISSING PLUGIN BUTTON PRESSED\n"); } -void TestController::decidePolicyForNavigationAction(WKPageRef, WKFrameRef, WKFrameNavigationType, WKEventModifiers, WKEventMouseButton, WKFrameRef, WKURLRequestRef, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo) +void TestController::decidePolicyForNavigationAction(WKPageRef, WKNavigationActionRef navigationAction, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo) { static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForNavigationAction(listener); } void TestController::decidePolicyForNavigationAction(WKFramePolicyListenerRef listener) { - if (m_policyDelegateEnabled && !m_policyDelegatePermissive) { - WKFramePolicyListenerIgnore(listener); - return; - } + WKRetainPtr<WKFramePolicyListenerRef> retainedListener { listener }; + const bool shouldIgnore { m_policyDelegateEnabled && !m_policyDelegatePermissive }; + auto decisionFunction = [shouldIgnore, retainedListener]() { + if (shouldIgnore) + WKFramePolicyListenerIgnore(retainedListener.get()); + else + WKFramePolicyListenerUse(retainedListener.get()); + }; - WKFramePolicyListenerUse(listener); + if (m_shouldDecideNavigationPolicyAfterDelay) + RunLoop::main().dispatch(WTFMove(decisionFunction)); + else + decisionFunction(); } -void TestController::decidePolicyForResponse(WKPageRef, WKFrameRef frame, WKURLResponseRef response, WKURLRequestRef, bool canShowMIMEType, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo) +void TestController::decidePolicyForNavigationResponse(WKPageRef, WKNavigationResponseRef navigationResponse, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo) { - static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForResponse(frame, response, listener); + static_cast<TestController*>(const_cast<void*>(clientInfo))->decidePolicyForNavigationResponse(navigationResponse, listener); } -void TestController::decidePolicyForResponse(WKFrameRef frame, WKURLResponseRef response, WKFramePolicyListenerRef listener) +void TestController::decidePolicyForNavigationResponse(WKNavigationResponseRef navigationResponse, WKFramePolicyListenerRef listener) { // Even though Response was already checked by WKBundlePagePolicyClient, the check did not include plugins // so we have to re-check again. - WKRetainPtr<WKStringRef> wkMIMEType(AdoptWK, WKURLResponseCopyMIMEType(response)); - if (WKFrameCanShowMIMEType(frame, wkMIMEType.get())) { + if (WKNavigationResponseCanShowMIMEType(navigationResponse)) { WKFramePolicyListenerUse(listener); return; } - WKFramePolicyListenerIgnore(listener); + if (m_shouldDownloadUndisplayableMIMETypes) + WKFramePolicyListenerDownload(listener); + else + WKFramePolicyListenerIgnore(listener); +} + +void TestController::didNavigateWithNavigationData(WKContextRef, WKPageRef, WKNavigationDataRef navigationData, WKFrameRef frame, const void* clientInfo) +{ + static_cast<TestController*>(const_cast<void*>(clientInfo))->didNavigateWithNavigationData(navigationData, frame); } +void TestController::didNavigateWithNavigationData(WKNavigationDataRef navigationData, WKFrameRef) +{ + if (m_state != RunningTest) + return; + + if (!m_shouldLogHistoryClientCallbacks) + return; + + // URL + WKRetainPtr<WKURLRef> urlWK = adoptWK(WKNavigationDataCopyURL(navigationData)); + WKRetainPtr<WKStringRef> urlStringWK = adoptWK(WKURLCopyString(urlWK.get())); + // Title + WKRetainPtr<WKStringRef> titleWK = adoptWK(WKNavigationDataCopyTitle(navigationData)); + // HTTP method + WKRetainPtr<WKURLRequestRef> requestWK = adoptWK(WKNavigationDataCopyOriginalRequest(navigationData)); + WKRetainPtr<WKStringRef> methodWK = adoptWK(WKURLRequestCopyHTTPMethod(requestWK.get())); + + // FIXME: Determine whether the navigation was successful / a client redirect rather than hard-coding the message here. + m_currentInvocation->outputText(String::format("WebView navigated to url \"%s\" with title \"%s\" with HTTP equivalent method \"%s\". The navigation was successful and was not a client redirect.\n", + toSTD(urlStringWK).c_str(), toSTD(titleWK).c_str(), toSTD(methodWK).c_str())); +} + +void TestController::didPerformClientRedirect(WKContextRef, WKPageRef, WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef frame, const void* clientInfo) +{ + static_cast<TestController*>(const_cast<void*>(clientInfo))->didPerformClientRedirect(sourceURL, destinationURL, frame); +} + +void TestController::didPerformClientRedirect(WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef) +{ + if (m_state != RunningTest) + return; + + if (!m_shouldLogHistoryClientCallbacks) + return; + + WKRetainPtr<WKStringRef> sourceStringWK = adoptWK(WKURLCopyString(sourceURL)); + WKRetainPtr<WKStringRef> destinationStringWK = adoptWK(WKURLCopyString(destinationURL)); + + m_currentInvocation->outputText(String::format("WebView performed a client redirect from \"%s\" to \"%s\".\n", toSTD(sourceStringWK).c_str(), toSTD(destinationStringWK).c_str())); +} + +void TestController::didPerformServerRedirect(WKContextRef, WKPageRef, WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef frame, const void* clientInfo) +{ + static_cast<TestController*>(const_cast<void*>(clientInfo))->didPerformServerRedirect(sourceURL, destinationURL, frame); +} + +void TestController::didPerformServerRedirect(WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef) +{ + if (m_state != RunningTest) + return; + + if (!m_shouldLogHistoryClientCallbacks) + return; + + WKRetainPtr<WKStringRef> sourceStringWK = adoptWK(WKURLCopyString(sourceURL)); + WKRetainPtr<WKStringRef> destinationStringWK = adoptWK(WKURLCopyString(destinationURL)); + + m_currentInvocation->outputText(String::format("WebView performed a server redirect from \"%s\" to \"%s\".\n", toSTD(sourceStringWK).c_str(), toSTD(destinationStringWK).c_str())); +} + +void TestController::didUpdateHistoryTitle(WKContextRef, WKPageRef, WKStringRef title, WKURLRef URL, WKFrameRef frame, const void* clientInfo) +{ + static_cast<TestController*>(const_cast<void*>(clientInfo))->didUpdateHistoryTitle(title, URL, frame); +} + +void TestController::didUpdateHistoryTitle(WKStringRef title, WKURLRef URL, WKFrameRef) +{ + if (m_state != RunningTest) + return; + + if (!m_shouldLogHistoryClientCallbacks) + return; + + WKRetainPtr<WKStringRef> urlStringWK(AdoptWK, WKURLCopyString(URL)); + m_currentInvocation->outputText(String::format("WebView updated the title for history URL \"%s\" to \"%s\".\n", toSTD(urlStringWK).c_str(), toSTD(title).c_str())); +} + +void TestController::setNavigationGesturesEnabled(bool value) +{ + m_mainWebView->setNavigationGesturesEnabled(value); +} + +void TestController::setIgnoresViewportScaleLimits(bool ignoresViewportScaleLimits) +{ + WKPageSetIgnoresViewportScaleLimits(m_mainWebView->page(), ignoresViewportScaleLimits); +} + +void TestController::setStatisticsPrevalentResource(WKStringRef hostName, bool value) +{ + WKResourceLoadStatisticsManagerSetPrevalentResource(hostName, value); +} + +bool TestController::isStatisticsPrevalentResource(WKStringRef hostName) +{ + return WKResourceLoadStatisticsManagerIsPrevalentResource(hostName); +} + +void TestController::setStatisticsHasHadUserInteraction(WKStringRef hostName, bool value) +{ + WKResourceLoadStatisticsManagerSetHasHadUserInteraction(hostName, value); +} + +bool TestController::isStatisticsHasHadUserInteraction(WKStringRef hostName) +{ + return WKResourceLoadStatisticsManagerIsHasHadUserInteraction(hostName); +} + +void TestController::setStatisticsTimeToLiveUserInteraction(double seconds) +{ + WKResourceLoadStatisticsManagerSetTimeToLiveUserInteraction(seconds); +} + +void TestController::statisticsFireDataModificationHandler() +{ + WKResourceLoadStatisticsManagerFireDataModificationHandler(); +} + +void TestController::setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool value) +{ + WKResourceLoadStatisticsManagerSetNotifyPagesWhenDataRecordsWereScanned(value); +} + +void TestController::setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(bool value) +{ + WKResourceLoadStatisticsManagerSetShouldClassifyResourcesBeforeDataRecordsRemoval(value); +} + +void TestController::setStatisticsMinimumTimeBetweeenDataRecordsRemoval(double seconds) +{ + WKResourceLoadStatisticsManagerSetMinimumTimeBetweeenDataRecordsRemoval(seconds); +} +void TestController::statisticsResetToConsistentState() +{ + WKResourceLoadStatisticsManagerResetToConsistentState(); +} + +#if !PLATFORM(COCOA) +void TestController::platformWillRunTest(const TestInvocation&) +{ +} + +void TestController::platformCreateWebView(WKPageConfigurationRef configuration, const TestOptions& options) +{ + m_mainWebView = std::make_unique<PlatformWebView>(configuration, options); +} + +PlatformWebView* TestController::platformCreateOtherPage(PlatformWebView* parentView, WKPageConfigurationRef configuration, const TestOptions& options) +{ + return new PlatformWebView(configuration, options); +} + +WKContextRef TestController::platformAdjustContext(WKContextRef context, WKContextConfigurationRef contextConfiguration) +{ + return context; +} + +void TestController::platformResetStateToConsistentValues() +{ + +} + +unsigned TestController::imageCountInGeneralPasteboard() const +{ + return 0; +} + +#endif + } // namespace WTR diff --git a/Tools/WebKitTestRunner/TestController.h b/Tools/WebKitTestRunner/TestController.h index 10031a176..cc753c297 100644 --- a/Tools/WebKitTestRunner/TestController.h +++ b/Tools/WebKitTestRunner/TestController.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010, 2015-2017 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,22 +29,28 @@ #include "GeolocationProviderMock.h" #include "WebNotificationProvider.h" #include "WorkQueueManager.h" -#include <WebKit2/WKRetainPtr.h> +#include <WebKit/WKRetainPtr.h> #include <string> #include <vector> -#include <wtf/OwnPtr.h> +#include <wtf/HashMap.h> #include <wtf/Vector.h> +#include <wtf/text/StringHash.h> + +OBJC_CLASS WKWebViewConfiguration; namespace WTR { class TestInvocation; +class OriginSettings; class PlatformWebView; class EventSenderProxy; +struct TestCommand; +struct TestOptions; // FIXME: Rename this TestRunner? class TestController { public: - static TestController& shared(); + static TestController& singleton(); static const unsigned viewWidth; static const unsigned viewHeight; @@ -52,29 +58,32 @@ public: static const unsigned w3cSVGViewWidth; static const unsigned w3cSVGViewHeight; + static const double defaultShortTimeout; + static const double noTimeout; + TestController(int argc, const char* argv[]); ~TestController(); bool verbose() const { return m_verbose; } - WKStringRef injectedBundlePath() { return m_injectedBundlePath.get(); } - WKStringRef testPluginDirectory() { return m_testPluginDirectory.get(); } + WKStringRef injectedBundlePath() const { return m_injectedBundlePath.get(); } + WKStringRef testPluginDirectory() const { return m_testPluginDirectory.get(); } PlatformWebView* mainWebView() { return m_mainWebView.get(); } WKContextRef context() { return m_context.get(); } EventSenderProxy* eventSenderProxy() { return m_eventSenderProxy.get(); } - void ensureViewSupportsOptions(WKDictionaryRef options); bool shouldUseRemoteLayerTree() const { return m_shouldUseRemoteLayerTree; } // Runs the run loop until `done` is true or the timeout elapses. - enum TimeoutDuration { ShortTimeout, LongTimeout, NoTimeout, CustomTimeout }; bool useWaitToDumpWatchdogTimer() { return m_useWaitToDumpWatchdogTimer; } - void runUntil(bool& done, TimeoutDuration); + void runUntil(bool& done, double timeoutSeconds); void notifyDone(); - int getCustomTimeout(); + bool shouldShowWebView() const { return m_shouldShowWebView; } + bool usingServerMode() const { return m_usingServerMode; } + void configureViewForTest(const TestInvocation&); bool beforeUnloadReturnValue() const { return m_beforeUnloadReturnValue; } void setBeforeUnloadReturnValue(bool value) { m_beforeUnloadReturnValue = value; } @@ -86,27 +95,75 @@ public: void setMockGeolocationPosition(double latitude, double longitude, double accuracy, bool providesAltitude, double altitude, bool providesAltitudeAccuracy, double altitudeAccuracy, bool providesHeading, double heading, bool providesSpeed, double speed); void setMockGeolocationPositionUnavailableError(WKStringRef errorMessage); void handleGeolocationPermissionRequest(WKGeolocationPermissionRequestRef); + bool isGeolocationProviderActive() const; + + // MediaStream. + String saltForOrigin(WKFrameRef, String); + void getUserMediaInfoForOrigin(WKFrameRef, WKStringRef originKey, bool&, WKRetainPtr<WKStringRef>&); + WKStringRef getUserMediaSaltForOrigin(WKFrameRef, WKStringRef originKey); + void setUserMediaPermission(bool); + void setUserMediaPersistentPermissionForOrigin(bool, WKStringRef userMediaDocumentOriginString, WKStringRef topLevelDocumentOriginString); + void handleUserMediaPermissionRequest(WKFrameRef, WKSecurityOriginRef, WKSecurityOriginRef, WKUserMediaPermissionRequestRef); + void handleCheckOfUserMediaPermissionForOrigin(WKFrameRef, WKSecurityOriginRef, WKSecurityOriginRef, const WKUserMediaPermissionCheckRef&); + OriginSettings& settingsForOrigin(const String&); + unsigned userMediaPermissionRequestCountForOrigin(WKStringRef userMediaDocumentOriginString, WKStringRef topLevelDocumentOriginString); + void resetUserMediaPermissionRequestCountForOrigin(WKStringRef userMediaDocumentOriginString, WKStringRef topLevelDocumentOriginString); // Policy delegate. void setCustomPolicyDelegate(bool enabled, bool permissive); // Page Visibility. - void setVisibilityState(WKPageVisibilityState, bool isInitialState); + void setHidden(bool); + + unsigned imageCountInGeneralPasteboard() const; + + bool resetStateToConsistentValues(const TestOptions&); + void resetPreferencesToConsistentValues(const TestOptions&); - bool resetStateToConsistentValues(); - void resetPreferencesToConsistentValues(); + void terminateWebContentProcess(); + void reattachPageToWebProcess(); + + static const char* webProcessName(); + static const char* networkProcessName(); + static const char* databaseProcessName(); WorkQueueManager& workQueueManager() { return m_workQueueManager; } + void setRejectsProtectionSpaceAndContinueForAuthenticationChallenges(bool value) { m_rejectsProtectionSpaceAndContinueForAuthenticationChallenges = value; } void setHandlesAuthenticationChallenges(bool value) { m_handlesAuthenticationChallenges = value; } void setAuthenticationUsername(String username) { m_authenticationUsername = username; } void setAuthenticationPassword(String password) { m_authenticationPassword = password; } void setBlockAllPlugins(bool shouldBlock) { m_shouldBlockAllPlugins = shouldBlock; } + void setShouldLogHistoryClientCallbacks(bool shouldLog) { m_shouldLogHistoryClientCallbacks = shouldLog; } + void setShouldLogCanAuthenticateAgainstProtectionSpace(bool shouldLog) { m_shouldLogCanAuthenticateAgainstProtectionSpace = shouldLog; } + + bool isCurrentInvocation(TestInvocation* invocation) const { return invocation == m_currentInvocation.get(); } + + void setShouldDecideNavigationPolicyAfterDelay(bool value) { m_shouldDecideNavigationPolicyAfterDelay = value; } + + void setNavigationGesturesEnabled(bool value); + void setIgnoresViewportScaleLimits(bool); + + void setShouldDownloadUndisplayableMIMETypes(bool value) { m_shouldDownloadUndisplayableMIMETypes = value; } + + void setStatisticsPrevalentResource(WKStringRef hostName, bool value); + bool isStatisticsPrevalentResource(WKStringRef hostName); + void setStatisticsHasHadUserInteraction(WKStringRef hostName, bool value); + bool isStatisticsHasHadUserInteraction(WKStringRef hostName); + void setStatisticsTimeToLiveUserInteraction(double seconds); + void statisticsFireDataModificationHandler(); + void setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool); + void setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(bool); + void setStatisticsMinimumTimeBetweeenDataRecordsRemoval(double); + void statisticsResetToConsistentState(); + private: + WKRetainPtr<WKPageConfigurationRef> generatePageConfiguration(WKContextConfigurationRef); + WKRetainPtr<WKContextConfigurationRef> generateContextConfiguration() const; void initialize(int argc, const char* argv[]); - void createWebViewWithOptions(WKDictionaryRef); + void createWebViewWithOptions(const TestOptions&); void run(); void runTestingServerLoop(); @@ -114,34 +171,87 @@ private: void platformInitialize(); void platformDestroy(); + WKContextRef platformAdjustContext(WKContextRef, WKContextConfigurationRef); void platformInitializeContext(); + void platformCreateWebView(WKPageConfigurationRef, const TestOptions&); + static PlatformWebView* platformCreateOtherPage(PlatformWebView* parentView, WKPageConfigurationRef, const TestOptions&); + void platformResetPreferencesToConsistentValues(); + void platformResetStateToConsistentValues(); +#if PLATFORM(COCOA) + void cocoaResetStateToConsistentValues(); +#endif + void platformConfigureViewForTest(const TestInvocation&); + void platformWillRunTest(const TestInvocation&); void platformRunUntil(bool& done, double timeout); void platformDidCommitLoadForFrame(WKPageRef, WKFrameRef); + WKPreferencesRef platformPreferences(); void initializeInjectedBundlePath(); void initializeTestPluginDirectory(); + void ensureViewSupportsOptionsForTest(const TestInvocation&); + TestOptions testOptionsForTest(const TestCommand&) const; + void updatePlatformSpecificTestOptionsForTest(TestOptions&, const std::string& pathOrURL) const; + + void updateWebViewSizeForTest(const TestInvocation&); + void updateWindowScaleForTest(PlatformWebView*, const TestInvocation&); + void decidePolicyForGeolocationPermissionRequestIfPossible(); + void decidePolicyForUserMediaPermissionRequestIfPossible(); // WKContextInjectedBundleClient static void didReceiveMessageFromInjectedBundle(WKContextRef, WKStringRef messageName, WKTypeRef messageBody, const void*); static void didReceiveSynchronousMessageFromInjectedBundle(WKContextRef, WKStringRef messageName, WKTypeRef messageBody, WKTypeRef* returnData, const void*); + static WKTypeRef getInjectedBundleInitializationUserData(WKContextRef, const void *clientInfo); + + // WKPageInjectedBundleClient + static void didReceivePageMessageFromInjectedBundle(WKPageRef, WKStringRef messageName, WKTypeRef messageBody, const void*); + static void didReceiveSynchronousPageMessageFromInjectedBundle(WKPageRef, WKStringRef messageName, WKTypeRef messageBody, WKTypeRef* returnData, const void*); void didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody); WKRetainPtr<WKTypeRef> didReceiveSynchronousMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody); + WKRetainPtr<WKTypeRef> getInjectedBundleInitializationUserData(); void didReceiveKeyDownMessageFromInjectedBundle(WKDictionaryRef messageBodyDictionary, bool synchronous); - // WKPageLoaderClient - static void didCommitLoadForFrame(WKPageRef, WKFrameRef, WKTypeRef userData, const void*); - void didCommitLoadForFrame(WKPageRef, WKFrameRef); + // WKContextClient + static void networkProcessDidCrash(WKContextRef, const void*); + void networkProcessDidCrash(); + static void databaseProcessDidCrash(WKContextRef, const void*); + void databaseProcessDidCrash(); - static void didFinishLoadForFrame(WKPageRef, WKFrameRef, WKTypeRef userData, const void*); - void didFinishLoadForFrame(WKPageRef, WKFrameRef); + // WKPageNavigationClient + static void didCommitNavigation(WKPageRef, WKNavigationRef, WKTypeRef userData, const void*); + void didCommitNavigation(WKPageRef, WKNavigationRef); + static void didFinishNavigation(WKPageRef, WKNavigationRef, WKTypeRef userData, const void*); + void didFinishNavigation(WKPageRef, WKNavigationRef); + + + // WKContextDownloadClient + static void downloadDidStart(WKContextRef, WKDownloadRef, const void*); + void downloadDidStart(WKContextRef, WKDownloadRef); + static WKStringRef decideDestinationWithSuggestedFilename(WKContextRef, WKDownloadRef, WKStringRef filename, bool* allowOverwrite, const void *clientInfo); + WKStringRef decideDestinationWithSuggestedFilename(WKContextRef, WKDownloadRef, WKStringRef filename, bool*& allowOverwrite); + static void downloadDidFinish(WKContextRef, WKDownloadRef, const void*); + void downloadDidFinish(WKContextRef, WKDownloadRef); + static void downloadDidFail(WKContextRef, WKDownloadRef, WKErrorRef, const void*); + void downloadDidFail(WKContextRef, WKDownloadRef, WKErrorRef); + static void downloadDidCancel(WKContextRef, WKDownloadRef, const void*); + void downloadDidCancel(WKContextRef, WKDownloadRef); + static void processDidCrash(WKPageRef, const void* clientInfo); void processDidCrash(); - static WKPluginLoadPolicy pluginLoadPolicy(WKPageRef, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription, const void* clientInfo); - WKPluginLoadPolicy pluginLoadPolicy(WKPageRef, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription); + static void didBeginNavigationGesture(WKPageRef, const void*); + static void willEndNavigationGesture(WKPageRef, WKBackForwardListItemRef, const void*); + static void didEndNavigationGesture(WKPageRef, WKBackForwardListItemRef, const void*); + static void didRemoveNavigationGestureSnapshot(WKPageRef, const void*); + void didBeginNavigationGesture(WKPageRef); + void willEndNavigationGesture(WKPageRef, WKBackForwardListItemRef); + void didEndNavigationGesture(WKPageRef, WKBackForwardListItemRef); + void didRemoveNavigationGestureSnapshot(WKPageRef); + + static WKPluginLoadPolicy decidePolicyForPluginLoad(WKPageRef, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription, const void* clientInfo); + WKPluginLoadPolicy decidePolicyForPluginLoad(WKPageRef, WKPluginLoadPolicy currentPluginLoadPolicy, WKDictionaryRef pluginInformation, WKStringRef* unavailabilityDescription); static void decidePolicyForNotificationPermissionRequest(WKPageRef, WKSecurityOriginRef, WKNotificationPermissionRequestRef, const void*); @@ -149,40 +259,54 @@ private: static void unavailablePluginButtonClicked(WKPageRef, WKPluginUnavailabilityReason, WKDictionaryRef, const void*); - static void didReceiveAuthenticationChallengeInFrame(WKPageRef, WKFrameRef, WKAuthenticationChallengeRef, const void *clientInfo); - void didReceiveAuthenticationChallengeInFrame(WKPageRef, WKFrameRef, WKAuthenticationChallengeRef); + static bool canAuthenticateAgainstProtectionSpace(WKPageRef, WKProtectionSpaceRef, const void*); + bool canAuthenticateAgainstProtectionSpace(WKPageRef, WKProtectionSpaceRef); + + static void didReceiveAuthenticationChallenge(WKPageRef, WKAuthenticationChallengeRef, const void*); + void didReceiveAuthenticationChallenge(WKPageRef, WKAuthenticationChallengeRef); - // WKPagePolicyClient - static void decidePolicyForNavigationAction(WKPageRef, WKFrameRef, WKFrameNavigationType, WKEventModifiers, WKEventMouseButton, WKFrameRef, WKURLRequestRef, WKFramePolicyListenerRef, WKTypeRef, const void*); + static void decidePolicyForNavigationAction(WKPageRef, WKNavigationActionRef, WKFramePolicyListenerRef, WKTypeRef, const void*); void decidePolicyForNavigationAction(WKFramePolicyListenerRef); - static void decidePolicyForResponse(WKPageRef, WKFrameRef, WKURLResponseRef, WKURLRequestRef, bool canShowMIMEType, WKFramePolicyListenerRef, WKTypeRef, const void*); - void decidePolicyForResponse(WKFrameRef, WKURLResponseRef, WKFramePolicyListenerRef); + static void decidePolicyForNavigationResponse(WKPageRef, WKNavigationResponseRef, WKFramePolicyListenerRef, WKTypeRef, const void*); + void decidePolicyForNavigationResponse(WKNavigationResponseRef, WKFramePolicyListenerRef); + + // WKContextHistoryClient + static void didNavigateWithNavigationData(WKContextRef, WKPageRef, WKNavigationDataRef, WKFrameRef, const void*); + void didNavigateWithNavigationData(WKNavigationDataRef, WKFrameRef); + + static void didPerformClientRedirect(WKContextRef, WKPageRef, WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef, const void*); + void didPerformClientRedirect(WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef); - static WKPageRef createOtherPage(WKPageRef oldPage, WKURLRequestRef, WKDictionaryRef, WKEventModifiers, WKEventMouseButton, const void*); + static void didPerformServerRedirect(WKContextRef, WKPageRef, WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef, const void*); + void didPerformServerRedirect(WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef); + + static void didUpdateHistoryTitle(WKContextRef, WKPageRef, WKStringRef title, WKURLRef, WKFrameRef, const void*); + void didUpdateHistoryTitle(WKStringRef title, WKURLRef, WKFrameRef); + + static WKPageRef createOtherPage(WKPageRef, WKPageConfigurationRef, WKNavigationActionRef, WKWindowFeaturesRef, const void*); static void runModal(WKPageRef, const void* clientInfo); static void runModal(PlatformWebView*); - void setHidden(bool); - static const char* libraryPathForTesting(); static const char* platformLibraryPathForTesting(); - OwnPtr<TestInvocation> m_currentInvocation; + std::unique_ptr<TestInvocation> m_currentInvocation; - bool m_verbose; - bool m_printSeparators; - bool m_usingServerMode; - bool m_gcBetweenTests; - bool m_shouldDumpPixelsForAllTests; + bool m_verbose { false }; + bool m_printSeparators { false }; + bool m_usingServerMode { false }; + bool m_gcBetweenTests { false }; + bool m_shouldDumpPixelsForAllTests { false }; std::vector<std::string> m_paths; + std::vector<std::string> m_allowedHosts; WKRetainPtr<WKStringRef> m_injectedBundlePath; WKRetainPtr<WKStringRef> m_testPluginDirectory; WebNotificationProvider m_webNotificationProvider; - OwnPtr<PlatformWebView> m_mainWebView; + std::unique_ptr<PlatformWebView> m_mainWebView; WKRetainPtr<WKContextRef> m_context; WKRetainPtr<WKPageGroupRef> m_pageGroup; @@ -191,45 +315,65 @@ private: Resetting, RunningTest }; - State m_state; - bool m_doneResetting; + State m_state { Initial }; + bool m_doneResetting { false }; - double m_longTimeout; - double m_shortTimeout; - double m_noTimeout; - bool m_useWaitToDumpWatchdogTimer; - bool m_forceNoTimeout; + bool m_useWaitToDumpWatchdogTimer { true }; + bool m_forceNoTimeout { false }; - int m_timeout; - - bool m_didPrintWebProcessCrashedMessage; - bool m_shouldExitWhenWebProcessCrashes; + bool m_didPrintWebProcessCrashedMessage { false }; + bool m_shouldExitWhenWebProcessCrashes { true }; - bool m_beforeUnloadReturnValue; + bool m_beforeUnloadReturnValue { true }; - OwnPtr<GeolocationProviderMock> m_geolocationProvider; + std::unique_ptr<GeolocationProviderMock> m_geolocationProvider; Vector<WKRetainPtr<WKGeolocationPermissionRequestRef> > m_geolocationPermissionRequests; - bool m_isGeolocationPermissionSet; - bool m_isGeolocationPermissionAllowed; + bool m_isGeolocationPermissionSet { false }; + bool m_isGeolocationPermissionAllowed { false }; + + HashMap<String, RefPtr<OriginSettings>> m_cachedUserMediaPermissions; + + typedef Vector<std::pair<String, WKRetainPtr<WKUserMediaPermissionRequestRef>>> PermissionRequestList; + PermissionRequestList m_userMediaPermissionRequests; + + bool m_isUserMediaPermissionSet { false }; + bool m_isUserMediaPermissionAllowed { false }; - bool m_policyDelegateEnabled; - bool m_policyDelegatePermissive; + bool m_policyDelegateEnabled { false }; + bool m_policyDelegatePermissive { false }; + bool m_shouldDownloadUndisplayableMIMETypes { false }; - bool m_handlesAuthenticationChallenges; + bool m_rejectsProtectionSpaceAndContinueForAuthenticationChallenges { false }; + bool m_handlesAuthenticationChallenges { false }; String m_authenticationUsername; String m_authenticationPassword; - bool m_shouldBlockAllPlugins; + bool m_shouldBlockAllPlugins { false }; - bool m_forceComplexText; - bool m_shouldUseAcceleratedDrawing; - bool m_shouldUseRemoteLayerTree; + bool m_forceComplexText { false }; + bool m_shouldUseAcceleratedDrawing { false }; + bool m_shouldUseRemoteLayerTree { false }; - OwnPtr<EventSenderProxy> m_eventSenderProxy; + bool m_shouldLogCanAuthenticateAgainstProtectionSpace { false }; + bool m_shouldLogHistoryClientCallbacks { false }; + bool m_shouldShowWebView { false }; + + bool m_shouldDecideNavigationPolicyAfterDelay { false }; + + std::unique_ptr<EventSenderProxy> m_eventSenderProxy; WorkQueueManager m_workQueueManager; }; +struct TestCommand { + std::string pathOrURL; + std::string absolutePath; + bool shouldDumpPixels { false }; + std::string expectedPixelHash; + int timeout { 0 }; + bool dumpJSConsoleLogInStdErr { false }; +}; + } // namespace WTR #endif // TestController_h diff --git a/Tools/WebKitTestRunner/TestInvocation.cpp b/Tools/WebKitTestRunner/TestInvocation.cpp index cac2ba8b8..b0a0442cc 100644 --- a/Tools/WebKitTestRunner/TestInvocation.cpp +++ b/Tools/WebKitTestRunner/TestInvocation.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010, 2011, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2010-2017 Apple Inc. All rights reserved. * Copyright (C) 2012 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,196 +30,144 @@ #include "PlatformWebView.h" #include "StringFunctions.h" #include "TestController.h" +#include "UIScriptController.h" +#include "WebCoreTestSupport.h" +#include <WebKit/WKContextPrivate.h> +#include <WebKit/WKCookieManager.h> +#include <WebKit/WKData.h> +#include <WebKit/WKDictionary.h> +#include <WebKit/WKInspector.h> +#include <WebKit/WKPagePrivate.h> +#include <WebKit/WKRetainPtr.h> +#include <WebKit/WKWebsiteDataStoreRef.h> #include <climits> #include <cstdio> -#include <WebKit2/WKContextPrivate.h> -#include <WebKit2/WKData.h> -#include <WebKit2/WKDictionary.h> -#include <WebKit2/WKInspector.h> -#include <WebKit2/WKRetainPtr.h> -#include <wtf/PassOwnPtr.h> +#include <unistd.h> #include <wtf/StdLibExtras.h> #include <wtf/text/CString.h> -#if PLATFORM(MAC) -#if !PLATFORM(IOS) +#if PLATFORM(MAC) && !PLATFORM(IOS) #include <Carbon/Carbon.h> #endif -#include <WebKit2/WKPagePrivateMac.h> -#endif -#include <unistd.h> // For getcwd. +#if PLATFORM(COCOA) +#include <WebKit/WKPagePrivateMac.h> +#endif +using namespace JSC; using namespace WebKit; using namespace std; namespace WTR { -static WKURLRef createWKURL(const char* pathOrURL) +TestInvocation::TestInvocation(WKURLRef url, const TestOptions& options) + : m_options(options) + , m_url(url) { - if (strstr(pathOrURL, "http://") || strstr(pathOrURL, "https://") || strstr(pathOrURL, "file://")) - return WKURLCreateWithUTF8CString(pathOrURL); + WKRetainPtr<WKStringRef> urlString = adoptWK(WKURLCopyString(m_url.get())); - // Creating from filesytem path. - size_t length = strlen(pathOrURL); - if (!length) - return 0; - - const char separator = '/'; - bool isAbsolutePath = pathOrURL[0] == separator; - const char* filePrefix = "file://"; - static const size_t prefixLength = strlen(filePrefix); - - std::unique_ptr<char[]> buffer; - if (isAbsolutePath) { - buffer = std::make_unique<char[]>(prefixLength + length + 1); - strcpy(buffer.get(), filePrefix); - strcpy(buffer.get() + prefixLength, pathOrURL); - } else { - buffer = std::make_unique<char[]>(prefixLength + PATH_MAX + length + 2); // 1 for the separator - strcpy(buffer.get(), filePrefix); - if (!getcwd(buffer.get() + prefixLength, PATH_MAX)) - return 0; - size_t numCharacters = strlen(buffer.get()); - buffer[numCharacters] = separator; - strcpy(buffer.get() + numCharacters + 1, pathOrURL); - } - - return WKURLCreateWithUTF8CString(buffer.get()); -} + size_t stringLength = WKStringGetLength(urlString.get()); -TestInvocation::TestInvocation(const std::string& pathOrURL) - : m_url(AdoptWK, createWKURL(pathOrURL.c_str())) - , m_pathOrURL(pathOrURL) - , m_dumpPixels(false) - , m_timeout(0) - , m_gotInitialResponse(false) - , m_gotFinalMessage(false) - , m_gotRepaint(false) - , m_error(false) - , m_webProcessIsUnresponsive(false) -{ + Vector<char> urlVector; + urlVector.resize(stringLength + 1); + + WKStringGetUTF8CString(urlString.get(), urlVector.data(), stringLength + 1); + + m_urlString = String(urlVector.data(), stringLength); } TestInvocation::~TestInvocation() { + if (m_pendingUIScriptInvocationData) + m_pendingUIScriptInvocationData->testInvocation = nullptr; } -void TestInvocation::setIsPixelTest(const std::string& expectedPixelHash) +WKURLRef TestInvocation::url() const { - m_dumpPixels = true; - m_expectedPixelHash = expectedPixelHash; + return m_url.get(); } -void TestInvocation::setCustomTimeout(int timeout) +bool TestInvocation::urlContains(const char* searchString) const { - m_timeout = timeout; + return m_urlString.contains(searchString, false); } -static void sizeWebViewForCurrentTest(const char* pathOrURL) +void TestInvocation::setIsPixelTest(const std::string& expectedPixelHash) { - bool isSVGW3CTest = strstr(pathOrURL, "svg/W3C-SVG-1.1") || strstr(pathOrURL, "svg\\W3C-SVG-1.1"); - - if (isSVGW3CTest) - TestController::shared().mainWebView()->resizeTo(TestController::w3cSVGViewWidth, TestController::w3cSVGViewHeight); - else - TestController::shared().mainWebView()->resizeTo(TestController::viewWidth, TestController::viewHeight); + m_dumpPixels = true; + m_expectedPixelHash = expectedPixelHash; } -static bool shouldLogFrameLoadDelegates(const char* pathOrURL) +double TestInvocation::shortTimeout() const { - return strstr(pathOrURL, "loading/"); -} + if (!m_timeout) { + // Running WKTR directly, without webkitpy. + return TestController::defaultShortTimeout; + } -#if ENABLE(INSPECTOR) && !PLATFORM(IOS) -static bool shouldOpenWebInspector(const char* pathOrURL) -{ - return strstr(pathOrURL, "inspector/") || strstr(pathOrURL, "inspector\\"); + // This is not exactly correct for the way short timeout is used - it should not depend on whether a test is "slow", + // but it currently does. There is no way to know what a normal test's timeout is, as webkitpy only passes timeouts + // for each test individually. + // But there shouldn't be any observable negative consequences from this. + return m_timeout / 1000. / 2; } -#endif -#if PLATFORM(MAC) -static bool shouldUseThreadedScrolling(const char* pathOrURL) +bool TestInvocation::shouldLogFrameLoadDelegates() const { - return strstr(pathOrURL, "tiled-drawing/") || strstr(pathOrURL, "tiled-drawing\\"); + return urlContains("loading/"); } -#endif -static void updateThreadedScrollingForCurrentTest(const char* pathOrURL) +bool TestInvocation::shouldLogHistoryClientCallbacks() const { -#if PLATFORM(MAC) - WKRetainPtr<WKMutableDictionaryRef> viewOptions = adoptWK(WKMutableDictionaryCreate()); - WKRetainPtr<WKStringRef> useThreadedScrollingKey = adoptWK(WKStringCreateWithUTF8CString("ThreadedScrolling")); - WKRetainPtr<WKBooleanRef> useThreadedScrollingValue = adoptWK(WKBooleanCreate(shouldUseThreadedScrolling(pathOrURL))); - WKDictionarySetItem(viewOptions.get(), useThreadedScrollingKey.get(), useThreadedScrollingValue.get()); - - WKRetainPtr<WKStringRef> useRemoteLayerTreeKey = adoptWK(WKStringCreateWithUTF8CString("RemoteLayerTree")); - WKRetainPtr<WKBooleanRef> useRemoteLayerTreeValue = adoptWK(WKBooleanCreate(TestController::shared().shouldUseRemoteLayerTree())); - WKDictionarySetItem(viewOptions.get(), useRemoteLayerTreeKey.get(), useRemoteLayerTreeValue.get()); - - TestController::shared().ensureViewSupportsOptions(viewOptions.get()); -#else - UNUSED_PARAM(pathOrURL); -#endif + return urlContains("globalhistory/"); } -static bool shouldUseFixedLayout(const char* pathOrURL) +void TestInvocation::invoke() { -#if ENABLE(CSS_DEVICE_ADAPTATION) - if (strstr(pathOrURL, "device-adapt/") || strstr(pathOrURL, "device-adapt\\")) - return true; -#endif + TestController::singleton().configureViewForTest(*this); -#if USE(TILED_BACKING_STORE) && PLATFORM(EFL) - if (strstr(pathOrURL, "sticky/") || strstr(pathOrURL, "sticky\\")) - return true; -#endif - return false; + WKPageSetAddsVisitedLinks(TestController::singleton().mainWebView()->page(), false); - UNUSED_PARAM(pathOrURL); -} - -static void updateLayoutType(const char* pathOrURL) -{ - WKRetainPtr<WKMutableDictionaryRef> viewOptions = adoptWK(WKMutableDictionaryCreate()); - WKRetainPtr<WKStringRef> useFixedLayoutKey = adoptWK(WKStringCreateWithUTF8CString("UseFixedLayout")); - WKRetainPtr<WKBooleanRef> useFixedLayoutValue = adoptWK(WKBooleanCreate(shouldUseFixedLayout(pathOrURL))); - WKDictionarySetItem(viewOptions.get(), useFixedLayoutKey.get(), useFixedLayoutValue.get()); + m_textOutput.clear(); - TestController::shared().ensureViewSupportsOptions(viewOptions.get()); -} + TestController::singleton().setShouldLogHistoryClientCallbacks(shouldLogHistoryClientCallbacks()); -void TestInvocation::invoke() -{ - TestController::TimeoutDuration timeoutToUse = TestController::LongTimeout; - sizeWebViewForCurrentTest(m_pathOrURL.c_str()); - updateLayoutType(m_pathOrURL.c_str()); - updateThreadedScrollingForCurrentTest(m_pathOrURL.c_str()); + WKCookieManagerSetHTTPCookieAcceptPolicy(WKContextGetCookieManager(TestController::singleton().context()), kWKHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain); - m_textOutput.clear(); + // FIXME: We should clear out visited links here. WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("BeginTest")); WKRetainPtr<WKMutableDictionaryRef> beginTestMessageBody = adoptWK(WKMutableDictionaryCreate()); WKRetainPtr<WKStringRef> dumpFrameLoadDelegatesKey = adoptWK(WKStringCreateWithUTF8CString("DumpFrameLoadDelegates")); - WKRetainPtr<WKBooleanRef> dumpFrameLoadDelegatesValue = adoptWK(WKBooleanCreate(shouldLogFrameLoadDelegates(m_pathOrURL.c_str()))); + WKRetainPtr<WKBooleanRef> dumpFrameLoadDelegatesValue = adoptWK(WKBooleanCreate(shouldLogFrameLoadDelegates())); WKDictionarySetItem(beginTestMessageBody.get(), dumpFrameLoadDelegatesKey.get(), dumpFrameLoadDelegatesValue.get()); + WKRetainPtr<WKStringRef> useFlexibleViewportKey = adoptWK(WKStringCreateWithUTF8CString("UseFlexibleViewport")); + WKRetainPtr<WKBooleanRef> useFlexibleViewportValue = adoptWK(WKBooleanCreate(options().useFlexibleViewport)); + WKDictionarySetItem(beginTestMessageBody.get(), useFlexibleViewportKey.get(), useFlexibleViewportValue.get()); + WKRetainPtr<WKStringRef> dumpPixelsKey = adoptWK(WKStringCreateWithUTF8CString("DumpPixels")); WKRetainPtr<WKBooleanRef> dumpPixelsValue = adoptWK(WKBooleanCreate(m_dumpPixels)); WKDictionarySetItem(beginTestMessageBody.get(), dumpPixelsKey.get(), dumpPixelsValue.get()); WKRetainPtr<WKStringRef> useWaitToDumpWatchdogTimerKey = adoptWK(WKStringCreateWithUTF8CString("UseWaitToDumpWatchdogTimer")); - WKRetainPtr<WKBooleanRef> useWaitToDumpWatchdogTimerValue = adoptWK(WKBooleanCreate(TestController::shared().useWaitToDumpWatchdogTimer())); + WKRetainPtr<WKBooleanRef> useWaitToDumpWatchdogTimerValue = adoptWK(WKBooleanCreate(TestController::singleton().useWaitToDumpWatchdogTimer())); WKDictionarySetItem(beginTestMessageBody.get(), useWaitToDumpWatchdogTimerKey.get(), useWaitToDumpWatchdogTimerValue.get()); WKRetainPtr<WKStringRef> timeoutKey = adoptWK(WKStringCreateWithUTF8CString("Timeout")); WKRetainPtr<WKUInt64Ref> timeoutValue = adoptWK(WKUInt64Create(m_timeout)); WKDictionarySetItem(beginTestMessageBody.get(), timeoutKey.get(), timeoutValue.get()); - WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), beginTestMessageBody.get()); + WKRetainPtr<WKStringRef> dumpJSConsoleLogInStdErrKey = adoptWK(WKStringCreateWithUTF8CString("DumpJSConsoleLogInStdErr")); + WKRetainPtr<WKBooleanRef> dumpJSConsoleLogInStdErrValue = adoptWK(WKBooleanCreate(m_dumpJSConsoleLogInStdErr)); + WKDictionarySetItem(beginTestMessageBody.get(), dumpJSConsoleLogInStdErrKey.get(), dumpJSConsoleLogInStdErrValue.get()); - TestController::shared().runUntil(m_gotInitialResponse, TestController::ShortTimeout); + WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), beginTestMessageBody.get()); + + bool shouldOpenExternalURLs = false; + + TestController::singleton().runUntil(m_gotInitialResponse, shortTimeout()); if (!m_gotInitialResponse) { m_errorMessage = "Timed out waiting for initial response from web process\n"; m_webProcessIsUnresponsive = true; @@ -228,42 +176,29 @@ void TestInvocation::invoke() if (m_error) goto end; -#if ENABLE(INSPECTOR) && !PLATFORM(IOS) - if (shouldOpenWebInspector(m_pathOrURL.c_str())) - WKInspectorShow(WKPageGetInspector(TestController::shared().mainWebView()->page())); -#endif // ENABLE(INSPECTOR) - - WKPageLoadURL(TestController::shared().mainWebView()->page(), m_url.get()); - - if (TestController::shared().useWaitToDumpWatchdogTimer()) { - if (m_timeout > 0) - timeoutToUse = TestController::CustomTimeout; - } else - timeoutToUse = TestController::NoTimeout; - TestController::shared().runUntil(m_gotFinalMessage, timeoutToUse); + WKPageLoadURLWithShouldOpenExternalURLsPolicy(TestController::singleton().mainWebView()->page(), m_url.get(), shouldOpenExternalURLs); - if (!m_gotFinalMessage) { - m_errorMessage = "Timed out waiting for final message from web process\n"; - m_webProcessIsUnresponsive = true; - goto end; - } + TestController::singleton().runUntil(m_gotFinalMessage, TestController::noTimeout); if (m_error) goto end; dumpResults(); end: -#if ENABLE(INSPECTOR) && !PLATFORM(IOS) +#if !PLATFORM(IOS) if (m_gotInitialResponse) - WKInspectorClose(WKPageGetInspector(TestController::shared().mainWebView()->page())); -#endif // ENABLE(INSPECTOR) + WKInspectorClose(WKPageGetInspector(TestController::singleton().mainWebView()->page())); +#endif // !PLATFORM(IOS) if (m_webProcessIsUnresponsive) dumpWebProcessUnresponsiveness(); - else if (!TestController::shared().resetStateToConsistentValues()) { - m_errorMessage = "Timed out loading about:blank before the next test"; - dumpWebProcessUnresponsiveness(); - } + else if (TestController::singleton().resetStateToConsistentValues(m_options)) + return; + + // The process is unresponsive, so let's start a new one. + TestController::singleton().terminateWebContentProcess(); + // Make sure that we have a process, as invoke() will need one to send bundle messages for the next test. + TestController::singleton().reattachPageToWebProcess(); } void TestInvocation::dumpWebProcessUnresponsiveness() @@ -273,17 +208,25 @@ void TestInvocation::dumpWebProcessUnresponsiveness() void TestInvocation::dumpWebProcessUnresponsiveness(const char* errorMessage) { - const char* errorMessageToStderr = 0; -#if PLATFORM(MAC) - char buffer[64]; - pid_t pid = WKPageGetProcessIdentifier(TestController::shared().mainWebView()->page()); - sprintf(buffer, "#PROCESS UNRESPONSIVE - WebProcess (pid %ld)\n", static_cast<long>(pid)); - errorMessageToStderr = buffer; + fprintf(stderr, "%s", errorMessage); + char buffer[1024] = { }; +#if PLATFORM(COCOA) + pid_t pid = WKPageGetProcessIdentifier(TestController::singleton().mainWebView()->page()); + snprintf(buffer, sizeof(buffer), "#PROCESS UNRESPONSIVE - %s (pid %ld)\n", TestController::webProcessName(), static_cast<long>(pid)); #else - errorMessageToStderr = "#PROCESS UNRESPONSIVE - WebProcess"; + snprintf(buffer, sizeof(buffer), "#PROCESS UNRESPONSIVE - %s\n", TestController::webProcessName()); #endif - dump(errorMessage, errorMessageToStderr, true); + dump(errorMessage, buffer, true); + + if (!TestController::singleton().usingServerMode()) + return; + + if (isatty(fileno(stdin)) || isatty(fileno(stderr))) + fputs("Grab an image of the stack, then hit enter...\n", stderr); + + if (!fgets(buffer, sizeof(buffer), stdin) || strcmp(buffer, "#SAMPLE FINISHED\n")) + fprintf(stderr, "Failed receive expected sample response, got:\n\t\"%s\"\nContinuing...\n", buffer); } void TestInvocation::dump(const char* textToStdout, const char* textToStderr, bool seenError) @@ -302,11 +245,17 @@ void TestInvocation::dump(const char* textToStdout, const char* textToStderr, bo fflush(stderr); } -void TestInvocation::forceRepaintDoneCallback(WKErrorRef, void* context) +void TestInvocation::forceRepaintDoneCallback(WKErrorRef error, void* context) { + // The context may not be valid any more, e.g. if WebKit is invalidating callbacks at process exit. + if (error) + return; + TestInvocation* testInvocation = static_cast<TestInvocation*>(context); + RELEASE_ASSERT(TestController::singleton().isCurrentInvocation(testInvocation)); + testInvocation->m_gotRepaint = true; - TestController::shared().notifyDone(); + TestController::singleton().notifyDone(); } void TestInvocation::dumpResults() @@ -316,18 +265,22 @@ void TestInvocation::dumpResults() else dumpAudio(m_audioResult.get()); - if (m_dumpPixels && m_pixelResult) { - if (PlatformWebView::windowSnapshotEnabled()) { + if (m_dumpPixels) { + if (m_pixelResult) + dumpPixelsAndCompareWithExpected(m_pixelResult.get(), m_repaintRects.get(), TestInvocation::SnapshotResultType::WebContents); + else if (m_pixelResultIsPending) { m_gotRepaint = false; - WKPageForceRepaint(TestController::shared().mainWebView()->page(), this, TestInvocation::forceRepaintDoneCallback); - TestController::shared().runUntil(m_gotRepaint, TestController::ShortTimeout); + WKPageForceRepaint(TestController::singleton().mainWebView()->page(), this, TestInvocation::forceRepaintDoneCallback); + TestController::singleton().runUntil(m_gotRepaint, shortTimeout()); if (!m_gotRepaint) { m_errorMessage = "Timed out waiting for pre-pixel dump repaint\n"; m_webProcessIsUnresponsive = true; return; } + + WKRetainPtr<WKImageRef> windowSnapshot = TestController::singleton().mainWebView()->windowSnapshotImage(); + dumpPixelsAndCompareWithExpected(windowSnapshot.get(), m_repaintRects.get(), TestInvocation::SnapshotResultType::WebView); } - dumpPixelsAndCompareWithExpected(m_pixelResult.get(), m_repaintRects.get()); } fputs("#EOF\n", stdout); @@ -374,7 +327,7 @@ void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName m_gotFinalMessage = true; m_error = true; m_errorMessage = "FAIL\n"; - TestController::shared().notifyDone(); + TestController::singleton().notifyDone(); return; } @@ -383,7 +336,7 @@ void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName WKStringRef messageBodyString = static_cast<WKStringRef>(messageBody); if (WKStringIsEqualToUTF8CString(messageBodyString, "BeginTest")) { m_gotInitialResponse = true; - TestController::shared().notifyDone(); + TestController::singleton().notifyDone(); return; } @@ -394,9 +347,15 @@ void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID()); WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody); - WKRetainPtr<WKStringRef> pixelResultKey = adoptWK(WKStringCreateWithUTF8CString("PixelResult")); - m_pixelResult = static_cast<WKImageRef>(WKDictionaryGetItemForKey(messageBodyDictionary, pixelResultKey.get())); - ASSERT(!m_pixelResult || m_dumpPixels); + WKRetainPtr<WKStringRef> pixelResultIsPendingKey = adoptWK(WKStringCreateWithUTF8CString("PixelResultIsPending")); + WKBooleanRef pixelResultIsPending = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, pixelResultIsPendingKey.get())); + m_pixelResultIsPending = WKBooleanGetValue(pixelResultIsPending); + + if (!m_pixelResultIsPending) { + WKRetainPtr<WKStringRef> pixelResultKey = adoptWK(WKStringCreateWithUTF8CString("PixelResult")); + m_pixelResult = static_cast<WKImageRef>(WKDictionaryGetItemForKey(messageBodyDictionary, pixelResultKey.get())); + ASSERT(!m_pixelResult || m_dumpPixels); + } WKRetainPtr<WKStringRef> repaintRectsKey = adoptWK(WKStringCreateWithUTF8CString("RepaintRects")); m_repaintRects = static_cast<WKArrayRef>(WKDictionaryGetItemForKey(messageBodyDictionary, repaintRectsKey.get())); @@ -405,7 +364,7 @@ void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName m_audioResult = static_cast<WKDataRef>(WKDictionaryGetItemForKey(messageBodyDictionary, audioResultKey.get())); m_gotFinalMessage = true; - TestController::shared().notifyDone(); + TestController::singleton().notifyDone(); return; } @@ -416,55 +375,69 @@ void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName return; } + if (WKStringIsEqualToUTF8CString(messageName, "DumpToStdErr")) { + ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID()); + WKStringRef textOutput = static_cast<WKStringRef>(messageBody); + fprintf(stderr, "%s", toWTFString(textOutput).utf8().data()); + return; + } + if (WKStringIsEqualToUTF8CString(messageName, "BeforeUnloadReturnValue")) { ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID()); WKBooleanRef beforeUnloadReturnValue = static_cast<WKBooleanRef>(messageBody); - TestController::shared().setBeforeUnloadReturnValue(WKBooleanGetValue(beforeUnloadReturnValue)); + TestController::singleton().setBeforeUnloadReturnValue(WKBooleanGetValue(beforeUnloadReturnValue)); return; } if (WKStringIsEqualToUTF8CString(messageName, "AddChromeInputField")) { - TestController::shared().mainWebView()->addChromeInputField(); + TestController::singleton().mainWebView()->addChromeInputField(); WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallAddChromeInputFieldCallback")); - WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0); + WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0); return; } if (WKStringIsEqualToUTF8CString(messageName, "RemoveChromeInputField")) { - TestController::shared().mainWebView()->removeChromeInputField(); + TestController::singleton().mainWebView()->removeChromeInputField(); WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallRemoveChromeInputFieldCallback")); - WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0); + WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0); return; } if (WKStringIsEqualToUTF8CString(messageName, "FocusWebView")) { - TestController::shared().mainWebView()->makeWebViewFirstResponder(); + TestController::singleton().mainWebView()->makeWebViewFirstResponder(); WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallFocusWebViewCallback")); - WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0); + WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0); return; } if (WKStringIsEqualToUTF8CString(messageName, "SetBackingScaleFactor")) { ASSERT(WKGetTypeID(messageBody) == WKDoubleGetTypeID()); double backingScaleFactor = WKDoubleGetValue(static_cast<WKDoubleRef>(messageBody)); - WKPageSetCustomBackingScaleFactor(TestController::shared().mainWebView()->page(), backingScaleFactor); + WKPageSetCustomBackingScaleFactor(TestController::singleton().mainWebView()->page(), backingScaleFactor); WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallSetBackingScaleFactorCallback")); - WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0); + WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0); return; } if (WKStringIsEqualToUTF8CString(messageName, "SimulateWebNotificationClick")) { ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID()); uint64_t notificationID = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody)); - TestController::shared().simulateWebNotificationClick(notificationID); + TestController::singleton().simulateWebNotificationClick(notificationID); + return; + } + + if (WKStringIsEqualToUTF8CString(messageName, "SetAddsVisitedLinks")) { + ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID()); + WKBooleanRef enabledWK = static_cast<WKBooleanRef>(messageBody); + WKPageSetAddsVisitedLinks(TestController::singleton().mainWebView()->page(), WKBooleanGetValue(enabledWK)); return; } if (WKStringIsEqualToUTF8CString(messageName, "SetGeolocationPermission")) { ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID()); WKBooleanRef enabledWK = static_cast<WKBooleanRef>(messageBody); - TestController::shared().setGeolocationPermission(WKBooleanGetValue(enabledWK)); + TestController::singleton().setGeolocationPermission(WKBooleanGetValue(enabledWK)); return; } @@ -516,14 +489,60 @@ void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName WKDoubleRef speedWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, speedKeyWK.get())); double speed = WKDoubleGetValue(speedWK); - TestController::shared().setMockGeolocationPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed); + TestController::singleton().setMockGeolocationPosition(latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed); return; } if (WKStringIsEqualToUTF8CString(messageName, "SetMockGeolocationPositionUnavailableError")) { ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID()); WKStringRef errorMessage = static_cast<WKStringRef>(messageBody); - TestController::shared().setMockGeolocationPositionUnavailableError(errorMessage); + TestController::singleton().setMockGeolocationPositionUnavailableError(errorMessage); + return; + } + + if (WKStringIsEqualToUTF8CString(messageName, "SetUserMediaPermission")) { + ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID()); + WKBooleanRef enabledWK = static_cast<WKBooleanRef>(messageBody); + TestController::singleton().setUserMediaPermission(WKBooleanGetValue(enabledWK)); + return; + } + + if (WKStringIsEqualToUTF8CString(messageName, "SetUserMediaPersistentPermissionForOrigin")) { + ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID()); + WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody); + + WKRetainPtr<WKStringRef> permissionKeyWK(AdoptWK, WKStringCreateWithUTF8CString("permission")); + WKBooleanRef permissionWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, permissionKeyWK.get())); + bool permission = WKBooleanGetValue(permissionWK); + + WKRetainPtr<WKStringRef> originKey(AdoptWK, WKStringCreateWithUTF8CString("origin")); + WKStringRef originWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, originKey.get())); + + WKRetainPtr<WKStringRef> parentOriginKey(AdoptWK, WKStringCreateWithUTF8CString("parentOrigin")); + WKStringRef parentOriginWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, parentOriginKey.get())); + + TestController::singleton().setUserMediaPersistentPermissionForOrigin(permission, originWK, parentOriginWK); + return; + } + + if (WKStringIsEqualToUTF8CString(messageName, "ResetUserMediaPermissionRequestCountForOrigin")) { + ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID()); + WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody); + + WKRetainPtr<WKStringRef> originKey(AdoptWK, WKStringCreateWithUTF8CString("origin")); + WKStringRef originWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, originKey.get())); + + WKRetainPtr<WKStringRef> parentOriginKey(AdoptWK, WKStringCreateWithUTF8CString("parentOrigin")); + WKStringRef parentOriginWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, parentOriginKey.get())); + + TestController::singleton().resetUserMediaPermissionRequestCountForOrigin(originWK, parentOriginWK); + return; + } + + if (WKStringIsEqualToUTF8CString(messageName, "SetCacheModel")) { + ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID()); + uint64_t model = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody)); + WKContextSetCacheModel(TestController::singleton().context(), model); return; } @@ -539,30 +558,26 @@ void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName WKBooleanRef permissiveWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, permissiveKeyWK.get())); bool permissive = WKBooleanGetValue(permissiveWK); - TestController::shared().setCustomPolicyDelegate(enabled, permissive); + TestController::singleton().setCustomPolicyDelegate(enabled, permissive); return; } - if (WKStringIsEqualToUTF8CString(messageName, "SetVisibilityState")) { + if (WKStringIsEqualToUTF8CString(messageName, "SetHidden")) { ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID()); WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody); - WKRetainPtr<WKStringRef> visibilityStateKeyWK(AdoptWK, WKStringCreateWithUTF8CString("visibilityState")); - WKUInt64Ref visibilityStateWK = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, visibilityStateKeyWK.get())); - WKPageVisibilityState visibilityState = static_cast<WKPageVisibilityState>(WKUInt64GetValue(visibilityStateWK)); - - WKRetainPtr<WKStringRef> isInitialKeyWK(AdoptWK, WKStringCreateWithUTF8CString("isInitialState")); - WKBooleanRef isInitialWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, isInitialKeyWK.get())); - bool isInitialState = WKBooleanGetValue(isInitialWK); + WKRetainPtr<WKStringRef> isInitialKeyWK(AdoptWK, WKStringCreateWithUTF8CString("hidden")); + WKBooleanRef hiddenWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, isInitialKeyWK.get())); + bool hidden = WKBooleanGetValue(hiddenWK); - TestController::shared().setVisibilityState(visibilityState, isInitialState); + TestController::singleton().setHidden(hidden); return; } if (WKStringIsEqualToUTF8CString(messageName, "ProcessWorkQueue")) { - if (TestController::shared().workQueueManager().processWorkQueue()) { + if (TestController::singleton().workQueueManager().processWorkQueue()) { WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("WorkQueueProcessedCallback")); - WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0); + WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0); } return; } @@ -570,14 +585,14 @@ void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName if (WKStringIsEqualToUTF8CString(messageName, "QueueBackNavigation")) { ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID()); uint64_t stepCount = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody)); - TestController::shared().workQueueManager().queueBackNavigation(stepCount); + TestController::singleton().workQueueManager().queueBackNavigation(stepCount); return; } if (WKStringIsEqualToUTF8CString(messageName, "QueueForwardNavigation")) { ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID()); uint64_t stepCount = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody)); - TestController::shared().workQueueManager().queueForwardNavigation(stepCount); + TestController::singleton().workQueueManager().queueForwardNavigation(stepCount); return; } @@ -591,7 +606,10 @@ void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName WKRetainPtr<WKStringRef> targetKey(AdoptWK, WKStringCreateWithUTF8CString("target")); WKStringRef targetWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(loadDataDictionary, targetKey.get())); - TestController::shared().workQueueManager().queueLoad(toWTFString(urlWK), toWTFString(targetWK)); + WKRetainPtr<WKStringRef> shouldOpenExternalURLsKey(AdoptWK, WKStringCreateWithUTF8CString("shouldOpenExternalURLs")); + WKBooleanRef shouldOpenExternalURLsValueWK = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(loadDataDictionary, shouldOpenExternalURLsKey.get())); + + TestController::singleton().workQueueManager().queueLoad(toWTFString(urlWK), toWTFString(targetWK), WKBooleanGetValue(shouldOpenExternalURLsValueWK)); return; } @@ -608,54 +626,110 @@ void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName WKRetainPtr<WKStringRef> unreachableURLKey(AdoptWK, WKStringCreateWithUTF8CString("unreachableURL")); WKStringRef unreachableURLWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(loadDataDictionary, unreachableURLKey.get())); - TestController::shared().workQueueManager().queueLoadHTMLString(toWTFString(contentWK), baseURLWK ? toWTFString(baseURLWK) : String(), unreachableURLWK ? toWTFString(unreachableURLWK) : String()); + TestController::singleton().workQueueManager().queueLoadHTMLString(toWTFString(contentWK), baseURLWK ? toWTFString(baseURLWK) : String(), unreachableURLWK ? toWTFString(unreachableURLWK) : String()); return; } if (WKStringIsEqualToUTF8CString(messageName, "QueueReload")) { - TestController::shared().workQueueManager().queueReload(); + TestController::singleton().workQueueManager().queueReload(); return; } if (WKStringIsEqualToUTF8CString(messageName, "QueueLoadingScript")) { ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID()); WKStringRef script = static_cast<WKStringRef>(messageBody); - TestController::shared().workQueueManager().queueLoadingScript(toWTFString(script)); + TestController::singleton().workQueueManager().queueLoadingScript(toWTFString(script)); return; } if (WKStringIsEqualToUTF8CString(messageName, "QueueNonLoadingScript")) { ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID()); WKStringRef script = static_cast<WKStringRef>(messageBody); - TestController::shared().workQueueManager().queueNonLoadingScript(toWTFString(script)); + TestController::singleton().workQueueManager().queueNonLoadingScript(toWTFString(script)); + return; + } + + if (WKStringIsEqualToUTF8CString(messageName, "SetRejectsProtectionSpaceAndContinueForAuthenticationChallenges")) { + ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID()); + WKBooleanRef value = static_cast<WKBooleanRef>(messageBody); + TestController::singleton().setRejectsProtectionSpaceAndContinueForAuthenticationChallenges(WKBooleanGetValue(value)); return; } - if (WKStringIsEqualToUTF8CString(messageName, "SetHandlesAuthenticationChallenge")) { + if (WKStringIsEqualToUTF8CString(messageName, "SetHandlesAuthenticationChallenges")) { ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID()); WKBooleanRef value = static_cast<WKBooleanRef>(messageBody); - TestController::shared().setHandlesAuthenticationChallenges(WKBooleanGetValue(value)); + TestController::singleton().setHandlesAuthenticationChallenges(WKBooleanGetValue(value)); + return; + } + + if (WKStringIsEqualToUTF8CString(messageName, "SetShouldLogCanAuthenticateAgainstProtectionSpace")) { + ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID()); + WKBooleanRef value = static_cast<WKBooleanRef>(messageBody); + TestController::singleton().setShouldLogCanAuthenticateAgainstProtectionSpace(WKBooleanGetValue(value)); return; } if (WKStringIsEqualToUTF8CString(messageName, "SetAuthenticationUsername")) { ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID()); WKStringRef username = static_cast<WKStringRef>(messageBody); - TestController::shared().setAuthenticationUsername(toWTFString(username)); + TestController::singleton().setAuthenticationUsername(toWTFString(username)); return; } if (WKStringIsEqualToUTF8CString(messageName, "SetAuthenticationPassword")) { ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID()); WKStringRef password = static_cast<WKStringRef>(messageBody); - TestController::shared().setAuthenticationPassword(toWTFString(password)); + TestController::singleton().setAuthenticationPassword(toWTFString(password)); return; } if (WKStringIsEqualToUTF8CString(messageName, "SetBlockAllPlugins")) { ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID()); WKBooleanRef shouldBlock = static_cast<WKBooleanRef>(messageBody); - TestController::shared().setBlockAllPlugins(WKBooleanGetValue(shouldBlock)); + TestController::singleton().setBlockAllPlugins(WKBooleanGetValue(shouldBlock)); + return; + } + + if (WKStringIsEqualToUTF8CString(messageName, "SetShouldDecideNavigationPolicyAfterDelay")) { + ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID()); + WKBooleanRef value = static_cast<WKBooleanRef>(messageBody); + TestController::singleton().setShouldDecideNavigationPolicyAfterDelay(WKBooleanGetValue(value)); + return; + } + + if (WKStringIsEqualToUTF8CString(messageName, "SetNavigationGesturesEnabled")) { + ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID()); + WKBooleanRef value = static_cast<WKBooleanRef>(messageBody); + TestController::singleton().setNavigationGesturesEnabled(WKBooleanGetValue(value)); + return; + } + + if (WKStringIsEqualToUTF8CString(messageName, "SetIgnoresViewportScaleLimits")) { + ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID()); + WKBooleanRef value = static_cast<WKBooleanRef>(messageBody); + TestController::singleton().setIgnoresViewportScaleLimits(WKBooleanGetValue(value)); + return; + } + + if (WKStringIsEqualToUTF8CString(messageName, "SetShouldDownloadUndisplayableMIMETypes")) { + ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID()); + WKBooleanRef value = static_cast<WKBooleanRef>(messageBody); + TestController::singleton().setShouldDownloadUndisplayableMIMETypes(WKBooleanGetValue(value)); + return; + } + + if (WKStringIsEqualToUTF8CString(messageName, "RunUIProcessScript")) { + WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody); + WKRetainPtr<WKStringRef> scriptKey(AdoptWK, WKStringCreateWithUTF8CString("Script")); + WKRetainPtr<WKStringRef> callbackIDKey(AdoptWK, WKStringCreateWithUTF8CString("CallbackID")); + + UIScriptInvocationData* invocationData = new UIScriptInvocationData(); + invocationData->testInvocation = this; + invocationData->callbackID = (unsigned)WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, callbackIDKey.get()))); + invocationData->scriptString = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, scriptKey.get())); + m_pendingUIScriptInvocationData = invocationData; + WKPageCallAfterNextPresentationUpdate(TestController::singleton().mainWebView()->page(), invocationData, runUISideScriptAfterUpdateCallback); return; } @@ -667,12 +741,32 @@ WKRetainPtr<WKTypeRef> TestInvocation::didReceiveSynchronousMessageFromInjectedB if (WKStringIsEqualToUTF8CString(messageName, "SetWindowIsKey")) { ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID()); WKBooleanRef isKeyValue = static_cast<WKBooleanRef>(messageBody); - TestController::shared().mainWebView()->setWindowIsKey(WKBooleanGetValue(isKeyValue)); - return 0; + TestController::singleton().mainWebView()->setWindowIsKey(WKBooleanGetValue(isKeyValue)); + return nullptr; + } + + if (WKStringIsEqualToUTF8CString(messageName, "SetViewSize")) { + ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID()); + + WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody); + WKRetainPtr<WKStringRef> widthKey(AdoptWK, WKStringCreateWithUTF8CString("width")); + WKRetainPtr<WKStringRef> heightKey(AdoptWK, WKStringCreateWithUTF8CString("height")); + + WKDoubleRef widthWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, widthKey.get())); + WKDoubleRef heightWK = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, heightKey.get())); + + TestController::singleton().mainWebView()->resizeTo(WKDoubleGetValue(widthWK), WKDoubleGetValue(heightWK)); + return nullptr; + } + + if (WKStringIsEqualToUTF8CString(messageName, "IsGeolocationClientActive")) { + bool isActive = TestController::singleton().isGeolocationProviderActive(); + WKRetainPtr<WKTypeRef> result(AdoptWK, WKBooleanCreate(isActive)); + return result; } if (WKStringIsEqualToUTF8CString(messageName, "IsWorkQueueEmpty")) { - bool isEmpty = TestController::shared().workQueueManager().isWorkQueueEmpty(); + bool isEmpty = TestController::singleton().workQueueManager().isWorkQueueEmpty(); WKRetainPtr<WKTypeRef> result(AdoptWK, WKBooleanCreate(isEmpty)); return result; } @@ -685,8 +779,234 @@ WKRetainPtr<WKTypeRef> TestInvocation::didReceiveSynchronousMessageFromInjectedB #endif return result; } + + if (WKStringIsEqualToUTF8CString(messageName, "SetAlwaysAcceptCookies")) { + WKBooleanRef accept = static_cast<WKBooleanRef>(messageBody); + WKHTTPCookieAcceptPolicy policy = WKBooleanGetValue(accept) ? kWKHTTPCookieAcceptPolicyAlways : kWKHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain; + // FIXME: This updates the policy in WebProcess and in NetworkProcess asynchronously, which might break some tests' expectations. + WKCookieManagerSetHTTPCookieAcceptPolicy(WKContextGetCookieManager(TestController::singleton().context()), policy); + return nullptr; + } + + if (WKStringIsEqualToUTF8CString(messageName, "ImageCountInGeneralPasteboard")) { + unsigned count = TestController::singleton().imageCountInGeneralPasteboard(); + WKRetainPtr<WKUInt64Ref> result(AdoptWK, WKUInt64Create(count)); + return result; + } + + if (WKStringIsEqualToUTF8CString(messageName, "DeleteAllIndexedDatabases")) { + WKWebsiteDataStoreRemoveAllIndexedDatabases(WKContextGetWebsiteDataStore(TestController::singleton().context())); + return nullptr; + } + +#if PLATFORM(MAC) + if (WKStringIsEqualToUTF8CString(messageName, "ConnectMockGamepad")) { + ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID()); + + uint64_t index = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody)); + WebCoreTestSupport::connectMockGamepad(index); + + return nullptr; + } + + if (WKStringIsEqualToUTF8CString(messageName, "DisconnectMockGamepad")) { + ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID()); + + uint64_t index = WKUInt64GetValue(static_cast<WKUInt64Ref>(messageBody)); + WebCoreTestSupport::disconnectMockGamepad(index); + + return nullptr; + } + + if (WKStringIsEqualToUTF8CString(messageName, "SetMockGamepadDetails")) { + ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID()); + + WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody); + WKRetainPtr<WKStringRef> gamepadIndexKey(AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex")); + WKRetainPtr<WKStringRef> gamepadIDKey(AdoptWK, WKStringCreateWithUTF8CString("GamepadID")); + WKRetainPtr<WKStringRef> axisCountKey(AdoptWK, WKStringCreateWithUTF8CString("AxisCount")); + WKRetainPtr<WKStringRef> buttonCountKey(AdoptWK, WKStringCreateWithUTF8CString("ButtonCount")); + + WKUInt64Ref gamepadIndex = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, gamepadIndexKey.get())); + WKStringRef gamepadID = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, gamepadIDKey.get())); + WKUInt64Ref axisCount = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, axisCountKey.get())); + WKUInt64Ref buttonCount = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, buttonCountKey.get())); + + WebCoreTestSupport::setMockGamepadDetails(WKUInt64GetValue(gamepadIndex), toWTFString(gamepadID), WKUInt64GetValue(axisCount), WKUInt64GetValue(buttonCount)); + return nullptr; + } + + if (WKStringIsEqualToUTF8CString(messageName, "SetMockGamepadAxisValue")) { + ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID()); + + WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody); + WKRetainPtr<WKStringRef> gamepadIndexKey(AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex")); + WKRetainPtr<WKStringRef> axisIndexKey(AdoptWK, WKStringCreateWithUTF8CString("AxisIndex")); + WKRetainPtr<WKStringRef> valueKey(AdoptWK, WKStringCreateWithUTF8CString("Value")); + + WKUInt64Ref gamepadIndex = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, gamepadIndexKey.get())); + WKUInt64Ref axisIndex = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, axisIndexKey.get())); + WKDoubleRef value = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, valueKey.get())); + + WebCoreTestSupport::setMockGamepadAxisValue(WKUInt64GetValue(gamepadIndex), WKUInt64GetValue(axisIndex), WKDoubleGetValue(value)); + + return nullptr; + } + + if (WKStringIsEqualToUTF8CString(messageName, "SetMockGamepadButtonValue")) { + ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID()); + + WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody); + WKRetainPtr<WKStringRef> gamepadIndexKey(AdoptWK, WKStringCreateWithUTF8CString("GamepadIndex")); + WKRetainPtr<WKStringRef> buttonIndexKey(AdoptWK, WKStringCreateWithUTF8CString("ButtonIndex")); + WKRetainPtr<WKStringRef> valueKey(AdoptWK, WKStringCreateWithUTF8CString("Value")); + + WKUInt64Ref gamepadIndex = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, gamepadIndexKey.get())); + WKUInt64Ref buttonIndex = static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, buttonIndexKey.get())); + WKDoubleRef value = static_cast<WKDoubleRef>(WKDictionaryGetItemForKey(messageBodyDictionary, valueKey.get())); + + WebCoreTestSupport::setMockGamepadButtonValue(WKUInt64GetValue(gamepadIndex), WKUInt64GetValue(buttonIndex), WKDoubleGetValue(value)); + + return nullptr; + } +#endif // PLATFORM(MAC) + + if (WKStringIsEqualToUTF8CString(messageName, "UserMediaPermissionRequestCountForOrigin")) { + ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID()); + WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody); + + WKRetainPtr<WKStringRef> originKey(AdoptWK, WKStringCreateWithUTF8CString("origin")); + WKStringRef originWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, originKey.get())); + + WKRetainPtr<WKStringRef> parentOriginKey(AdoptWK, WKStringCreateWithUTF8CString("parentOrigin")); + WKStringRef parentOriginWK = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, parentOriginKey.get())); + + unsigned count = TestController::singleton().userMediaPermissionRequestCountForOrigin(originWK, parentOriginWK); + WKRetainPtr<WKUInt64Ref> result(AdoptWK, WKUInt64Create(count)); + return result; + } + + if (WKStringIsEqualToUTF8CString(messageName, "SetStatisticsPrevalentResource")) { + ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID()); + + WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody); + WKRetainPtr<WKStringRef> hostNameKey(AdoptWK, WKStringCreateWithUTF8CString("HostName")); + WKRetainPtr<WKStringRef> valueKey(AdoptWK, WKStringCreateWithUTF8CString("Value")); + + WKStringRef hostName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, hostNameKey.get())); + WKBooleanRef value = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, valueKey.get())); + + TestController::singleton().setStatisticsPrevalentResource(hostName, WKBooleanGetValue(value)); + return nullptr; + } + + if (WKStringIsEqualToUTF8CString(messageName, "IsStatisticsPrevalentResource")) { + ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID()); + + WKStringRef hostName = static_cast<WKStringRef>(messageBody); + bool isPrevalent = TestController::singleton().isStatisticsPrevalentResource(hostName); + WKRetainPtr<WKTypeRef> result(AdoptWK, WKBooleanCreate(isPrevalent)); + return result; + } + + if (WKStringIsEqualToUTF8CString(messageName, "SetStatisticsHasHadUserInteraction")) { + ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID()); + + WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody); + WKRetainPtr<WKStringRef> hostNameKey(AdoptWK, WKStringCreateWithUTF8CString("HostName")); + WKRetainPtr<WKStringRef> valueKey(AdoptWK, WKStringCreateWithUTF8CString("Value")); + + WKStringRef hostName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, hostNameKey.get())); + WKBooleanRef value = static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, valueKey.get())); + + TestController::singleton().setStatisticsHasHadUserInteraction(hostName, WKBooleanGetValue(value)); + return nullptr; + } + + if (WKStringIsEqualToUTF8CString(messageName, "IsStatisticsHasHadUserInteraction")) { + ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID()); + + WKStringRef hostName = static_cast<WKStringRef>(messageBody); + bool hasHadUserInteraction = TestController::singleton().isStatisticsHasHadUserInteraction(hostName); + WKRetainPtr<WKTypeRef> result(AdoptWK, WKBooleanCreate(hasHadUserInteraction)); + return result; + } + + if (WKStringIsEqualToUTF8CString(messageName, "SetStatisticsTimeToLiveUserInteraction")) { + ASSERT(WKGetTypeID(messageBody) == WKDoubleGetTypeID()); + WKDoubleRef seconds = static_cast<WKDoubleRef>(messageBody); + TestController::singleton().setStatisticsTimeToLiveUserInteraction(WKDoubleGetValue(seconds)); + return nullptr; + } + + if (WKStringIsEqualToUTF8CString(messageName, "StatisticsFireDataModificationHandler")) { + TestController::singleton().statisticsFireDataModificationHandler(); + return nullptr; + } + + if (WKStringIsEqualToUTF8CString(messageName, "StatisticsNotifyPagesWhenDataRecordsWereScanned")) { + ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID()); + WKBooleanRef value = static_cast<WKBooleanRef>(messageBody); + TestController::singleton().setStatisticsNotifyPagesWhenDataRecordsWereScanned(WKBooleanGetValue(value)); + return nullptr; + } + + if (WKStringIsEqualToUTF8CString(messageName, "StatisticsShouldClassifyResourcesBeforeDataRecordsRemoval")) { + ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID()); + WKBooleanRef value = static_cast<WKBooleanRef>(messageBody); + TestController::singleton().setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(WKBooleanGetValue(value)); + return nullptr; + } + + if (WKStringIsEqualToUTF8CString(messageName, "SetStatisticsMinimumTimeBetweeenDataRecordsRemoval")) { + ASSERT(WKGetTypeID(messageBody) == WKDoubleGetTypeID()); + WKDoubleRef seconds = static_cast<WKDoubleRef>(messageBody); + TestController::singleton().setStatisticsMinimumTimeBetweeenDataRecordsRemoval(WKDoubleGetValue(seconds)); + return nullptr; + } + + if (WKStringIsEqualToUTF8CString(messageName, "StatisticsResetToConsistentState")) { + TestController::singleton().statisticsResetToConsistentState(); + return nullptr; + } + ASSERT_NOT_REACHED(); - return 0; + return nullptr; +} + +void TestInvocation::runUISideScriptAfterUpdateCallback(WKErrorRef, void* context) +{ + UIScriptInvocationData* data = static_cast<UIScriptInvocationData*>(context); + if (TestInvocation* invocation = data->testInvocation) { + RELEASE_ASSERT(TestController::singleton().isCurrentInvocation(invocation)); + invocation->runUISideScript(data->scriptString.get(), data->callbackID); + } + delete data; +} + +void TestInvocation::runUISideScript(WKStringRef script, unsigned scriptCallbackID) +{ + m_pendingUIScriptInvocationData = nullptr; + + if (!m_UIScriptContext) + m_UIScriptContext = std::make_unique<UIScriptContext>(*this); + + m_UIScriptContext->runUIScript(toWTFString(script), scriptCallbackID); +} + +void TestInvocation::uiScriptDidComplete(const String& result, unsigned scriptCallbackID) +{ + WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallUISideScriptCallback")); + + WKRetainPtr<WKMutableDictionaryRef> messageBody(AdoptWK, WKMutableDictionaryCreate()); + WKRetainPtr<WKStringRef> resultKey(AdoptWK, WKStringCreateWithUTF8CString("Result")); + WKRetainPtr<WKStringRef> callbackIDKey(AdoptWK, WKStringCreateWithUTF8CString("CallbackID")); + WKRetainPtr<WKUInt64Ref> callbackIDValue = adoptWK(WKUInt64Create(scriptCallbackID)); + + WKDictionarySetItem(messageBody.get(), resultKey.get(), toWK(result).get()); + WKDictionarySetItem(messageBody.get(), callbackIDKey.get(), callbackIDValue.get()); + + WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), messageBody.get()); } void TestInvocation::outputText(const WTF::String& text) @@ -694,4 +1014,34 @@ void TestInvocation::outputText(const WTF::String& text) m_textOutput.append(text); } +void TestInvocation::didBeginSwipe() +{ + WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallDidBeginSwipeCallback")); + WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0); +} + +void TestInvocation::willEndSwipe() +{ + WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallWillEndSwipeCallback")); + WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0); +} + +void TestInvocation::didEndSwipe() +{ + WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallDidEndSwipeCallback")); + WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0); +} + +void TestInvocation::didRemoveSwipeSnapshot() +{ + WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("CallDidRemoveSwipeSnapshotCallback")); + WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0); +} + +void TestInvocation::notifyDownloadDone() +{ + WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("NotifyDownloadDone")); + WKPagePostMessageToInjectedBundle(TestController::singleton().mainWebView()->page(), messageName.get(), 0); +} + } // namespace WTR diff --git a/Tools/WebKitTestRunner/TestInvocation.h b/Tools/WebKitTestRunner/TestInvocation.h index a32678135..df5885c7e 100644 --- a/Tools/WebKitTestRunner/TestInvocation.h +++ b/Tools/WebKitTestRunner/TestInvocation.h @@ -26,23 +26,35 @@ #ifndef TestInvocation_h #define TestInvocation_h +#include "JSWrappable.h" +#include "TestOptions.h" +#include "UIScriptContext.h" +#include <WebKit/WKRetainPtr.h> #include <string> -#include <WebKit2/WKRetainPtr.h> #include <wtf/Noncopyable.h> -#include <wtf/OwnPtr.h> #include <wtf/text/StringBuilder.h> namespace WTR { -class TestInvocation { +class TestInvocation : public UIScriptContextDelegate { WTF_MAKE_NONCOPYABLE(TestInvocation); public: - explicit TestInvocation(const std::string& pathOrURL); + explicit TestInvocation(WKURLRef, const TestOptions&); ~TestInvocation(); + WKURLRef url() const; + bool urlContains(const char*) const; + + const TestOptions& options() const { return m_options; } + void setIsPixelTest(const std::string& expectedPixelHash); - void setCustomTimeout(int duration); + // Milliseconds + void setCustomTimeout(int duration) { m_timeout = duration; } + void setDumpJSConsoleLogInStdErr(bool value) { m_dumpJSConsoleLogInStdErr = value; } + + // Seconds + double shortTimeout() const; void invoke(); void didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody); @@ -51,36 +63,66 @@ public: void dumpWebProcessUnresponsiveness(); static void dumpWebProcessUnresponsiveness(const char* errorMessage); void outputText(const WTF::String&); + + void didBeginSwipe(); + void willEndSwipe(); + void didEndSwipe(); + void didRemoveSwipeSnapshot(); + + void notifyDownloadDone(); + private: void dumpResults(); static void dump(const char* textToStdout, const char* textToStderr = 0, bool seenError = false); - void dumpPixelsAndCompareWithExpected(WKImageRef, WKArrayRef repaintRects); + enum class SnapshotResultType { WebView, WebContents }; + void dumpPixelsAndCompareWithExpected(WKImageRef, WKArrayRef repaintRects, SnapshotResultType); void dumpAudio(WKDataRef); bool compareActualHashToExpectedAndDumpResults(const char[33]); static void forceRepaintDoneCallback(WKErrorRef, void* context); + + struct UIScriptInvocationData { + unsigned callbackID; + WebKit::WKRetainPtr<WKStringRef> scriptString; + TestInvocation* testInvocation; + }; + static void runUISideScriptAfterUpdateCallback(WKErrorRef, void* context); - WKRetainPtr<WKURLRef> m_url; - std::string m_pathOrURL; + bool shouldLogFrameLoadDelegates() const; + bool shouldLogHistoryClientCallbacks() const; + + void runUISideScript(WKStringRef, unsigned callbackID); + // UIScriptContextDelegate + void uiScriptDidComplete(const String& result, unsigned callbackID) override; + + const TestOptions m_options; - bool m_dumpPixels; + WKRetainPtr<WKURLRef> m_url; + WTF::String m_urlString; + std::string m_expectedPixelHash; - int m_timeout; + int m_timeout { 0 }; + bool m_dumpJSConsoleLogInStdErr { false }; // Invocation state - bool m_gotInitialResponse; - bool m_gotFinalMessage; - bool m_gotRepaint; - bool m_error; + bool m_gotInitialResponse { false }; + bool m_gotFinalMessage { false }; + bool m_gotRepaint { false }; + bool m_error { false }; + + bool m_dumpPixels { false }; + bool m_pixelResultIsPending { false }; + bool m_webProcessIsUnresponsive { false }; StringBuilder m_textOutput; WKRetainPtr<WKDataRef> m_audioResult; WKRetainPtr<WKImageRef> m_pixelResult; WKRetainPtr<WKArrayRef> m_repaintRects; std::string m_errorMessage; - bool m_webProcessIsUnresponsive; - + + std::unique_ptr<UIScriptContext> m_UIScriptContext; + UIScriptInvocationData* m_pendingUIScriptInvocationData { nullptr }; }; } // namespace WTR diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.cpp b/Tools/WebKitTestRunner/TestOptions.cpp index e3cf58c2c..d6e8ab238 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.cpp +++ b/Tools/WebKitTestRunner/TestOptions.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,57 +24,53 @@ */ #include "config.h" -#include "JSWrapper.h" +#include "TestOptions.h" -#include <JavaScriptCore/JSContextRefPrivate.h> +#include <string> +#include <wtf/text/WTFString.h> namespace WTR { -JSValueRef JSWrapper::wrap(JSContextRef context, JSWrappable* object) +static bool pathContains(const std::string& pathOrURL, const char* substring) { - ASSERT_ARG(context, context); - - if (!object) - return JSValueMakeNull(context); - - JSClassRef objectClass = object->wrapperClass(); - ASSERT(objectClass); - JSObjectRef wrapperObject = JSObjectMake(context, objectClass, object); - ASSERT(wrapperObject); + String path(pathOrURL.c_str()); + return path.contains(substring); // Case-insensitive. +} - return wrapperObject; +static bool shouldMakeViewportFlexible(const std::string& pathOrURL) +{ + return pathContains(pathOrURL, "viewport/") && !pathContains(pathOrURL, "visual-viewport/"); } -JSWrappable* JSWrapper::unwrap(JSContextRef context, JSValueRef value) +static bool shouldUseFixedLayout(const std::string& pathOrURL) { - ASSERT_ARG(context, context); - ASSERT_ARG(value, value); - if (!context || !value) - return 0; - return static_cast<JSWrappable*>(JSObjectGetPrivate(JSValueToObject(context, value, 0))); +#if ENABLE(CSS_DEVICE_ADAPTATION) + if (pathContains(pathOrURL, "device-adapt/") || pathContains(pathOrURL, "device-adapt\\")) + return true; +#endif + return false; } -static JSWrappable* unwrapObject(JSObjectRef object) +static bool isSVGTestPath(const std::string& pathOrURL) { - JSWrappable* wrappable = static_cast<JSWrappable*>(JSObjectGetPrivate(object)); - ASSERT(wrappable); - return wrappable; + return pathContains(pathOrURL, "svg/W3C-SVG-1.1") || pathContains(pathOrURL, "svg\\W3C-SVG-1.1"); } -void JSWrapper::initialize(JSContextRef ctx, JSObjectRef object) +static float deviceScaleFactorForTest(const std::string& pathOrURL) { - JSWrappable* wrappable = unwrapObject(object); - if (!wrappable) - return; - wrappable->ref(); + if (pathContains(pathOrURL, "/hidpi-3x-")) + return 3; + if (pathContains(pathOrURL, "/hidpi-")) + return 2; + return 1; } -void JSWrapper::finalize(JSObjectRef object) +TestOptions::TestOptions(const std::string& pathOrURL) + : useFlexibleViewport(shouldMakeViewportFlexible(pathOrURL)) + , useFixedLayout(shouldUseFixedLayout(pathOrURL)) + , isSVGTest(isSVGTestPath(pathOrURL)) + , deviceScaleFactor(deviceScaleFactorForTest(pathOrURL)) { - JSWrappable* wrappable = unwrapObject(object); - if (!wrappable) - return; - wrappable->deref(); } -} // namespace WTR +} diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.h b/Tools/WebKitTestRunner/TestOptions.h index d885801b9..9c665192c 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.h +++ b/Tools/WebKitTestRunner/TestOptions.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,35 +23,36 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSWrapper_h -#define JSWrapper_h +#ifndef TestOptions_h +#define TestOptions_h -#include "JSWrappable.h" -#include <JavaScriptCore/JSRetainPtr.h> +#include <wtf/Vector.h> +#include <wtf/text/WTFString.h> namespace WTR { -// FIXME: If necessary, we can do wrapper caching here. -class JSWrapper { -public: - static JSValueRef wrap(JSContextRef context, JSWrappable* object); - static JSWrappable* unwrap(JSContextRef context, JSValueRef value); - - static void initialize(JSContextRef, JSObjectRef); - static void finalize(JSObjectRef); +struct TestOptions { + bool useThreadedScrolling { false }; + bool useRemoteLayerTree { false }; + bool shouldShowWebView { false }; + bool useFlexibleViewport { false }; + bool useFixedLayout { false }; + bool isSVGTest { false }; + bool useDataDetection { false }; + bool useMockScrollbars { true }; + bool needsSiteSpecificQuirks { false }; + bool ignoresViewportScaleLimits { false }; + bool useCharacterSelectionGranularity { false }; + bool enableIntersectionObserver { false }; + bool enableModernMediaControls { true }; + bool enablePointerLock { false }; + + float deviceScaleFactor { 1 }; + Vector<String> overrideLanguages; + + TestOptions(const std::string& pathOrURL); }; -inline JSValueRef toJS(JSContextRef context, JSWrappable* impl) -{ - return JSWrapper::wrap(context, impl); -} - -inline void setProperty(JSContextRef context, JSObjectRef object, const char* propertyName, JSWrappable* value, JSPropertyAttributes attributes, JSValueRef* exception) -{ - JSRetainPtr<JSStringRef> propertyNameString(Adopt, JSStringCreateWithUTF8CString(propertyName)); - JSObjectSetProperty(context, object, propertyNameString.get(), JSWrapper::wrap(context, value), attributes, exception); } -} // namespace WTR - -#endif // JSWrapper_h +#endif // TestOptions_h diff --git a/Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h b/Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h index dc958c10e..5f989fc54 100644 --- a/Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h +++ b/Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h @@ -27,13 +27,8 @@ #import <Foundation/Foundation.h> #endif -#if defined(BUILDING_GTK__) -#include "autotoolsconfig.h" -#endif /* defined (BUILDING_GTK__) */ - +#include <WebKit/WebKit2_C.h> #include <wtf/Platform.h> -#include <WebKit2/WebKit2_C.h> - /* When C++ exceptions are disabled, the C++ library defines |try| and |catch| * to allow C++ code that expects exceptions to build. These definitions diff --git a/Tools/WebKitTestRunner/WebNotificationProvider.cpp b/Tools/WebKitTestRunner/WebNotificationProvider.cpp index 55064249f..b009b36a3 100644 --- a/Tools/WebKitTestRunner/WebNotificationProvider.cpp +++ b/Tools/WebKitTestRunner/WebNotificationProvider.cpp @@ -26,10 +26,11 @@ #include "config.h" #include "WebNotificationProvider.h" -#include <WebKit2/WKMutableArray.h> -#include <WebKit2/WKNotification.h> -#include <WebKit2/WKNumber.h> -#include <WebKit2/WKSecurityOrigin.h> +#include <WebKit/WKMutableArray.h> +#include <WebKit/WKNotification.h> +#include <WebKit/WKNotificationManager.h> +#include <WebKit/WKNumber.h> +#include <WebKit/WKSecurityOriginRef.h> #include <wtf/Assertions.h> namespace WTR { @@ -65,13 +66,14 @@ WebNotificationProvider::WebNotificationProvider() WebNotificationProvider::~WebNotificationProvider() { - WKNotificationManagerSetProvider(m_notificationManager.get(), 0); + for (auto& manager : m_ownedNotifications) + WKNotificationManagerSetProvider(manager.key.get(), nullptr); } WKNotificationProviderV0 WebNotificationProvider::provider() { WKNotificationProviderV0 notificationProvider = { - { kWKNotificationProviderCurrentVersion, this }, + { 0, this }, WTR::showWebNotification, WTR::closeWebNotification, 0, // didDestroyNotification @@ -83,44 +85,73 @@ WKNotificationProviderV0 WebNotificationProvider::provider() return notificationProvider; } -void WebNotificationProvider::showWebNotification(WKPageRef, WKNotificationRef notification) +void WebNotificationProvider::showWebNotification(WKPageRef page, WKNotificationRef notification) { - if (!m_notificationManager) - return; - + auto context = WKPageGetContext(page); + auto notificationManager = WKContextGetNotificationManager(context); uint64_t id = WKNotificationGetID(notification); - ASSERT(!m_shownNotifications.contains(id)); - m_shownNotifications.add(id); - WKNotificationManagerProviderDidShowNotification(m_notificationManager.get(), WKNotificationGetID(notification)); + ASSERT(m_ownedNotifications.contains(notificationManager)); + auto addResult = m_ownedNotifications.find(notificationManager)->value.add(id); + ASSERT_UNUSED(addResult, addResult.isNewEntry); + auto addResult2 = m_owningManager.set(id, notificationManager); + ASSERT_UNUSED(addResult2, addResult2.isNewEntry); + auto addResult3 = m_localToGlobalNotificationIDMap.add(std::make_pair(page, WKNotificationManagerGetLocalIDForTesting(notificationManager, notification)), id); + ASSERT_UNUSED(addResult3, addResult3.isNewEntry); + + WKNotificationManagerProviderDidShowNotification(notificationManager, id); } -void WebNotificationProvider::closeWebNotification(WKNotificationRef notification) +static void removeGlobalIDFromIDMap(HashMap<std::pair<WKPageRef, uint64_t>, uint64_t>& map, uint64_t id) { - if (!m_notificationManager) - return; + for (auto iter = map.begin(); iter != map.end(); ++iter) { + if (iter->value == id) { + map.remove(iter); + return; + } + } + ASSERT_NOT_REACHED(); +} +void WebNotificationProvider::closeWebNotification(WKNotificationRef notification) +{ uint64_t id = WKNotificationGetID(notification); + ASSERT(m_owningManager.contains(id)); + auto notificationManager = m_owningManager.get(id); + + ASSERT(m_ownedNotifications.contains(notificationManager)); + bool success = m_ownedNotifications.find(notificationManager)->value.remove(id); + ASSERT_UNUSED(success, success); + m_owningManager.remove(id); + + removeGlobalIDFromIDMap(m_localToGlobalNotificationIDMap, id); + WKRetainPtr<WKUInt64Ref> wkID = WKUInt64Create(id); WKRetainPtr<WKMutableArrayRef> array(AdoptWK, WKMutableArrayCreate()); WKArrayAppendItem(array.get(), wkID.get()); - m_shownNotifications.remove(id); - WKNotificationManagerProviderDidCloseNotifications(m_notificationManager.get(), array.get()); + WKNotificationManagerProviderDidCloseNotifications(notificationManager, array.get()); } void WebNotificationProvider::addNotificationManager(WKNotificationManagerRef manager) { - // We assume there is only one for testing. - ASSERT(!m_notificationManager); - m_notificationManager = manager; + m_ownedNotifications.add(manager, HashSet<uint64_t>()); } void WebNotificationProvider::removeNotificationManager(WKNotificationManagerRef manager) { - // We assume there is only one for testing. - ASSERT(m_notificationManager); - ASSERT(m_notificationManager.get() == manager); - m_notificationManager = 0; + auto iterator = m_ownedNotifications.find(manager); + ASSERT(iterator != m_ownedNotifications.end()); + auto toRemove = iterator->value; + WKRetainPtr<WKNotificationManagerRef> guard(manager); + m_ownedNotifications.remove(iterator); + WKRetainPtr<WKMutableArrayRef> array = adoptWK(WKMutableArrayCreate()); + for (uint64_t notificationID : toRemove) { + bool success = m_owningManager.remove(notificationID); + ASSERT_UNUSED(success, success); + removeGlobalIDFromIDMap(m_localToGlobalNotificationIDMap, notificationID); + WKArrayAppendItem(array.get(), adoptWK(WKUInt64Create(notificationID)).get()); + } + WKNotificationManagerProviderDidCloseNotifications(manager, array.get()); } WKDictionaryRef WebNotificationProvider::notificationPermissions() @@ -129,31 +160,28 @@ WKDictionaryRef WebNotificationProvider::notificationPermissions() return WKMutableDictionaryCreate(); } -void WebNotificationProvider::simulateWebNotificationClick(uint64_t notificationID) +void WebNotificationProvider::simulateWebNotificationClick(WKPageRef page, uint64_t notificationID) { - if (!m_notificationManager) - return; - - ASSERT(m_shownNotifications.contains(notificationID)); - WKNotificationManagerProviderDidClickNotification(m_notificationManager.get(), notificationID); + ASSERT(m_localToGlobalNotificationIDMap.contains(std::make_pair(page, notificationID))); + auto globalID = m_localToGlobalNotificationIDMap.get(std::make_pair(page, notificationID)); + ASSERT(m_owningManager.contains(globalID)); + WKNotificationManagerProviderDidClickNotification(m_owningManager.get(globalID), globalID); } void WebNotificationProvider::reset() { - if (!m_notificationManager) { - m_shownNotifications.clear(); - return; + for (auto& notificationPair : m_ownedNotifications) { + if (notificationPair.value.isEmpty()) + continue; + WKRetainPtr<WKMutableArrayRef> array = adoptWK(WKMutableArrayCreate()); + for (uint64_t notificationID : notificationPair.value) + WKArrayAppendItem(array.get(), adoptWK(WKUInt64Create(notificationID)).get()); + + notificationPair.value.clear(); + WKNotificationManagerProviderDidCloseNotifications(notificationPair.key.get(), array.get()); } - - WKRetainPtr<WKMutableArrayRef> array(AdoptWK, WKMutableArrayCreate()); - HashSet<uint64_t>::const_iterator itEnd = m_shownNotifications.end(); - for (HashSet<uint64_t>::const_iterator it = m_shownNotifications.begin(); it != itEnd; ++it) { - WKRetainPtr<WKUInt64Ref> wkID = WKUInt64Create(*it); - WKArrayAppendItem(array.get(), wkID.get()); - } - - m_shownNotifications.clear(); - WKNotificationManagerProviderDidCloseNotifications(m_notificationManager.get(), array.get()); + m_owningManager.clear(); + m_localToGlobalNotificationIDMap.clear(); } } // namespace WTR diff --git a/Tools/WebKitTestRunner/WebNotificationProvider.h b/Tools/WebKitTestRunner/WebNotificationProvider.h index fba2870fc..ccf8b1bce 100644 --- a/Tools/WebKitTestRunner/WebNotificationProvider.h +++ b/Tools/WebKitTestRunner/WebNotificationProvider.h @@ -26,9 +26,10 @@ #ifndef WebNotificationProvider_h #define WebNotificationProvider_h -#include <WebKit2/WKNotificationManager.h> -#include <WebKit2/WKNotificationProvider.h> -#include <WebKit2/WKRetainPtr.h> +#include <WebKit/WKNotificationManager.h> +#include <WebKit/WKNotificationProvider.h> +#include <WebKit/WKRetainPtr.h> +#include <wtf/HashMap.h> #include <wtf/HashSet.h> namespace WTR { @@ -45,12 +46,15 @@ public: void removeNotificationManager(WKNotificationManagerRef); WKDictionaryRef notificationPermissions(); - void simulateWebNotificationClick(uint64_t notificationID); + void simulateWebNotificationClick(WKPageRef, uint64_t notificationID); void reset(); private: - WKRetainPtr<WKNotificationManagerRef> m_notificationManager; - HashSet<uint64_t> m_shownNotifications; + // Inverses of each other. + HashMap<WKRetainPtr<WKNotificationManagerRef>, HashSet<uint64_t>> m_ownedNotifications; + HashMap<uint64_t, WKNotificationManagerRef> m_owningManager; + + HashMap<std::pair<WKPageRef, uint64_t>, uint64_t> m_localToGlobalNotificationIDMap; }; } diff --git a/Tools/WebKitTestRunner/WorkQueueManager.cpp b/Tools/WebKitTestRunner/WorkQueueManager.cpp index e74fa3464..63f491b47 100644 --- a/Tools/WebKitTestRunner/WorkQueueManager.cpp +++ b/Tools/WebKitTestRunner/WorkQueueManager.cpp @@ -28,17 +28,17 @@ #include "PlatformWebView.h" #include "TestController.h" -#include <WebKit2/WKPage.h> -#include <WebKit2/WKRetainPtr.h> +#include <WebKit/WKPage.h> +#include <WebKit/WKPagePrivate.h> +#include <WebKit/WKRetainPtr.h> #include <stdio.h> -#include <wtf/PassOwnPtr.h> #include <wtf/text/CString.h> namespace WTR { static inline WKPageRef mainPage() { - return TestController::shared().mainWebView()->page(); + return TestController::singleton().mainWebView()->page(); } static inline bool goToItemAtIndex(int index) @@ -119,20 +119,21 @@ bool WorkQueueManager::processWorkQueue() { m_processing = false; while (!m_processing && !m_workQueue.isEmpty()) { - OwnPtr<WorkQueueItem> item(m_workQueue.takeFirst()); + std::unique_ptr<WorkQueueItem> item(m_workQueue.takeFirst()); m_processing = (item->invoke() == WorkQueueItem::Loading); } return !m_processing; } -void WorkQueueManager::queueLoad(const String& url, const String& target) +void WorkQueueManager::queueLoad(const String& url, const String& target, bool shouldOpenExternalURLs) { class LoadItem : public WorkQueueItem { public: - LoadItem(const String& url, const String& target) + LoadItem(const String& url, const String& target, bool shouldOpenExternalURLs) : m_url(AdoptWK, WKURLCreateWithUTF8CString(url.utf8().data())) , m_target(target) + , m_shouldOpenExternalURLs(shouldOpenExternalURLs) { } @@ -143,15 +144,16 @@ void WorkQueueManager::queueLoad(const String& url, const String& target) fprintf(stderr, "queueLoad for a specific target is not implemented.\n"); return WorkQueueItem::NonLoading; } - WKPageLoadURL(mainPage(), m_url.get()); + WKPageLoadURLWithShouldOpenExternalURLsPolicy(mainPage(), m_url.get(), m_shouldOpenExternalURLs); return WorkQueueItem::Loading; } WKRetainPtr<WKURLRef> m_url; String m_target; + bool m_shouldOpenExternalURLs; }; - enqueue(new LoadItem(url, target)); + enqueue(new LoadItem(url, target, shouldOpenExternalURLs)); } void WorkQueueManager::queueLoadHTMLString(const String& content, const String& baseURL, const String& unreachableURL) @@ -222,7 +224,7 @@ void WorkQueueManager::enqueue(WorkQueueItem* item) return; } - m_workQueue.append(adoptPtr(item)); + m_workQueue.append(std::unique_ptr<WorkQueueItem>(item)); } } // namespace WTR diff --git a/Tools/WebKitTestRunner/WorkQueueManager.h b/Tools/WebKitTestRunner/WorkQueueManager.h index 21d5ebb88..273d51191 100644 --- a/Tools/WebKitTestRunner/WorkQueueManager.h +++ b/Tools/WebKitTestRunner/WorkQueueManager.h @@ -27,7 +27,6 @@ #define WorkQueueManager_h #include <wtf/Deque.h> -#include <wtf/OwnPtr.h> #include <wtf/text/WTFString.h> namespace WTR { @@ -42,7 +41,7 @@ public: void clearWorkQueue(); bool processWorkQueue(); // Returns 'true' if queue is processed (no new loading is started), returns 'false' otherwise. - void queueLoad(const String& url, const String& target); + void queueLoad(const String& url, const String& target, bool shouldOpenExternalURLs); void queueLoadHTMLString(const String& content, const String& baseURL, const String& unreachableURL); void queueBackNavigation(unsigned howFarBackward); void queueForwardNavigation(unsigned howFarForward); @@ -51,7 +50,7 @@ public: void queueNonLoadingScript(const String& script); private: - typedef Deque<OwnPtr<class WorkQueueItem> > WorkQueue; + typedef Deque<std::unique_ptr<class WorkQueueItem>> WorkQueue; void enqueue(WorkQueueItem*); // Adopts pointer. diff --git a/Tools/WebKitTestRunner/cairo/TestInvocationCairo.cpp b/Tools/WebKitTestRunner/cairo/TestInvocationCairo.cpp index 828e65b1b..376f31986 100644 --- a/Tools/WebKitTestRunner/cairo/TestInvocationCairo.cpp +++ b/Tools/WebKitTestRunner/cairo/TestInvocationCairo.cpp @@ -32,7 +32,7 @@ #include "PixelDumpSupport.h" #include "PlatformWebView.h" #include "TestController.h" -#include <WebKit2/WKImageCairo.h> +#include <WebKit/WKImageCairo.h> #include <cairo/cairo.h> #include <cstdio> #include <wtf/Assertions.h> @@ -106,14 +106,9 @@ static void paintRepaintRectOverlay(cairo_surface_t* surface, WKArrayRef repaint cairo_destroy(context); } -void TestInvocation::dumpPixelsAndCompareWithExpected(WKImageRef wkImage, WKArrayRef repaintRects) +void TestInvocation::dumpPixelsAndCompareWithExpected(WKImageRef image, WKArrayRef repaintRects, SnapshotResultType) { -#if USE(ACCELERATED_COMPOSITING) && PLATFORM(EFL) - UNUSED_PARAM(wkImage); - cairo_surface_t* surface = WKImageCreateCairoSurface(TestController::shared().mainWebView()->windowSnapshotImage().get()); -#else - cairo_surface_t* surface = WKImageCreateCairoSurface(wkImage); -#endif + cairo_surface_t* surface = WKImageCreateCairoSurface(image); if (repaintRects) paintRepaintRectOverlay(surface, repaintRects); diff --git a/Tools/WebKitTestRunner/config.h b/Tools/WebKitTestRunner/config.h new file mode 100644 index 000000000..4042b715b --- /dev/null +++ b/Tools/WebKitTestRunner/config.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#ifndef WebKitTestRunner_config_h +#define WebKitTestRunner_config_h + +#if defined (BUILDING_WITH_CMAKE) +#include "cmakeconfig.h" +#endif + +#include <WebCore/PlatformExportMacros.h> +#include <WebKit/WebKit2_C.h> +#include <wtf/Platform.h> +#include <wtf/ExportMacros.h> +#include <runtime/JSExportMacros.h> + +#endif diff --git a/Tools/WebKitTestRunner/gtk/EventSenderProxyGtk.cpp b/Tools/WebKitTestRunner/gtk/EventSenderProxyGtk.cpp index d25320125..e93caf5aa 100644 --- a/Tools/WebKitTestRunner/gtk/EventSenderProxyGtk.cpp +++ b/Tools/WebKitTestRunner/gtk/EventSenderProxyGtk.cpp @@ -14,7 +14,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -39,7 +39,7 @@ #include <gdk/gdkkeysyms.h> #include <gtk/gtk.h> #include <wtf/StdLibExtras.h> -#include <wtf/gobject/GUniquePtr.h> +#include <wtf/glib/GUniquePtr.h> #include <wtf/text/WTFString.h> namespace WTR { @@ -122,6 +122,8 @@ static guint webkitModifiersToGDKModifiers(WKEventModifiers wkModifiers) modifiers |= GDK_MOD1_MASK; if (wkModifiers & kWKEventModifiersMetaKey) modifiers |= GDK_META_MASK; + if (wkModifiers & kWKEventModifiersCapsLockKey) + modifiers |= GDK_LOCK_MASK; return modifiers; } @@ -162,8 +164,9 @@ void EventSenderProxy::updateClickCountForButton(int button) m_clickButton = button; } -static void dispatchEvent(GdkEvent* event) +void EventSenderProxy::dispatchEvent(GdkEvent* event) { + ASSERT(m_testController->mainWebView()); gtk_main_do_event(event); gdk_event_free(event); } @@ -217,6 +220,18 @@ int getGDKKeySymForKeyRef(WKStringRef keyRef, unsigned location, guint* modifier return GDK_KEY_VoidSymbol; } + if (WKStringIsEqualToUTF8CString(keyRef, "leftControl")) + return GDK_KEY_Control_L; + if (WKStringIsEqualToUTF8CString(keyRef, "rightControl")) + return GDK_KEY_Control_R; + if (WKStringIsEqualToUTF8CString(keyRef, "leftShift")) + return GDK_KEY_Shift_L; + if (WKStringIsEqualToUTF8CString(keyRef, "rightShift")) + return GDK_KEY_Shift_R; + if (WKStringIsEqualToUTF8CString(keyRef, "leftAlt")) + return GDK_KEY_Alt_L; + if (WKStringIsEqualToUTF8CString(keyRef, "rightAlt")) + return GDK_KEY_Alt_R; if (WKStringIsEqualToUTF8CString(keyRef, "leftArrow")) return GDK_KEY_Left; if (WKStringIsEqualToUTF8CString(keyRef, "rightArrow")) @@ -277,6 +292,8 @@ int getGDKKeySymForKeyRef(WKStringRef keyRef, unsigned location, guint* modifier return GDK_KEY_Tab; if (charCode == '\x8') return GDK_KEY_BackSpace; + if (charCode == 0x001B) + return GDK_KEY_Escape; if (WTF::isASCIIUpper(charCode)) *modifiers |= GDK_SHIFT_MASK; @@ -416,7 +433,10 @@ void EventSenderProxy::mouseScrollBy(int horizontal, int vertical) void EventSenderProxy::continuousMouseScrollBy(int horizontal, int vertical, bool paged) { // Gtk+ does not support paged scroll events. - g_return_if_fail(!paged); + if (paged) { + WTFLogAlways("EventSenderProxy::continuousMouseScrollBy not implemented for paged scroll events"); + return; + } GdkEvent* event = gdk_event_new(GDK_SCROLL); event->scroll.x = m_position.x; @@ -433,6 +453,18 @@ void EventSenderProxy::continuousMouseScrollBy(int horizontal, int vertical, boo sendOrQueueEvent(event); } +void EventSenderProxy::mouseScrollByWithWheelAndMomentumPhases(int x, int y, int /*phase*/, int /*momentum*/) +{ + // Gtk+ does not have the concept of wheel gesture phases or momentum. Just relay to + // the mouse wheel handler. + mouseScrollBy(x, y); +} + +void EventSenderProxy::swipeGestureWithWheelAndMomentumPhases(int, int, int, int) +{ + notImplemented(); +} + void EventSenderProxy::leapForward(int milliseconds) { if (m_eventQueue.isEmpty()) @@ -466,6 +498,7 @@ GUniquePtr<GdkEvent> EventSenderProxy::createTouchEvent(GdkEventType eventType, return touchEvent; } +#if ENABLE(TOUCH_EVENTS) void EventSenderProxy::addTouchPoint(int x, int y) { // Touch ID is array index plus one, so 0 is skipped. @@ -556,6 +589,6 @@ void EventSenderProxy::setTouchModifier(WKEventModifiers modifier, bool enable) m_updatedTouchEvents.add(GPOINTER_TO_INT(event->touch.sequence)); } } - +#endif // ENABLE(TOUCH_EVENTS) } // namespace WTR diff --git a/Tools/WebKitTestRunner/gtk/PlatformWebViewGtk.cpp b/Tools/WebKitTestRunner/gtk/PlatformWebViewGtk.cpp index fd6f8466b..eb0a08d74 100644 --- a/Tools/WebKitTestRunner/gtk/PlatformWebViewGtk.cpp +++ b/Tools/WebKitTestRunner/gtk/PlatformWebViewGtk.cpp @@ -28,13 +28,17 @@ #include "config.h" #include "PlatformWebView.h" -#include <WebKit2/WKViewPrivate.h> +#include <WebKit/WKImageCairo.h> +#include <WebKit/WKPageConfigurationRef.h> +#include <WebKit/WKView.h> +#include <WebKit/WKViewPrivate.h> #include <gtk/gtk.h> +#include <wtf/Assertions.h> namespace WTR { -PlatformWebView::PlatformWebView(WKContextRef context, WKPageGroupRef pageGroup, WKPageRef /* relatedPage */, WKDictionaryRef options) - : m_view(WKViewCreate(context, pageGroup)) +PlatformWebView::PlatformWebView(WKPageConfigurationRef configuration, const TestOptions& options) + : m_view(WKViewCreate(configuration)) , m_window(gtk_window_new(GTK_WINDOW_POPUP)) , m_windowIsKey(true) , m_options(options) @@ -42,7 +46,7 @@ PlatformWebView::PlatformWebView(WKContextRef context, WKPageGroupRef pageGroup, gtk_container_add(GTK_CONTAINER(m_window), GTK_WIDGET(m_view)); GtkAllocation size = { 0, 0, 800, 600 }; - gtk_widget_size_allocate(m_window, &size); + gtk_widget_size_allocate(GTK_WIDGET(m_view), &size); gtk_window_resize(GTK_WINDOW(m_window), 800, 600); gtk_widget_show_all(m_window); @@ -55,14 +59,17 @@ PlatformWebView::~PlatformWebView() gtk_widget_destroy(m_window); } -void PlatformWebView::resizeTo(unsigned width, unsigned height) +void PlatformWebView::setWindowIsKey(bool isKey) { - GtkAllocation size = { 0, 0, static_cast<int>(width), static_cast<int>(height) }; - gtk_widget_size_allocate(m_window, &size); - gtk_window_resize(GTK_WINDOW(m_window), width, height); + m_windowIsKey = isKey; +} - while (gtk_events_pending()) - gtk_main_iteration(); +void PlatformWebView::resizeTo(unsigned width, unsigned height, WebViewSizingMode sizingMode) +{ + WKRect frame = windowFrame(); + frame.size.width = width; + frame.size.height = height; + setWindowFrame(frame, sizingMode); } WKPageRef PlatformWebView::page() @@ -79,14 +86,8 @@ void PlatformWebView::focus() WKRect PlatformWebView::windowFrame() { GtkAllocation geometry; -#ifdef GTK_API_VERSION_2 - gint depth; - gdk_window_get_geometry(gtk_widget_get_window(GTK_WIDGET(m_window)), - &geometry.x, &geometry.y, &geometry.width, &geometry.height, &depth); -#else gdk_window_get_geometry(gtk_widget_get_window(GTK_WIDGET(m_window)), &geometry.x, &geometry.y, &geometry.width, &geometry.height); -#endif WKRect frame; frame.origin.x = geometry.x; @@ -96,10 +97,15 @@ WKRect PlatformWebView::windowFrame() return frame; } -void PlatformWebView::setWindowFrame(WKRect frame) +void PlatformWebView::setWindowFrame(WKRect frame, WebViewSizingMode) { - gtk_window_move(GTK_WINDOW(m_window), frame.origin.x, frame.origin.y); - resizeTo(frame.size.width, frame.size.height); + gdk_window_move_resize(gtk_widget_get_window(GTK_WIDGET(m_window)), + frame.origin.x, frame.origin.y, frame.size.width, frame.size.height); + GtkAllocation size = { 0, 0, static_cast<int>(frame.size.width), static_cast<int>(frame.size.height) }; + gtk_widget_size_allocate(GTK_WIDGET(m_view), &size); + + while (gtk_events_pending()) + gtk_main_iteration(); } void PlatformWebView::addChromeInputField() @@ -110,20 +116,65 @@ void PlatformWebView::removeChromeInputField() { } +void PlatformWebView::addToWindow() +{ +} + +void PlatformWebView::removeFromWindow() +{ +} + void PlatformWebView::makeWebViewFirstResponder() { } +void PlatformWebView::changeWindowScaleIfNeeded(float) +{ +} + WKRetainPtr<WKImageRef> PlatformWebView::windowSnapshotImage() { - // FIXME: implement to capture pixels in the UI process, - // which may be necessary to capture things like 3D transforms. - return 0; + int width = gtk_widget_get_allocated_width(GTK_WIDGET(m_view)); + int height = gtk_widget_get_allocated_height(GTK_WIDGET(m_view)); + + while (gtk_events_pending()) + gtk_main_iteration(); + + cairo_surface_t* imageSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + + cairo_t* context = cairo_create(imageSurface); + gtk_widget_draw(GTK_WIDGET(m_view), context); + cairo_destroy(context); + + WKRetainPtr<WKImageRef> wkImage = adoptWK(WKImageCreateFromCairoSurface(imageSurface, 0 /* options */)); + + cairo_surface_destroy(imageSurface); + return wkImage; } void PlatformWebView::didInitializeClients() { } +bool PlatformWebView::viewSupportsOptions(const TestOptions&) const +{ + return true; +} + +void PlatformWebView::dismissAllPopupMenus() +{ + // gtk_menu_popdown doesn't modify the GList of attached menus, so it should + // be safe to walk this list while calling it. + GList* attachedMenusList = gtk_menu_get_for_attach_widget(GTK_WIDGET(m_view)); + g_list_foreach(attachedMenusList, [] (void* data, void*) { + ASSERT(data); + gtk_menu_popdown(GTK_MENU(data)); + }, nullptr); +} + +void PlatformWebView::setNavigationGesturesEnabled(bool) +{ +} + } // namespace WTR diff --git a/Tools/WebKitTestRunner/gtk/TestControllerGtk.cpp b/Tools/WebKitTestRunner/gtk/TestControllerGtk.cpp index d8fb9f728..62d031a87 100644 --- a/Tools/WebKitTestRunner/gtk/TestControllerGtk.cpp +++ b/Tools/WebKitTestRunner/gtk/TestControllerGtk.cpp @@ -27,52 +27,68 @@ #include "config.h" #include "TestController.h" +#include "PlatformWebView.h" #include <gtk/gtk.h> #include <wtf/Platform.h> -#include <wtf/gobject/GUniquePtr.h> +#include <wtf/RunLoop.h> +#include <wtf/glib/GRefPtr.h> +#include <wtf/glib/GUniquePtr.h> #include <wtf/text/WTFString.h> namespace WTR { -static guint gTimeoutSourceId = 0; - -static void cancelTimeout() +static GSource* timeoutSource() { - if (!gTimeoutSourceId) - return; - g_source_remove(gTimeoutSourceId); - gTimeoutSourceId = 0; + static GRefPtr<GSource> source = nullptr; + if (!source) { + source = adoptGRef(g_timeout_source_new(0)); + g_source_set_ready_time(source.get(), -1); + g_source_set_name(source.get(), "[WTR] Test timeout source"); + g_source_set_callback(source.get(), [](gpointer userData) -> gboolean { + g_source_set_ready_time(static_cast<GSource*>(userData), -1); + fprintf(stderr, "FAIL: TestControllerRunLoop timed out.\n"); + RunLoop::main().stop(); + return G_SOURCE_REMOVE; + }, source.get(), nullptr); + g_source_attach(source.get(), nullptr); + } + return source.get(); } void TestController::notifyDone() { - gtk_main_quit(); - cancelTimeout(); + g_source_set_ready_time(timeoutSource(), -1); + RunLoop::main().stop(); } void TestController::platformInitialize() { } -void TestController::platformDestroy() +WKPreferencesRef TestController::platformPreferences() { + return WKPageGroupGetPreferences(m_pageGroup.get()); } -static gboolean timeoutCallback(gpointer) +void TestController::platformDestroy() { - fprintf(stderr, "FAIL: TestControllerRunLoop timed out.\n"); - gtk_main_quit(); - return FALSE; } void TestController::platformRunUntil(bool&, double timeout) { - cancelTimeout(); - if (timeout != m_noTimeout) { - gTimeoutSourceId = g_timeout_add(timeout * 1000, timeoutCallback, 0); - g_source_set_name_by_id(gTimeoutSourceId, "[WebKit] timeoutCallback"); - } - gtk_main(); + if (timeout > 0) { + // FIXME: This conversion is now repeated in several places, it should be moved to a common place in WTF and used everywhere. + auto timeoutDuration = std::chrono::duration<double>(timeout); + auto safeDuration = std::chrono::microseconds::max(); + if (timeoutDuration < safeDuration) + safeDuration = std::chrono::duration_cast<std::chrono::microseconds>(timeoutDuration); + gint64 currentTime = g_get_monotonic_time(); + gint64 targetTime = currentTime + std::min<gint64>(G_MAXINT64 - currentTime, safeDuration.count()); + ASSERT(targetTime >= currentTime); + g_source_set_ready_time(timeoutSource(), targetTime); + } else + g_source_set_ready_time(timeoutSource(), -1); + RunLoop::main().run(); } static char* getEnvironmentVariableAsUTF8String(const char* variableName) @@ -102,9 +118,14 @@ void TestController::platformInitializeContext() { } -void TestController::setHidden(bool) +void TestController::setHidden(bool hidden) { - // FIXME: Need to implement this to test visibilityState. + if (!m_mainWebView) + return; + if (hidden) + gtk_widget_unmap(GTK_WIDGET(m_mainWebView->platformView())); + else + gtk_widget_map(GTK_WIDGET(m_mainWebView->platformView())); } void TestController::runModal(PlatformWebView*) @@ -117,4 +138,20 @@ const char* TestController::platformLibraryPathForTesting() return 0; } +void TestController::platformConfigureViewForTest(const TestInvocation&) +{ + WKPageSetApplicationNameForUserAgent(mainWebView()->page(), WKStringCreateWithUTF8CString("WebKitTestRunnerGTK")); +} + +void TestController::platformResetPreferencesToConsistentValues() +{ + if (!m_mainWebView) + return; + m_mainWebView->dismissAllPopupMenus(); +} + +void TestController::updatePlatformSpecificTestOptionsForTest(TestOptions&, const std::string&) const +{ +} + } // namespace WTR diff --git a/Tools/WebKitTestRunner/gtk/fonts/AHEM____.TTF b/Tools/WebKitTestRunner/gtk/fonts/AHEM____.TTF Binary files differnew file mode 100644 index 000000000..ac81cb031 --- /dev/null +++ b/Tools/WebKitTestRunner/gtk/fonts/AHEM____.TTF diff --git a/Tools/WebKitTestRunner/gtk/fonts/FontWithNoValidEncoding.fon b/Tools/WebKitTestRunner/gtk/fonts/FontWithNoValidEncoding.fon Binary files differnew file mode 100644 index 000000000..8fff7d9c1 --- /dev/null +++ b/Tools/WebKitTestRunner/gtk/fonts/FontWithNoValidEncoding.fon diff --git a/Tools/WebKitTestRunner/gtk/fonts/fonts.conf b/Tools/WebKitTestRunner/gtk/fonts/fonts.conf new file mode 100644 index 000000000..2387e9581 --- /dev/null +++ b/Tools/WebKitTestRunner/gtk/fonts/fonts.conf @@ -0,0 +1,435 @@ +<?xml version="1.0"?> +<!DOCTYPE fontconfig SYSTEM "fonts.dtd"> +<fontconfig> + + <!-- Due to patent (http://freetype.sourceforge.net/patents.html) + issues hinting gives different results depending on the + freetype version of the linux distribution, avoiding hinting + gives more consistent results. When all the distributions + release freetype the 2.4, which enables by default the + hinting method that was patented, we could undo this change + and try the hinting again. --> + <match target="font"> + <edit name="hinting" mode="assign"> + <bool>false</bool> + </edit> + </match> + + <!-- This system may have turned off selection of bitmap fonts, but + we must turn it on again, because we want to be able to test that + bitmap fonts with no valid encodings are *never* selected regardless + of the Fontconfig settings. So force Fontconfig to select our cruddy + bitmap font --> + <selectfont> + <acceptfont> + <pattern> + <patelt name="family"> + <string>FontWithNoValidEncoding</string> + </patelt> + </pattern> + </acceptfont> + </selectfont> + + <!-- The sans-serif font should be Liberation Serif --> + <match target="pattern"> + <test qual="any" name="family"> + <string>serif</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Serif</string> + </edit> + </match> + <match target="pattern"> + <test qual="any" name="family"> + <string>Times</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Serif</string> + </edit> + </match> + <match target="pattern"> + <test qual="any" name="family"> + <string>Times New Roman</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Serif</string> + </edit> + </match> + + <!-- Until we find good fonts to use for cursive and fantasy + just use our serif font. --> + <match target="pattern"> + <test qual="any" name="family"> + <string>cursive</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Serif</string> + </edit> + </match> + <match target="pattern"> + <test qual="any" name="family"> + <string>fantasy</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Serif</string> + </edit> + </match> + + <!-- The sans-serif font should be Liberation Sans --> + <match target="pattern"> + <test qual="any" name="family"> + <string>sans serif</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Sans</string> + </edit> + </match> + <match target="pattern"> + <test qual="any" name="family"> + <string>sans</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Sans</string> + </edit> + </match> + <!-- We need to ensure that layout tests that use "Helvetica" don't + fall back to the default serif font --> + <match target="pattern"> + <test qual="any" name="family"> + <string>Helvetica</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Sans</string> + </edit> + </match> + <match target="pattern"> + <test qual="any" name="family"> + <string>Arial</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Sans</string> + </edit> + </match> + <match target="pattern"> + <test qual="any" name="family"> + <string>Lucida Grande</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Sans</string> + </edit> + </match> + + <!-- The Monospace font should be Liberation Mono --> + <match target="pattern"> + <test qual="any" name="family"> + <string>monospace</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Mono</string> + </edit> + </match> + <match target="pattern"> + <test qual="any" name="family"> + <string>mono</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Mono</string> + </edit> + </match> + <!-- We need to ensure that layout tests that use "Courier", "Courier New", + and "Monaco" (all monospace fonts) don't fall back to the default + serif font --> + <match target="pattern"> + <test qual="any" name="family"> + <string>Courier</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Mono</string> + </edit> + </match> + <match target="pattern"> + <test qual="any" name="family"> + <string>Courier New</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Mono</string> + </edit> + </match> + <match target="pattern"> + <test qual="any" name="family"> + <string>Monaco</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Mono</string> + </edit> + </match> + + <!-- The following hinting specializations are adapted from those in the + Chromium test_shell. We try to duplicate their incredibly thorough + testing here --> + <match target="pattern"> + <test name="family" compare="eq"> + <string>NonAntiAliasedSans</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Sans</string> + </edit> + <edit name="antialias" mode="assign"> + <bool>false</bool> + </edit> + </match> + + <match target="pattern"> + <test name="family" compare="eq"> + <string>SlightHintedSerif</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Serif</string> + </edit> + <edit name="hinting" mode="assign"> + <bool>true</bool> + </edit> + <edit name="hintstyle" mode="assign"> + <const>hintslight</const> + </edit> + </match> + + <match target="pattern"> + <test name="family" compare="eq"> + <string>NonHintedSans</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Sans</string> + </edit> + <!-- These deliberately contradict each other. The 'hinting' preference + should take priority --> + <edit name="hintstyle" mode="assign"> + <const>hintfull</const> + </edit> + <edit name="hinting" mode="assign"> + <bool>false</bool> + </edit> + </match> + + <match target="pattern"> + <test name="family" compare="eq"> + <string>AutohintedSerif</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Serif</string> + </edit> + <edit name="hinting" mode="assign"> + <bool>true</bool> + </edit> + <edit name="autohint" mode="assign"> + <bool>true</bool> + </edit> + <edit name="hintstyle" mode="assign"> + <const>hintmedium</const> + </edit> + </match> + + <match target="pattern"> + <test name="family" compare="eq"> + <string>HintedSerif</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Serif</string> + </edit> + <edit name="hinting" mode="assign"> + <bool>true</bool> + </edit> + <edit name="autohint" mode="assign"> + <bool>false</bool> + </edit> + <edit name="hintstyle" mode="assign"> + <const>hintmedium</const> + </edit> + </match> + + <match target="pattern"> + <test name="family" compare="eq"> + <string>FullAndAutoHintedSerif</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Serif</string> + </edit> + <edit name="hinting" mode="assign"> + <bool>true</bool> + </edit> + <edit name="autohint" mode="assign"> + <bool>true</bool> + </edit> + <edit name="hintstyle" mode="assign"> + <const>hintfull</const> + </edit> + </match> + + <match target="pattern"> + <test name="family" compare="eq"> + <string>SubpixelEnabledSans</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Sans</string> + </edit> + <edit name="rgba" mode="assign"> + <const>rgb</const> + </edit> + </match> + + <match target="pattern"> + <test name="family" compare="eq"> + <string>SubpixelDisabledSans</string> + </test> + <edit name="family" mode="assign"> + <string>Liberation Sans</string> + </edit> + <edit name="rgba" mode="assign"> + <const>none</const> + </edit> + </match> + + <!-- We need to enable simulated bold to for DejaVu Serif to ensure that we interpret + this property correctly in: platform/gtk/fonts/fontconfig-synthetic-bold.html --> + <match target="font"> + <test qual="any" name="family"> + <string>DejaVu Serif</string> + </test> + <test name="weight" compare="less_eq"> + <const>medium</const> + </test> + <test target="pattern" name="weight" compare="more"> + <const>medium</const> + </test> + <edit name="embolden" mode="assign"> + <bool>true</bool> + </edit> + <edit name="weight" mode="assign"> + <const>bold</const> + </edit> + </match> + + <!-- We need to enable simulated oblique to for DejaVu Serif to ensure that we interpret + this property correctly in: platform/gtk/fonts/fontconfig-synthetic-oblique.html --> + <match target="font"> + <test qual="any" name="family"> + <string>DejaVu Serif</string> + </test> + <test name="slant"> + <const>roman</const> + </test> + <test target="pattern" name="slant" compare="not_eq"> + <const>roman</const> + </test> + <edit name="matrix" mode="assign"> + <times> + <name>matrix</name> + <matrix><double>1</double><double>0.2</double> + <double>0</double><double>1</double> + </matrix> + </times> + </edit> + <edit name="slant" mode="assign"> + <const>oblique</const> + </edit> + <edit name="embeddedbitmap" mode="assign"> + <bool>false</bool> + </edit> + </match> + + <!-- These fonts should be treated as identical by CSS font fallback. --> + <alias binding="same"> + <family>FamilyStrongAliasedToFreeMono</family> + <accept> + <family>FreeMono</family> + </accept> + </alias> + + <!-- These fonts should NOT be treated as identical by CSS font fallback. --> + <alias> + <family>FamilyWeakAliasedToFreeMono</family> + <accept> + <family>FreeMono</family> + </accept> + </alias> + + <!-- If this font doesn't have a family name we are falling back. The fallback + font will certainly be one of the DejaVu fonts that we have in our + collection since they have a wide range of characters. Fontconfig might + choose DejaVu Sans or DejaVu Serif depending on the system, so we force + the use of DejaVu Sans in these situations to maintain consistency. --> + <match target="pattern"> + <test qual="all" name="family" compare="eq"> + <string></string> + </test> + <edit name="family" mode="append_last"> + <string>DejaVu Sans</string> + </edit> + </match> + + <config> + <!-- These are the default Unicode chars that are expected to be blank + in fonts. All other blank chars are assumed to be broken and won't + appear in the resulting charsets --> + <blank> + <int>0x0020</int> <!-- SPACE --> + <int>0x00A0</int> <!-- NO-BREAK SPACE --> + <int>0x00AD</int> <!-- SOFT HYPHEN --> + <int>0x034F</int> <!-- COMBINING GRAPHEME JOINER --> + <int>0x0600</int> <!-- ARABIC NUMBER SIGN --> + <int>0x0601</int> <!-- ARABIC SIGN SANAH --> + <int>0x0602</int> <!-- ARABIC FOOTNOTE MARKER --> + <int>0x0603</int> <!-- ARABIC SIGN SAFHA --> + <int>0x06DD</int> <!-- ARABIC END OF AYAH --> + <int>0x070F</int> <!-- SYRIAC ABBREVIATION MARK --> + <int>0x115F</int> <!-- HANGUL CHOSEONG FILLER --> + <int>0x1160</int> <!-- HANGUL JUNGSEONG FILLER --> + <int>0x1680</int> <!-- OGHAM SPACE MARK --> + <int>0x17B4</int> <!-- KHMER VOWEL INHERENT AQ --> + <int>0x17B5</int> <!-- KHMER VOWEL INHERENT AA --> + <int>0x180E</int> <!-- MONGOLIAN VOWEL SEPARATOR --> + <int>0x2000</int> <!-- EN QUAD --> + <int>0x2001</int> <!-- EM QUAD --> + <int>0x2002</int> <!-- EN SPACE --> + <int>0x2003</int> <!-- EM SPACE --> + <int>0x2004</int> <!-- THREE-PER-EM SPACE --> + <int>0x2005</int> <!-- FOUR-PER-EM SPACE --> + <int>0x2006</int> <!-- SIX-PER-EM SPACE --> + <int>0x2007</int> <!-- FIGURE SPACE --> + <int>0x2008</int> <!-- PUNCTUATION SPACE --> + <int>0x2009</int> <!-- THIN SPACE --> + <int>0x200A</int> <!-- HAIR SPACE --> + <int>0x200B</int> <!-- ZERO WIDTH SPACE --> + <int>0x200C</int> <!-- ZERO WIDTH NON-JOINER --> + <int>0x200D</int> <!-- ZERO WIDTH JOINER --> + <int>0x200E</int> <!-- LEFT-TO-RIGHT MARK --> + <int>0x200F</int> <!-- RIGHT-TO-LEFT MARK --> + <int>0x2028</int> <!-- LINE SEPARATOR --> + <int>0x2029</int> <!-- PARAGRAPH SEPARATOR --> + <int>0x202A</int> <!-- LEFT-TO-RIGHT EMBEDDING --> + <int>0x202B</int> <!-- RIGHT-TO-LEFT EMBEDDING --> + <int>0x202C</int> <!-- POP DIRECTIONAL FORMATTING --> + <int>0x202D</int> <!-- LEFT-TO-RIGHT override --> + <int>0x202E</int> <!-- RIGHT-TO-LEFT override --> + <int>0x202F</int> <!-- NARROW NO-BREAK SPACE --> + <int>0x205F</int> <!-- MEDIUM MATHEMATICAL SPACE --> + <int>0x2060</int> <!-- WORD JOINER --> + <int>0x2061</int> <!-- FUNCTION APPLICATION --> + <int>0x2062</int> <!-- INVISIBLE TIMES --> + <int>0x2063</int> <!-- INVISIBLE SEPARATOR --> + <int>0x206A</int> <!-- INHIBIT SYMMETRIC SWAPPING --> + <int>0x206B</int> <!-- ACTIVATE SYMMETRIC SWAPPING --> + <int>0x206C</int> <!-- INHIBIT ARABIC FORM SHAPING --> + <int>0x206D</int> <!-- ACTIVATE ARABIC FORM SHAPING --> + <int>0x206E</int> <!-- NATIONAL DIGIT SHAPES --> + <int>0x206F</int> <!-- NOMINAL DIGIT SHAPES --> + <int>0x3000</int> <!-- IDEOGRAPHIC SPACE --> + <int>0x3164</int> <!-- HANGUL FILLER --> + <int>0xFEFF</int> <!-- ZERO WIDTH NO-BREAK SPACE --> + <int>0xFFA0</int> <!-- HALFWIDTH HANGUL FILLER --> + <int>0xFFF9</int> <!-- INTERLINEAR ANNOTATION ANCHOR --> + <int>0xFFFA</int> <!-- INTERLINEAR ANNOTATION SEPARATOR --> + <int>0xFFFB</int> <!-- INTERLINEAR ANNOTATION TERMINATOR --> + </blank> + </config> +</fontconfig> diff --git a/Tools/WebKitTestRunner/gtk/main.cpp b/Tools/WebKitTestRunner/gtk/main.cpp index d53c6248a..7947ce55c 100644 --- a/Tools/WebKitTestRunner/gtk/main.cpp +++ b/Tools/WebKitTestRunner/gtk/main.cpp @@ -26,12 +26,21 @@ #include "config.h" #include "TestController.h" +#include <WebKit/WKTextCheckerGtk.h> #include <gtk/gtk.h> +#include <wtf/glib/GRefPtr.h> int main(int argc, char** argv) { gtk_init(&argc, &argv); + + GRefPtr<GPtrArray> languages = adoptGRef(g_ptr_array_new()); + g_ptr_array_add(languages.get(), const_cast<gpointer>(static_cast<const void*>("en_US"))); + g_ptr_array_add(languages.get(), nullptr); + WKTextCheckerSetSpellCheckingLanguages(reinterpret_cast<const char* const*>(languages->pdata)); + // Prefer the not installed web and plugin processes. WTR::TestController controller(argc, const_cast<const char**>(argv)); + return 0; } |