summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Tokarev <annulen@yandex.ru>2016-12-26 00:24:34 +0300
committerKonstantin Tokarev <annulen@yandex.ru>2017-02-02 12:31:19 +0000
commitb9e202b0f12f275d4aade98943df92bf67684f52 (patch)
tree4471f3da5f573679c3f42b0ad54c46bdd0a50910
parent1c8f056531c65706b85c44c2db657ea891be868d (diff)
downloadqtwebkit-b9e202b0f12f275d4aade98943df92bf67684f52.tar.gz
Imported WebKit commit 12fbea815480c3b3fad139cd8dfb82e8c954bc9a
Change-Id: Iccbb1e8bd8b7f72322614224c203fc509a8dbb79 Reviewed-by: Konstantin Tokarev <annulen@yandex.ru>
-rw-r--r--Source/JavaScriptCore/PlatformQt.cmake2
-rw-r--r--Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h4
-rw-r--r--Source/JavaScriptCore/debugger/DebuggerCallFrame.h2
-rw-r--r--Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.cpp1
-rw-r--r--Source/JavaScriptCore/disassembler/ARM64Disassembler.cpp1
-rw-r--r--Source/JavaScriptCore/runtime/VM.h6
-rw-r--r--Source/WTF/wtf/Assertions.h2
-rw-r--r--Source/WTF/wtf/PlatformQt.cmake6
-rw-r--r--Source/WTF/wtf/WorkQueue.h7
-rw-r--r--Source/WTF/wtf/qt/WorkQueueQt.cpp7
-rw-r--r--Source/WebCore/CMakeLists.txt9
-rw-r--r--Source/WebCore/PlatformQt.cmake30
-rw-r--r--Source/WebCore/page/ContextMenuController.cpp2
-rw-r--r--Source/WebCore/page/qt/GestureTapHighlighter.cpp (renamed from Source/WebCore/page/GestureTapHighlighter.cpp)0
-rw-r--r--Source/WebCore/platform/graphics/PlatformLayer.h5
-rw-r--r--Source/WebCore/platform/graphics/win/MediaPlayerPrivateMediaFoundation.cpp3144
-rw-r--r--Source/WebCore/platform/network/ParsedContentRange.cpp4
-rw-r--r--Source/WebCore/platform/network/qt/QtMIMETypeSniffer.cpp2
-rw-r--r--Source/WebCore/platform/qt/ScrollbarThemeQStyle.cpp24
-rw-r--r--Source/WebCore/platform/qt/ScrollbarThemeQStyle.h2
-rw-r--r--Source/WebCore/platform/sql/SQLiteFileSystem.cpp2
-rw-r--r--Source/WebCore/rendering/break_lines.cpp2
-rw-r--r--Source/WebKit/CMakeLists.txt11
-rw-r--r--Source/WebKit/PlatformQt.cmake17
-rw-r--r--Source/WebKit/qt/Api/qwebelement.cpp62
-rw-r--r--Source/WebKit/qt/Api/qwebelement.h18
-rw-r--r--Source/WebKit/qt/Api/qwebfullscreenrequest.cpp124
-rw-r--r--Source/WebKit/qt/Api/qwebfullscreenrequest.h74
-rw-r--r--Source/WebKit/qt/Api/qwebsettings.cpp14
-rw-r--r--Source/WebKit/qt/Api/qwebsettings.h4
-rw-r--r--Source/WebKit/qt/WebCoreSupport/ChromeClientQt.cpp30
-rw-r--r--Source/WebKit/qt/WebCoreSupport/ChromeClientQt.h6
-rw-r--r--Source/WebKit/qt/WebCoreSupport/PlatformStrategiesQt.cpp9
-rw-r--r--Source/WebKit/qt/WebCoreSupport/QWebPageAdapter.cpp16
-rw-r--r--Source/WebKit/qt/WebCoreSupport/QWebPageAdapter.h11
-rw-r--r--Source/WebKit/qt/WidgetApi/qwebpage.cpp5
-rw-r--r--Source/WebKit/qt/WidgetApi/qwebpage.h5
-rw-r--r--Source/WebKit/qt/WidgetApi/qwebpage_p.cpp11
-rw-r--r--Source/WebKit/qt/WidgetApi/qwebpage_p.h5
-rw-r--r--Source/WebKit/qt/tests/CMakeLists.txt4
-rw-r--r--Source/WebKit2/NetworkProcess/Downloads/qt/QtFileDownloader.cpp34
-rw-r--r--Source/WebKit2/NetworkProcess/Downloads/qt/QtFileDownloader.h1
-rw-r--r--Source/WebKit2/Platform/IPC/unix/ConnectionUnix.cpp11
-rw-r--r--Source/WebKit2/Shared/qt/ShareableBitmapQt.cpp2
-rw-r--r--Source/WebKit2/UIProcess/API/C/WKNativeEvent.h12
-rw-r--r--Source/WebKit2/UIProcess/API/C/qt/WKNativeEvent.h37
-rw-r--r--Source/WebKit2/UIProcess/Launcher/qt/ProcessLauncherQt.cpp7
-rw-r--r--Source/WebKit2/UIProcess/WebPageProxy.messages.in2
-rw-r--r--Source/WebKit2/WebProcess/WebPage/WebPage.messages.in2
-rw-r--r--Source/cmake/OptionsQt.cmake72
-rw-r--r--Source/cmake/WebKitMacros.cmake14
-rw-r--r--[-rwxr-xr-x]Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp22
-rw-r--r--Tools/DumpRenderTree/qt/DumpRenderTreeQt.h33
-rw-r--r--Tools/DumpRenderTree/qt/EventSenderQt.cpp2
-rw-r--r--Tools/DumpRenderTree/qt/EventSenderQt.h6
-rw-r--r--Tools/DumpRenderTree/qt/TestRunnerQt.h4
-rw-r--r--Tools/DumpRenderTree/qt/WorkQueueItemQt.h4
-rw-r--r--Tools/DumpRenderTree/qt/testplugin.h8
-rw-r--r--Tools/QtTestBrowser/cookiejar.h4
-rw-r--r--Tools/QtTestBrowser/fpstimer.h4
-rw-r--r--Tools/QtTestBrowser/launcherwindow.cpp9
-rw-r--r--Tools/QtTestBrowser/launcherwindow.h6
-rw-r--r--Tools/QtTestBrowser/locationedit.h6
-rw-r--r--Tools/QtTestBrowser/mainwindow.cpp10
-rw-r--r--Tools/QtTestBrowser/mainwindow.h2
-rw-r--r--Tools/QtTestBrowser/webinspector.h6
-rw-r--r--Tools/QtTestBrowser/webpage.cpp24
-rw-r--r--Tools/QtTestBrowser/webpage.h6
-rw-r--r--Tools/QtTestBrowser/webview.h18
-rw-r--r--Tools/Scripts/webkitperl/FeatureList.pm2
-rw-r--r--Tools/qmake/mkspecs/features/functions.prf11
-rw-r--r--Tools/qmake/projects/generate_cmake_toolchain_file.pro3
-rw-r--r--Tools/qmake/projects/qtjpeg/qtjpeg.pro11
-rw-r--r--Tools/qmake/projects/qtpng/qtpng.pro11
-rw-r--r--Tools/qmake/projects/run_cmake.pro21
-rwxr-xr-xTools/qt/convert-prl-libs-to-cmake.pl41
-rw-r--r--Tools/qt/manifest.txt1
77 files changed, 3882 insertions, 277 deletions
diff --git a/Source/JavaScriptCore/PlatformQt.cmake b/Source/JavaScriptCore/PlatformQt.cmake
index 11587f401..057929139 100644
--- a/Source/JavaScriptCore/PlatformQt.cmake
+++ b/Source/JavaScriptCore/PlatformQt.cmake
@@ -29,7 +29,9 @@ if (WIN32)
list(REMOVE_ITEM JavaScriptCore_SOURCES
inspector/JSGlobalObjectInspectorController.cpp
)
+endif ()
+if (MSVC)
file(MAKE_DIRECTORY ${DERIVED_SOURCES_DIR}/ForwardingHeaders/JavaScriptCore)
set(JavaScriptCore_PRE_BUILD_COMMAND "${CMAKE_BINARY_DIR}/DerivedSources/JavaScriptCore/preBuild.cmd")
diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h b/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h
index b8051d370..f502a2551 100644
--- a/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h
+++ b/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h
@@ -32,6 +32,10 @@
#include "AbstractMacroAssembler.h"
#include <wtf/Optional.h>
+#if COMPILER(MSVC)
+#include <intrin.h>
+#endif
+
namespace JSC {
class MacroAssemblerX86Common : public AbstractMacroAssembler<X86Assembler, MacroAssemblerX86Common> {
diff --git a/Source/JavaScriptCore/debugger/DebuggerCallFrame.h b/Source/JavaScriptCore/debugger/DebuggerCallFrame.h
index aa3cca52b..b583455bc 100644
--- a/Source/JavaScriptCore/debugger/DebuggerCallFrame.h
+++ b/Source/JavaScriptCore/debugger/DebuggerCallFrame.h
@@ -61,7 +61,7 @@ public:
// line and column are in base 0 e.g. the first line is line 0.
int line() const { return m_position.m_line.zeroBasedInt(); }
int column() const { return m_position.m_column.zeroBasedInt(); }
- JS_EXPORT_PRIVATE const TextPosition& position() const { return m_position; }
+ const TextPosition& position() const { return m_position; }
JS_EXPORT_PRIVATE JSGlobalObject* vmEntryGlobalObject() const;
JS_EXPORT_PRIVATE DebuggerScope* scope();
diff --git a/Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.cpp b/Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.cpp
index 52a92c669..28f703801 100644
--- a/Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.cpp
+++ b/Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.cpp
@@ -23,7 +23,6 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#define __STDC_FORMAT_MACROS
#include "config.h"
#if USE(ARM64_DISASSEMBLER)
diff --git a/Source/JavaScriptCore/disassembler/ARM64Disassembler.cpp b/Source/JavaScriptCore/disassembler/ARM64Disassembler.cpp
index bb8fde4e4..ac52213df 100644
--- a/Source/JavaScriptCore/disassembler/ARM64Disassembler.cpp
+++ b/Source/JavaScriptCore/disassembler/ARM64Disassembler.cpp
@@ -23,7 +23,6 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#define __STDC_FORMAT_MACROS
#include "config.h"
#include "Disassembler.h"
diff --git a/Source/JavaScriptCore/runtime/VM.h b/Source/JavaScriptCore/runtime/VM.h
index 759bbd97d..8ba705a78 100644
--- a/Source/JavaScriptCore/runtime/VM.h
+++ b/Source/JavaScriptCore/runtime/VM.h
@@ -247,10 +247,10 @@ public:
JS_EXPORT_PRIVATE ~VM();
JS_EXPORT_PRIVATE Watchdog& ensureWatchdog();
- JS_EXPORT_PRIVATE Watchdog* watchdog() { return m_watchdog.get(); }
+ Watchdog* watchdog() { return m_watchdog.get(); }
#if ENABLE(SAMPLING_PROFILER)
- JS_EXPORT_PRIVATE SamplingProfiler* samplingProfiler() { return m_samplingProfiler.get(); }
+ SamplingProfiler* samplingProfiler() { return m_samplingProfiler.get(); }
JS_EXPORT_PRIVATE void ensureSamplingProfiler(RefPtr<Stopwatch>&&);
#endif
@@ -597,7 +597,7 @@ public:
JS_EXPORT_PRIVATE void queueMicrotask(JSGlobalObject*, PassRefPtr<Microtask>);
JS_EXPORT_PRIVATE void drainMicrotasks();
- JS_EXPORT_PRIVATE void setShouldRewriteConstAsVar(bool shouldRewrite) { m_shouldRewriteConstAsVar = shouldRewrite; }
+ void setShouldRewriteConstAsVar(bool shouldRewrite) { m_shouldRewriteConstAsVar = shouldRewrite; }
ALWAYS_INLINE bool shouldRewriteConstAsVar() { return m_shouldRewriteConstAsVar; }
inline bool shouldTriggerTermination(ExecState*);
diff --git a/Source/WTF/wtf/Assertions.h b/Source/WTF/wtf/Assertions.h
index 28060cc98..787c05f42 100644
--- a/Source/WTF/wtf/Assertions.h
+++ b/Source/WTF/wtf/Assertions.h
@@ -38,6 +38,8 @@
Defining any of the symbols explicitly prevents this from having any effect.
*/
+#undef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <stdarg.h>
#include <stdbool.h>
diff --git a/Source/WTF/wtf/PlatformQt.cmake b/Source/WTF/wtf/PlatformQt.cmake
index a85dc6abe..1e64e8bb2 100644
--- a/Source/WTF/wtf/PlatformQt.cmake
+++ b/Source/WTF/wtf/PlatformQt.cmake
@@ -40,13 +40,19 @@ if (USE_GLIB)
list(APPEND WTF_SYSTEM_INCLUDE_DIRECTORIES
${GLIB_INCLUDE_DIRS}
)
+ list(APPEND WTF_LIBRARIES
+ ${GLIB_GOBJECT_LIBRARIES}
+ ${GLIB_LIBRARIES}
+ )
endif ()
if (WIN32)
list(APPEND WTF_LIBRARIES
winmm
)
+endif ()
+if (MSVC)
set(WTF_POST_BUILD_COMMAND "${CMAKE_BINARY_DIR}/DerivedSources/WTF/postBuild.cmd")
file(WRITE "${WTF_POST_BUILD_COMMAND}" "@xcopy /y /s /d /f \"${WTF_DIR}/wtf/*.h\" \"${DERIVED_SOURCES_DIR}/ForwardingHeaders/WTF\" >nul 2>nul\n@xcopy /y /s /d /f \"${DERIVED_SOURCES_DIR}/WTF/*.h\" \"${DERIVED_SOURCES_DIR}/ForwardingHeaders/WTF\" >nul 2>nul\n")
file(MAKE_DIRECTORY ${DERIVED_SOURCES_DIR}/ForwardingHeaders/WTF)
diff --git a/Source/WTF/wtf/WorkQueue.h b/Source/WTF/wtf/WorkQueue.h
index c5f81666b..ca93aa7f8 100644
--- a/Source/WTF/wtf/WorkQueue.h
+++ b/Source/WTF/wtf/WorkQueue.h
@@ -52,6 +52,12 @@
#include <wtf/win/WorkItemWin.h>
#endif
+#if PLATFORM(QT)
+QT_BEGIN_NAMESPACE
+class QProcess;
+QT_END_NAMESPACE
+#endif
+
namespace WTF {
class WorkQueue final : public FunctionDispatcher {
@@ -83,6 +89,7 @@ public:
void unregisterSocketEventHandler(int);
#elif PLATFORM(QT)
QSocketNotifier* registerSocketEventHandler(int, QSocketNotifier::Type, std::function<void()>);
+ void dispatchOnTermination(QProcess*, std::function<void()>);
#elif OS(DARWIN)
dispatch_queue_t dispatchQueue() const { return m_dispatchQueue; }
#endif
diff --git a/Source/WTF/wtf/qt/WorkQueueQt.cpp b/Source/WTF/wtf/qt/WorkQueueQt.cpp
index 5d412361c..be04dae3f 100644
--- a/Source/WTF/wtf/qt/WorkQueueQt.cpp
+++ b/Source/WTF/wtf/qt/WorkQueueQt.cpp
@@ -28,6 +28,7 @@
#include "WorkQueue.h"
#include <QObject>
+#include <QProcess>
#include <QThread>
#include <wtf/Threading.h>
@@ -122,6 +123,12 @@ void WorkQueue::dispatchAfter(std::chrono::nanoseconds duration, std::function<v
itemQt->moveToThread(m_workThread);
}
+void WorkQueue::dispatchOnTermination(QProcess* process, std::function<void()> function)
+{
+ WorkQueue::WorkItemQt* itemQt = new WorkQueue::WorkItemQt(this, process, SIGNAL(finished(int, QProcess::ExitStatus)), function);
+ itemQt->moveToThread(m_workThread);
+}
+
}
#include "WorkQueueQt.moc"
diff --git a/Source/WebCore/CMakeLists.txt b/Source/WebCore/CMakeLists.txt
index 404af56e6..51791ac6d 100644
--- a/Source/WebCore/CMakeLists.txt
+++ b/Source/WebCore/CMakeLists.txt
@@ -2000,7 +2000,6 @@ set(WebCore_SOURCES
page/FrameSnapshotting.cpp
page/FrameTree.cpp
page/FrameView.cpp
- page/GestureTapHighlighter.cpp
page/History.cpp
page/Location.cpp
page/MainFrame.cpp
@@ -3758,6 +3757,10 @@ endif ()
WEBKIT_FRAMEWORK(WebCore)
+if (NOT MSVC AND WIN32 AND ${PORT} STREQUAL "Qt")
+ ADD_PREFIX_HEADER(WebCore "${WEBCORE_DIR}/WebCorePrefix.h")
+endif ()
+
# The -ftree-sra optimization (implicit with -O2) causes crashes when
# allocating large chunks of memory using bmalloc on Intel 32bit.
# See https://bugs.webkit.org/show_bug.cgi?id=146440
@@ -3776,6 +3779,10 @@ add_dependencies(WebCoreTestSupport WebCore)
target_link_libraries(WebCoreTestSupport ${WebCoreTestSupport_LIBRARIES})
set_target_properties(WebCoreTestSupport PROPERTIES FOLDER "WebCore")
+if (NOT MSVC AND WIN32 AND ${PORT} STREQUAL "Qt")
+ ADD_PREFIX_HEADER(WebCoreTestSupport "testing/js/WebCoreTestSupportPrefix.h")
+endif ()
+
if (WebCoreTestSupport_OUTPUT_NAME)
set_target_properties(WebCoreTestSupport PROPERTIES OUTPUT_NAME ${WebCoreTestSupport_OUTPUT_NAME})
if (MSVC)
diff --git a/Source/WebCore/PlatformQt.cmake b/Source/WebCore/PlatformQt.cmake
index 4e5909307..0661364c5 100644
--- a/Source/WebCore/PlatformQt.cmake
+++ b/Source/WebCore/PlatformQt.cmake
@@ -36,8 +36,10 @@ list(APPEND WebCore_INCLUDE_DIRECTORIES
"${WEBCORE_DIR}/platform/graphics/surfaces"
"${WEBCORE_DIR}/platform/graphics/surfaces/qt"
"${WEBCORE_DIR}/platform/graphics/qt"
+ "${WEBCORE_DIR}/platform/graphics/win"
"${WEBCORE_DIR}/platform/network/qt"
"${WEBCORE_DIR}/platform/text/qt"
+ "${WEBCORE_DIR}/platform/win"
"${WTF_DIR}"
)
@@ -241,6 +243,12 @@ list(APPEND WebCore_USER_AGENT_STYLE_SHEETS
${WEBCORE_DIR}/css/themeQtNoListboxes.css
)
+if (ENABLE_WEBKIT2)
+ list(APPEND WebCore_SOURCES
+ page/qt/GestureTapHighlighter.cpp
+ )
+endif ()
+
if (ENABLE_OPENGL)
list(APPEND WebCore_SOURCES
platform/graphics/OpenGLShims.cpp
@@ -293,6 +301,16 @@ if (USE_GSTREAMER)
)
endif ()
+if (USE_MEDIA_FOUNDATION)
+ list(APPEND WebCore_SOURCES
+ platform/graphics/win/MediaPlayerPrivateMediaFoundation.cpp
+ )
+ list(APPEND WebCore_LIBRARIES
+ mfuuid
+ strmbase
+ )
+endif ()
+
if (USE_QT_MULTIMEDIA)
list(APPEND WebCore_SOURCES
platform/graphics/qt/MediaPlayerPrivateQt.cpp
@@ -356,12 +374,18 @@ if (HAVE_FONTCONFIG)
endif ()
# From PlatformWin.cmake
-if (WIN32)
+if (WIN32)
if (${JavaScriptCore_LIBRARY_TYPE} MATCHES STATIC)
add_definitions(-DSTATICALLY_LINKED_WITH_WTF -DSTATICALLY_LINKED_WITH_JavaScriptCore)
endif ()
+ list(APPEND WebCore_SOURCES
+ platform/win/SystemInfo.cpp
+ )
+endif ()
+
+if (MSVC)
list(APPEND WebCore_INCLUDE_DIRECTORIES
"${CMAKE_BINARY_DIR}/../include/private"
"${CMAKE_BINARY_DIR}/../include/private/JavaScriptCore"
@@ -390,10 +414,6 @@ if (WIN32)
"${WEBCORE_DIR}/platform/win"
)
- list(APPEND WebCore_SOURCES
- platform/win/SystemInfo.cpp
- )
-
file(MAKE_DIRECTORY ${DERIVED_SOURCES_DIR}/ForwardingHeaders/WebCore)
set(WebCore_PRE_BUILD_COMMAND "${CMAKE_BINARY_DIR}/DerivedSources/WebCore/preBuild.cmd")
diff --git a/Source/WebCore/page/ContextMenuController.cpp b/Source/WebCore/page/ContextMenuController.cpp
index b09b04788..47e5fc970 100644
--- a/Source/WebCore/page/ContextMenuController.cpp
+++ b/Source/WebCore/page/ContextMenuController.cpp
@@ -1208,7 +1208,7 @@ void ContextMenuController::checkOrEnableIfNeeded(ContextMenuItem& item) const
shouldEnable = true;
break;
#endif
-#if PLATFORM(GTK) || PLATFORM(EFL)
+#if PLATFORM(GTK) || PLATFORM(EFL) || PLATFORM(QT)
case ContextMenuItemTagSelectAll:
shouldEnable = true;
break;
diff --git a/Source/WebCore/page/GestureTapHighlighter.cpp b/Source/WebCore/page/qt/GestureTapHighlighter.cpp
index 6c55d88ea..6c55d88ea 100644
--- a/Source/WebCore/page/GestureTapHighlighter.cpp
+++ b/Source/WebCore/page/qt/GestureTapHighlighter.cpp
diff --git a/Source/WebCore/platform/graphics/PlatformLayer.h b/Source/WebCore/platform/graphics/PlatformLayer.h
index 676752489..29f9decb2 100644
--- a/Source/WebCore/platform/graphics/PlatformLayer.h
+++ b/Source/WebCore/platform/graphics/PlatformLayer.h
@@ -31,11 +31,6 @@ OBJC_CLASS CALayer;
typedef CALayer PlatformLayer;
#elif PLATFORM(WIN) && USE(CA)
typedef struct _CACFLayer PlatformLayer;
-#elif PLATFORM(QT)
-namespace WebCore {
-class TextureMapperPlatformLayer;
-typedef TextureMapperPlatformLayer PlatformLayer;
-};
#elif USE(COORDINATED_GRAPHICS_THREADED)
namespace WebCore {
class TextureMapperPlatformLayerProxyProvider;
diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateMediaFoundation.cpp b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateMediaFoundation.cpp
new file mode 100644
index 000000000..8c898c17b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateMediaFoundation.cpp
@@ -0,0 +1,3144 @@
+/*
+ * Copyright (C) 2014 Alex Christensen <achristensen@webkit.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "MediaPlayerPrivateMediaFoundation.h"
+
+#include "CachedResourceLoader.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HWndDC.h"
+#include "HostWindow.h"
+#include "NotImplemented.h"
+#if USE(CAIRO)
+#include "PlatformContextCairo.h"
+#endif
+#include "SoftLinking.h"
+
+#if PLATFORM(QT)
+#include "QWebPageClient.h"
+#include <QWindow>
+#endif
+
+#if USE(MEDIA_FOUNDATION)
+
+#include <wtf/MainThread.h>
+#include <wtf/NeverDestroyed.h>
+
+SOFT_LINK_LIBRARY(Mf);
+SOFT_LINK_OPTIONAL(Mf, MFCreateSourceResolver, HRESULT, STDAPICALLTYPE, (IMFSourceResolver**));
+SOFT_LINK_OPTIONAL(Mf, MFCreateMediaSession, HRESULT, STDAPICALLTYPE, (IMFAttributes*, IMFMediaSession**));
+SOFT_LINK_OPTIONAL(Mf, MFCreateTopology, HRESULT, STDAPICALLTYPE, (IMFTopology**));
+SOFT_LINK_OPTIONAL(Mf, MFCreateTopologyNode, HRESULT, STDAPICALLTYPE, (MF_TOPOLOGY_TYPE, IMFTopologyNode**));
+SOFT_LINK_OPTIONAL(Mf, MFGetService, HRESULT, STDAPICALLTYPE, (IUnknown*, REFGUID, REFIID, LPVOID*));
+SOFT_LINK_OPTIONAL(Mf, MFCreateAudioRendererActivate, HRESULT, STDAPICALLTYPE, (IMFActivate**));
+SOFT_LINK_OPTIONAL(Mf, MFCreateVideoRendererActivate, HRESULT, STDAPICALLTYPE, (HWND, IMFActivate**));
+SOFT_LINK_OPTIONAL(Mf, MFCreateSampleGrabberSinkActivate, HRESULT, STDAPICALLTYPE, (IMFMediaType*, IMFSampleGrabberSinkCallback*, IMFActivate**));
+SOFT_LINK_OPTIONAL(Mf, MFGetSupportedMimeTypes, HRESULT, STDAPICALLTYPE, (PROPVARIANT*));
+
+SOFT_LINK_LIBRARY(Mfplat);
+SOFT_LINK_OPTIONAL(Mfplat, MFStartup, HRESULT, STDAPICALLTYPE, (ULONG, DWORD));
+SOFT_LINK_OPTIONAL(Mfplat, MFShutdown, HRESULT, STDAPICALLTYPE, ());
+SOFT_LINK_OPTIONAL(Mfplat, MFCreateMemoryBuffer, HRESULT, STDAPICALLTYPE, (DWORD, IMFMediaBuffer**));
+SOFT_LINK_OPTIONAL(Mfplat, MFCreateSample, HRESULT, STDAPICALLTYPE, (IMFSample**));
+SOFT_LINK_OPTIONAL(Mfplat, MFCreateMediaType, HRESULT, STDAPICALLTYPE, (IMFMediaType**));
+SOFT_LINK_OPTIONAL(Mfplat, MFFrameRateToAverageTimePerFrame, HRESULT, STDAPICALLTYPE, (UINT32, UINT32, UINT64*));
+
+SOFT_LINK_LIBRARY(evr);
+SOFT_LINK_OPTIONAL(evr, MFCreateVideoSampleFromSurface, HRESULT, STDAPICALLTYPE, (IUnknown*, IMFSample**));
+
+SOFT_LINK_LIBRARY(Dxva2);
+SOFT_LINK_OPTIONAL(Dxva2, DXVA2CreateDirect3DDeviceManager9, HRESULT, STDAPICALLTYPE, (UINT*, IDirect3DDeviceManager9**));
+
+SOFT_LINK_LIBRARY(D3d9);
+SOFT_LINK_OPTIONAL(D3d9, Direct3DCreate9Ex, HRESULT, STDAPICALLTYPE, (UINT, IDirect3D9Ex**));
+
+// MFSamplePresenterSampleCounter
+// Data type: UINT32
+//
+// Version number for the video samples. When the presenter increments the version
+// number, all samples with the previous version number are stale and should be
+// discarded.
+static const GUID MFSamplePresenterSampleCounter =
+{ 0x869f1f7c, 0x3496, 0x48a9, { 0x88, 0xe3, 0x69, 0x85, 0x79, 0xd0, 0x8c, 0xb6 } };
+
+static const double tenMegahertz = 10000000;
+
+namespace WebCore {
+
+MediaPlayerPrivateMediaFoundation::MediaPlayerPrivateMediaFoundation(MediaPlayer* player)
+ : m_player(player)
+ , m_visible(false)
+ , m_loadingProgress(false)
+ , m_paused(true)
+ , m_hasAudio(false)
+ , m_hasVideo(false)
+ , m_preparingToPlay(false)
+ , m_hwndVideo(nullptr)
+ , m_networkState(MediaPlayer::Empty)
+ , m_readyState(MediaPlayer::HaveNothing)
+ , m_weakPtrFactory(this)
+{
+ createSession();
+ createVideoWindow();
+}
+
+MediaPlayerPrivateMediaFoundation::~MediaPlayerPrivateMediaFoundation()
+{
+ notifyDeleted();
+ destroyVideoWindow();
+ endSession();
+}
+
+void MediaPlayerPrivateMediaFoundation::registerMediaEngine(MediaEngineRegistrar registrar)
+{
+ if (isAvailable()) {
+ registrar([](MediaPlayer* player) { return std::make_unique<MediaPlayerPrivateMediaFoundation>(player); },
+ getSupportedTypes, supportsType, 0, 0, 0, 0);
+ }
+}
+
+bool MediaPlayerPrivateMediaFoundation::isAvailable()
+{
+ notImplemented();
+ return true;
+}
+
+static const HashSet<String, ASCIICaseInsensitiveHash>& mimeTypeCache()
+{
+ static NeverDestroyed<HashSet<String, ASCIICaseInsensitiveHash>> cachedTypes;
+
+ if (cachedTypes.get().size() > 0)
+ return cachedTypes;
+
+ cachedTypes.get().add(String("video/mp4"));
+
+ if (!MFGetSupportedMimeTypesPtr())
+ return cachedTypes;
+
+ PROPVARIANT propVarMimeTypeArray;
+ PropVariantInit(&propVarMimeTypeArray);
+
+ HRESULT hr = MFGetSupportedMimeTypesPtr()(&propVarMimeTypeArray);
+
+ if (SUCCEEDED(hr)) {
+ CALPWSTR mimeTypeArray = propVarMimeTypeArray.calpwstr;
+ for (unsigned i = 0; i < mimeTypeArray.cElems; i++)
+ cachedTypes.get().add(mimeTypeArray.pElems[i]);
+ }
+
+ PropVariantClear(&propVarMimeTypeArray);
+
+ return cachedTypes;
+}
+
+void MediaPlayerPrivateMediaFoundation::getSupportedTypes(HashSet<String, ASCIICaseInsensitiveHash>& types)
+{
+ types = mimeTypeCache();
+}
+
+MediaPlayer::SupportsType MediaPlayerPrivateMediaFoundation::supportsType(const MediaEngineSupportParameters& parameters)
+{
+ if (parameters.type.isNull() || parameters.type.isEmpty())
+ return MediaPlayer::IsNotSupported;
+
+ if (mimeTypeCache().contains(parameters.type))
+ return MediaPlayer::IsSupported;
+
+ return MediaPlayer::IsNotSupported;
+}
+
+void MediaPlayerPrivateMediaFoundation::load(const String& url)
+{
+ startCreateMediaSource(url);
+
+ m_networkState = MediaPlayer::Loading;
+ m_player->networkStateChanged();
+ m_readyState = MediaPlayer::HaveNothing;
+ m_player->readyStateChanged();
+}
+
+void MediaPlayerPrivateMediaFoundation::cancelLoad()
+{
+ notImplemented();
+}
+
+void MediaPlayerPrivateMediaFoundation::prepareToPlay()
+{
+ // We call startSession() to start buffering video data.
+ // When we have received enough data, we pause, so that we don't actually start the playback.
+ ASSERT(m_paused);
+ ASSERT(!m_preparingToPlay);
+ m_preparingToPlay = startSession();
+}
+
+void MediaPlayerPrivateMediaFoundation::play()
+{
+ m_paused = !startSession();
+
+ m_preparingToPlay = false;
+}
+
+void MediaPlayerPrivateMediaFoundation::pause()
+{
+ if (!m_mediaSession)
+ return;
+
+ m_paused = SUCCEEDED(m_mediaSession->Pause());
+}
+
+bool MediaPlayerPrivateMediaFoundation::supportsFullscreen() const
+{
+ return true;
+}
+
+FloatSize MediaPlayerPrivateMediaFoundation::naturalSize() const
+{
+ return m_size;
+}
+
+bool MediaPlayerPrivateMediaFoundation::hasVideo() const
+{
+ return m_hasVideo;
+}
+
+bool MediaPlayerPrivateMediaFoundation::hasAudio() const
+{
+ return m_hasAudio;
+}
+
+void MediaPlayerPrivateMediaFoundation::setVisible(bool visible)
+{
+ m_visible = visible;
+}
+
+bool MediaPlayerPrivateMediaFoundation::seeking() const
+{
+ // We assume seeking is immediately complete.
+ return false;
+}
+
+void MediaPlayerPrivateMediaFoundation::seek(float time)
+{
+ PROPVARIANT propVariant;
+ PropVariantInit(&propVariant);
+ propVariant.vt = VT_I8;
+ propVariant.hVal.QuadPart = static_cast<__int64>(time * tenMegahertz);
+
+ HRESULT hr = m_mediaSession->Start(&GUID_NULL, &propVariant);
+ ASSERT(SUCCEEDED(hr));
+ PropVariantClear(&propVariant);
+
+ m_player->timeChanged();
+}
+
+void MediaPlayerPrivateMediaFoundation::setRate(float rate)
+{
+ COMPtr<IMFRateControl> rateControl;
+
+ HRESULT hr = MFGetServicePtr()(m_mediaSession.get(), MF_RATE_CONTROL_SERVICE, IID_IMFRateControl, (void**)&rateControl);
+
+ if (!SUCCEEDED(hr))
+ return;
+
+ BOOL reduceSamplesInStream = rate > 2.0;
+
+ rateControl->SetRate(reduceSamplesInStream, rate);
+}
+
+float MediaPlayerPrivateMediaFoundation::duration() const
+{
+ if (!m_mediaSource)
+ return 0;
+
+ IMFPresentationDescriptor* descriptor;
+ if (!SUCCEEDED(m_mediaSource->CreatePresentationDescriptor(&descriptor)))
+ return 0;
+
+ UINT64 duration;
+ if (!SUCCEEDED(descriptor->GetUINT64(MF_PD_DURATION, &duration)))
+ duration = 0;
+ descriptor->Release();
+
+ return static_cast<float>(duration) / tenMegahertz;
+}
+
+float MediaPlayerPrivateMediaFoundation::currentTime() const
+{
+ if (!m_presenter)
+ return 0.0f;
+
+ return m_presenter->currentTime();
+}
+
+bool MediaPlayerPrivateMediaFoundation::paused() const
+{
+ return m_paused;
+}
+
+void MediaPlayerPrivateMediaFoundation::setVolume(float volume)
+{
+ if (!MFGetServicePtr())
+ return;
+
+ COMPtr<IMFSimpleAudioVolume> audioVolume;
+ if (SUCCEEDED(MFGetServicePtr()(m_mediaSession.get(), MR_POLICY_VOLUME_SERVICE, __uuidof(IMFSimpleAudioVolume), (void **)&audioVolume))) {
+ HRESULT hr = audioVolume->SetMasterVolume(volume);
+ ASSERT(SUCCEEDED(hr));
+ }
+}
+
+bool MediaPlayerPrivateMediaFoundation::supportsMuting() const
+{
+ return true;
+}
+
+void MediaPlayerPrivateMediaFoundation::setMuted(bool muted)
+{
+ if (!MFGetServicePtr())
+ return;
+
+ COMPtr<IMFSimpleAudioVolume> audioVolume;
+ if (SUCCEEDED(MFGetServicePtr()(m_mediaSession.get(), MR_POLICY_VOLUME_SERVICE, __uuidof(IMFSimpleAudioVolume), (void **)&audioVolume))) {
+ HRESULT hr = audioVolume->SetMute(muted ? TRUE : FALSE);
+ ASSERT(SUCCEEDED(hr));
+ }
+}
+
+MediaPlayer::NetworkState MediaPlayerPrivateMediaFoundation::networkState() const
+{
+ return m_networkState;
+}
+
+MediaPlayer::ReadyState MediaPlayerPrivateMediaFoundation::readyState() const
+{
+ return m_readyState;
+}
+
+float MediaPlayerPrivateMediaFoundation::maxTimeSeekable() const
+{
+ return durationDouble();
+}
+
+std::unique_ptr<PlatformTimeRanges> MediaPlayerPrivateMediaFoundation::buffered() const
+{
+ auto ranges = std::make_unique<PlatformTimeRanges>();
+ if (m_presenter && m_presenter->maxTimeLoaded() > 0)
+ ranges->add(MediaTime::zeroTime(), MediaTime::createWithDouble(m_presenter->maxTimeLoaded()));
+ return ranges;
+}
+
+bool MediaPlayerPrivateMediaFoundation::didLoadingProgress() const
+{
+ return m_loadingProgress;
+}
+
+void MediaPlayerPrivateMediaFoundation::setSize(const IntSize& size)
+{
+ m_size = size;
+
+ auto videoDisplay = this->videoDisplay();
+ if (!videoDisplay)
+ return;
+
+ IntPoint positionInWindow(m_lastPaintRect.location());
+
+ FrameView* view = nullptr;
+ float deviceScaleFactor = 1.0f;
+ if (m_player && m_player->cachedResourceLoader() && m_player->cachedResourceLoader()->document()) {
+ view = m_player->cachedResourceLoader()->document()->view();
+ deviceScaleFactor = m_player->cachedResourceLoader()->document()->deviceScaleFactor();
+ }
+
+ LayoutPoint scrollPosition;
+ if (view) {
+ scrollPosition = view->scrollPositionForFixedPosition();
+ positionInWindow = view->convertToContainingWindow(IntPoint(m_lastPaintRect.location()));
+ }
+
+ positionInWindow.move(-scrollPosition.x().toInt(), -scrollPosition.y().toInt());
+
+ int x = positionInWindow.x() * deviceScaleFactor;
+ int y = positionInWindow.y() * deviceScaleFactor;
+ int w = m_size.width() * deviceScaleFactor;
+ int h = m_size.height() * deviceScaleFactor;
+
+ if (m_hwndVideo)
+ ::MoveWindow(m_hwndVideo, x, y, w, h, FALSE);
+
+ RECT rc = { 0, 0, w, h };
+ videoDisplay->SetVideoPosition(nullptr, &rc);
+}
+
+void MediaPlayerPrivateMediaFoundation::paint(GraphicsContext& context, const FloatRect& rect)
+{
+ if (context.paintingDisabled() || !m_player->visible())
+ return;
+
+ m_lastPaintRect = rect;
+
+ if (m_presenter)
+ m_presenter->paintCurrentFrame(context, rect);
+}
+
+bool MediaPlayerPrivateMediaFoundation::createSession()
+{
+ if (!MFStartupPtr() || !MFCreateMediaSessionPtr())
+ return false;
+
+ if (FAILED(MFStartupPtr()(MF_VERSION, MFSTARTUP_FULL)))
+ return false;
+
+ if (FAILED(MFCreateMediaSessionPtr()(nullptr, &m_mediaSession)))
+ return false;
+
+ // Get next event.
+ AsyncCallback* callback = new AsyncCallback(this, true);
+ HRESULT hr = m_mediaSession->BeginGetEvent(callback, nullptr);
+ ASSERT(SUCCEEDED(hr));
+
+ return true;
+}
+
+bool MediaPlayerPrivateMediaFoundation::startSession()
+{
+ if (!m_mediaSession)
+ return false;
+
+ PROPVARIANT varStart;
+ PropVariantInit(&varStart);
+ varStart.vt = VT_EMPTY;
+
+ HRESULT hr = m_mediaSession->Start(nullptr, &varStart);
+ ASSERT(SUCCEEDED(hr));
+
+ PropVariantClear(&varStart);
+
+ return SUCCEEDED(hr);
+}
+
+bool MediaPlayerPrivateMediaFoundation::endSession()
+{
+ if (m_mediaSession) {
+ m_mediaSession->Shutdown();
+ m_mediaSession = nullptr;
+ }
+
+ if (!MFShutdownPtr())
+ return false;
+
+ HRESULT hr = MFShutdownPtr()();
+ ASSERT(SUCCEEDED(hr));
+
+ return true;
+}
+
+bool MediaPlayerPrivateMediaFoundation::startCreateMediaSource(const String& url)
+{
+ if (!MFCreateSourceResolverPtr())
+ return false;
+
+ if (FAILED(MFCreateSourceResolverPtr()(&m_sourceResolver)))
+ return false;
+
+ COMPtr<IUnknown> cancelCookie;
+ Vector<UChar> urlSource = url.charactersWithNullTermination();
+
+ AsyncCallback* callback = new AsyncCallback(this, false);
+
+ if (FAILED(m_sourceResolver->BeginCreateObjectFromURL(urlSource.data(), MF_RESOLUTION_MEDIASOURCE, nullptr, &cancelCookie, callback, nullptr)))
+ return false;
+
+ return true;
+}
+
+bool MediaPlayerPrivateMediaFoundation::endCreatedMediaSource(IMFAsyncResult* asyncResult)
+{
+ MF_OBJECT_TYPE objectType;
+ COMPtr<IUnknown> source;
+
+ HRESULT hr = m_sourceResolver->EndCreateObjectFromURL(asyncResult, &objectType, &source);
+ if (FAILED(hr))
+ return false;
+
+ hr = source->QueryInterface(IID_PPV_ARGS(&m_mediaSource));
+ if (FAILED(hr))
+ return false;
+
+ hr = asyncResult->GetStatus();
+ m_loadingProgress = SUCCEEDED(hr);
+
+ auto weakPtr = m_weakPtrFactory.createWeakPtr();
+ callOnMainThread([weakPtr] {
+ if (!weakPtr)
+ return;
+ weakPtr->onCreatedMediaSource();
+ });
+
+ return true;
+}
+
+bool MediaPlayerPrivateMediaFoundation::endGetEvent(IMFAsyncResult* asyncResult)
+{
+ COMPtr<IMFMediaEvent> event;
+
+ if (!m_mediaSession)
+ return false;
+
+ // Get the event from the event queue.
+ HRESULT hr = m_mediaSession->EndGetEvent(asyncResult, &event);
+ if (FAILED(hr))
+ return false;
+
+ // Get the event type.
+ MediaEventType mediaEventType;
+ hr = event->GetType(&mediaEventType);
+ if (FAILED(hr))
+ return false;
+
+ switch (mediaEventType) {
+ case MESessionTopologySet: {
+ auto weakPtr = m_weakPtrFactory.createWeakPtr();
+ callOnMainThread([weakPtr] {
+ if (!weakPtr)
+ return;
+ weakPtr->onTopologySet();
+ });
+ break;
+ }
+
+ case MEBufferingStarted: {
+ auto weakPtr = m_weakPtrFactory.createWeakPtr();
+ callOnMainThread([weakPtr] {
+ if (!weakPtr)
+ return;
+ weakPtr->onBufferingStarted();
+ });
+ break;
+ }
+
+ case MEBufferingStopped: {
+ auto weakPtr = m_weakPtrFactory.createWeakPtr();
+ callOnMainThread([weakPtr] {
+ if (!weakPtr)
+ return;
+ weakPtr->onBufferingStopped();
+ });
+ break;
+ }
+
+ case MESessionEnded: {
+ auto weakPtr = m_weakPtrFactory.createWeakPtr();
+ callOnMainThread([weakPtr] {
+ if (!weakPtr)
+ return;
+ weakPtr->onSessionEnded();
+ });
+ break;
+ }
+
+ case MEMediaSample:
+ break;
+
+ case MEError: {
+ HRESULT status = S_OK;
+ event->GetStatus(&status);
+ break;
+ }
+ }
+
+ if (mediaEventType != MESessionClosed) {
+ // For all other events, ask the media session for the
+ // next event in the queue.
+ AsyncCallback* callback = new AsyncCallback(this, true);
+
+ hr = m_mediaSession->BeginGetEvent(callback, nullptr);
+ if (FAILED(hr))
+ return false;
+ }
+
+ return true;
+}
+
+bool MediaPlayerPrivateMediaFoundation::createTopologyFromSource()
+{
+ if (!MFCreateTopologyPtr())
+ return false;
+
+ // Create a new topology.
+ if (FAILED(MFCreateTopologyPtr()(&m_topology)))
+ return false;
+
+ // Create the presentation descriptor for the media source.
+ if (FAILED(m_mediaSource->CreatePresentationDescriptor(&m_sourcePD)))
+ return false;
+
+ // Get the number of streams in the media source.
+ DWORD sourceStreams = 0;
+ if (FAILED(m_sourcePD->GetStreamDescriptorCount(&sourceStreams)))
+ return false;
+
+ // For each stream, create the topology nodes and add them to the topology.
+ for (DWORD i = 0; i < sourceStreams; i++) {
+ if (!addBranchToPartialTopology(i))
+ return false;
+ }
+
+ return true;
+}
+
+bool MediaPlayerPrivateMediaFoundation::addBranchToPartialTopology(int stream)
+{
+ // Get the stream descriptor for this stream.
+ COMPtr<IMFStreamDescriptor> sourceSD;
+ BOOL selected = FALSE;
+ if (FAILED(m_sourcePD->GetStreamDescriptorByIndex(stream, &selected, &sourceSD)))
+ return false;
+
+ // Create the topology branch only if the stream is selected.
+ // Otherwise, do nothing.
+ if (!selected)
+ return true;
+
+ // Create a source node for this stream.
+ COMPtr<IMFTopologyNode> sourceNode;
+ if (!createSourceStreamNode(sourceSD, sourceNode))
+ return false;
+
+ COMPtr<IMFTopologyNode> outputNode;
+ if (!createOutputNode(sourceSD, outputNode))
+ return false;
+
+ // Add both nodes to the topology.
+ if (FAILED(m_topology->AddNode(sourceNode.get())))
+ return false;
+
+ if (FAILED(m_topology->AddNode(outputNode.get())))
+ return false;
+
+ // Connect the source node to the output node.
+ if (FAILED(sourceNode->ConnectOutput(0, outputNode.get(), 0)))
+ return false;
+
+ return true;
+}
+
+LRESULT CALLBACK MediaPlayerPrivateMediaFoundation::VideoViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+LPCWSTR MediaPlayerPrivateMediaFoundation::registerVideoWindowClass()
+{
+ const LPCWSTR kVideoWindowClassName = L"WebVideoWindowClass";
+
+ static bool haveRegisteredWindowClass = false;
+ if (haveRegisteredWindowClass)
+ return kVideoWindowClassName;
+
+ haveRegisteredWindowClass = true;
+
+ WNDCLASSEX wcex;
+
+ wcex.cbSize = sizeof(WNDCLASSEX);
+
+ wcex.style = CS_DBLCLKS;
+ wcex.lpfnWndProc = VideoViewWndProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = nullptr;
+ wcex.hIcon = nullptr;
+ wcex.hCursor = ::LoadCursor(0, IDC_ARROW);
+ wcex.hbrBackground = nullptr;
+ wcex.lpszMenuName = nullptr;
+ wcex.lpszClassName = kVideoWindowClassName;
+ wcex.hIconSm = nullptr;
+
+ if (RegisterClassEx(&wcex))
+ return kVideoWindowClassName;
+
+ return nullptr;
+}
+
+void MediaPlayerPrivateMediaFoundation::createVideoWindow()
+{
+ HWND hWndParent = nullptr;
+ FrameView* view = nullptr;
+ if (!m_player || !m_player->cachedResourceLoader() || !m_player->cachedResourceLoader()->document())
+ return;
+ view = m_player->cachedResourceLoader()->document()->view();
+ if (!view || !view->hostWindow())
+ return;
+
+ PlatformPageClient pageClient = view->hostWindow()->platformPageClient();
+#if PLATFORM(QT)
+ QWindow* ownerWindow = pageClient->ownerWindow();
+ if (!ownerWindow)
+ return;
+ hWndParent = (HWND)ownerWindow->winId();
+#else
+ hWndParent = pageClient;
+#endif
+
+ m_hwndVideo = CreateWindowEx(WS_EX_NOACTIVATE | WS_EX_TRANSPARENT, registerVideoWindowClass(), 0, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
+ 0, 0, 0, 0, hWndParent, 0, 0, 0);
+}
+
+void MediaPlayerPrivateMediaFoundation::destroyVideoWindow()
+{
+ if (m_hwndVideo) {
+ DestroyWindow(m_hwndVideo);
+ m_hwndVideo = nullptr;
+ }
+}
+
+void MediaPlayerPrivateMediaFoundation::invalidateFrameView()
+{
+ FrameView* view = nullptr;
+ if (!m_player || !m_player->cachedResourceLoader() || !m_player->cachedResourceLoader()->document())
+ return;
+ view = m_player->cachedResourceLoader()->document()->view();
+ if (!view)
+ return;
+
+ view->invalidate();
+}
+
+void MediaPlayerPrivateMediaFoundation::addListener(MediaPlayerListener* listener)
+{
+ LockHolder locker(m_mutexListeners);
+
+ m_listeners.add(listener);
+}
+
+void MediaPlayerPrivateMediaFoundation::removeListener(MediaPlayerListener* listener)
+{
+ LockHolder locker(m_mutexListeners);
+
+ m_listeners.remove(listener);
+}
+
+void MediaPlayerPrivateMediaFoundation::notifyDeleted()
+{
+ LockHolder locker(m_mutexListeners);
+
+ for (HashSet<MediaPlayerListener*>::const_iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
+ (*it)->onMediaPlayerDeleted();
+}
+
+bool MediaPlayerPrivateMediaFoundation::createOutputNode(COMPtr<IMFStreamDescriptor> sourceSD, COMPtr<IMFTopologyNode>& node)
+{
+ if (!MFCreateTopologyNodePtr() || !MFCreateAudioRendererActivatePtr() || !MFCreateVideoRendererActivatePtr())
+ return false;
+
+ if (!sourceSD)
+ return false;
+
+#ifndef NDEBUG
+ // Get the stream ID.
+ DWORD streamID = 0;
+ sourceSD->GetStreamIdentifier(&streamID); // Just for debugging, ignore any failures.
+#endif
+
+ COMPtr<IMFMediaTypeHandler> handler;
+ if (FAILED(sourceSD->GetMediaTypeHandler(&handler)))
+ return false;
+
+ GUID guidMajorType = GUID_NULL;
+ if (FAILED(handler->GetMajorType(&guidMajorType)))
+ return false;
+
+ // Create a downstream node.
+ if (FAILED(MFCreateTopologyNodePtr()(MF_TOPOLOGY_OUTPUT_NODE, &node)))
+ return false;
+
+ // Create an IMFActivate object for the renderer, based on the media type.
+ COMPtr<IMFActivate> rendererActivate;
+ if (MFMediaType_Audio == guidMajorType) {
+ // Create the audio renderer.
+ if (FAILED(MFCreateAudioRendererActivatePtr()(&rendererActivate)))
+ return false;
+ m_hasAudio = true;
+ } else if (MFMediaType_Video == guidMajorType) {
+ // Create the video renderer.
+ if (FAILED(MFCreateVideoRendererActivatePtr()(nullptr, &rendererActivate)))
+ return false;
+
+ m_presenter = new CustomVideoPresenter(this);
+ m_presenter->SetVideoWindow(m_hwndVideo);
+ if (FAILED(rendererActivate->SetUnknown(MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_ACTIVATE, static_cast<IMFActivate*>(m_presenter.get()))))
+ return false;
+ m_hasVideo = true;
+ } else
+ return false;
+
+ // Set the IActivate object on the output node.
+ if (FAILED(node->SetObject(rendererActivate.get())))
+ return false;
+
+ return true;
+}
+
+bool MediaPlayerPrivateMediaFoundation::createSourceStreamNode(COMPtr<IMFStreamDescriptor> sourceSD, COMPtr<IMFTopologyNode>& node)
+{
+ if (!MFCreateTopologyNodePtr())
+ return false;
+
+ if (!m_mediaSource || !m_sourcePD || !sourceSD)
+ return false;
+
+ // Create the source-stream node.
+ HRESULT hr = MFCreateTopologyNodePtr()(MF_TOPOLOGY_SOURCESTREAM_NODE, &node);
+ if (FAILED(hr))
+ return false;
+
+ // Set attribute: Pointer to the media source.
+ hr = node->SetUnknown(MF_TOPONODE_SOURCE, m_mediaSource.get());
+ if (FAILED(hr))
+ return false;
+
+ // Set attribute: Pointer to the presentation descriptor.
+ hr = node->SetUnknown(MF_TOPONODE_PRESENTATION_DESCRIPTOR, m_sourcePD.get());
+ if (FAILED(hr))
+ return false;
+
+ // Set attribute: Pointer to the stream descriptor.
+ hr = node->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, sourceSD.get());
+ if (FAILED(hr))
+ return false;
+
+ return true;
+}
+
+void MediaPlayerPrivateMediaFoundation::updateReadyState()
+{
+ if (!MFGetServicePtr())
+ return;
+
+ COMPtr<IPropertyStore> prop;
+
+ // Get the property store from the media session.
+ HRESULT hr = MFGetServicePtr()(m_mediaSession.get(), MFNETSOURCE_STATISTICS_SERVICE, IID_PPV_ARGS(&prop));
+
+ if (FAILED(hr))
+ return;
+
+ PROPERTYKEY key;
+ key.fmtid = MFNETSOURCE_STATISTICS;
+ key.pid = MFNETSOURCE_BUFFERPROGRESS_ID;
+
+ PROPVARIANT var;
+ hr = prop->GetValue(key, &var);
+
+ const LONG percentageOfPlaybackBufferFilled = var.lVal;
+
+ PropVariantClear(&var);
+
+ if (FAILED(hr))
+ return;
+
+ MediaPlayer::ReadyState oldReadyState = m_readyState;
+ if (percentageOfPlaybackBufferFilled >= 100) {
+ m_readyState = MediaPlayer::HaveEnoughData;
+ if (m_preparingToPlay) {
+ pause();
+ m_preparingToPlay = false;
+ }
+ } else if (percentageOfPlaybackBufferFilled > 0)
+ m_readyState = MediaPlayer::HaveFutureData;
+ else
+ m_readyState = MediaPlayer::HaveCurrentData;
+
+ if (m_readyState != oldReadyState)
+ m_player->readyStateChanged();
+}
+
+COMPtr<IMFVideoDisplayControl> MediaPlayerPrivateMediaFoundation::videoDisplay()
+{
+ if (m_videoDisplay)
+ return m_videoDisplay;
+
+ if (!MFGetServicePtr())
+ return nullptr;
+
+ MFGetServicePtr()(m_mediaSession.get(), MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_videoDisplay));
+
+ return m_videoDisplay;
+}
+
+void MediaPlayerPrivateMediaFoundation::onCreatedMediaSource()
+{
+ if (!createTopologyFromSource())
+ return;
+
+ // Set the topology on the media session.
+ HRESULT hr = m_mediaSession->SetTopology(0, m_topology.get());
+ ASSERT(SUCCEEDED(hr));
+}
+
+void MediaPlayerPrivateMediaFoundation::onTopologySet()
+{
+ // This method is called on the main thread as a result of load() being called.
+
+ if (auto videoDisplay = this->videoDisplay()) {
+ RECT rc = { 0, 0, m_size.width(), m_size.height() };
+ videoDisplay->SetVideoPosition(nullptr, &rc);
+ }
+
+ // It is expected that we start buffering data from the network now.
+ prepareToPlay();
+}
+
+void MediaPlayerPrivateMediaFoundation::onBufferingStarted()
+{
+ updateReadyState();
+}
+
+void MediaPlayerPrivateMediaFoundation::onBufferingStopped()
+{
+ updateReadyState();
+}
+
+void MediaPlayerPrivateMediaFoundation::onSessionEnded()
+{
+ m_networkState = MediaPlayer::Loaded;
+ m_player->networkStateChanged();
+
+ m_paused = true;
+ m_player->playbackStateChanged();
+}
+
+MediaPlayerPrivateMediaFoundation::AsyncCallback::AsyncCallback(MediaPlayerPrivateMediaFoundation* mediaPlayer, bool event)
+ : m_refCount(0)
+ , m_mediaPlayer(mediaPlayer)
+ , m_event(event)
+{
+ if (m_mediaPlayer)
+ m_mediaPlayer->addListener(this);
+}
+
+MediaPlayerPrivateMediaFoundation::AsyncCallback::~AsyncCallback()
+{
+ if (m_mediaPlayer)
+ m_mediaPlayer->removeListener(this);
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::AsyncCallback::QueryInterface(_In_ REFIID riid, __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+ if (!IsEqualGUID(riid, IID_IMFAsyncCallback)) {
+ *ppvObject = nullptr;
+ return E_NOINTERFACE;
+ }
+ *ppvObject = this;
+ AddRef();
+ return S_OK;
+}
+
+ULONG STDMETHODCALLTYPE MediaPlayerPrivateMediaFoundation::AsyncCallback::AddRef()
+{
+ m_refCount++;
+ return m_refCount;
+}
+
+ULONG STDMETHODCALLTYPE MediaPlayerPrivateMediaFoundation::AsyncCallback::Release()
+{
+ m_refCount--;
+ ULONG refCount = m_refCount;
+ if (!refCount)
+ delete this;
+ return refCount;
+}
+
+HRESULT STDMETHODCALLTYPE MediaPlayerPrivateMediaFoundation::AsyncCallback::GetParameters(__RPC__out DWORD *pdwFlags, __RPC__out DWORD *pdwQueue)
+{
+ // Returning E_NOTIMPL gives default values.
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE MediaPlayerPrivateMediaFoundation::AsyncCallback::Invoke(__RPC__in_opt IMFAsyncResult *pAsyncResult)
+{
+ LockHolder locker(m_mutex);
+
+ if (!m_mediaPlayer)
+ return S_OK;
+
+ if (m_event)
+ m_mediaPlayer->endGetEvent(pAsyncResult);
+ else
+ m_mediaPlayer->endCreatedMediaSource(pAsyncResult);
+
+ return S_OK;
+}
+
+void MediaPlayerPrivateMediaFoundation::AsyncCallback::onMediaPlayerDeleted()
+{
+ LockHolder locker(m_mutex);
+
+ m_mediaPlayer = nullptr;
+}
+
+MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::CustomVideoPresenter(MediaPlayerPrivateMediaFoundation* mediaPlayer)
+ : m_mediaPlayer(mediaPlayer)
+{
+ if (m_mediaPlayer)
+ m_mediaPlayer->addListener(this);
+
+ m_sourceRect.top = 0;
+ m_sourceRect.left = 0;
+ m_sourceRect.bottom = 1;
+ m_sourceRect.right = 1;
+
+ m_presenterEngine = std::make_unique<Direct3DPresenter>();
+ if (!m_presenterEngine)
+ return;
+
+ m_scheduler.setPresenter(m_presenterEngine.get());
+}
+
+MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::~CustomVideoPresenter()
+{
+ if (m_mediaPlayer)
+ m_mediaPlayer->removeListener(this);
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::QueryInterface(REFIID riid, __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject)
+{
+ *ppvObject = nullptr;
+ if (IsEqualGUID(riid, IID_IMFGetService))
+ *ppvObject = static_cast<IMFGetService*>(this);
+ else if (IsEqualGUID(riid, IID_IMFActivate))
+ *ppvObject = static_cast<IMFActivate*>(this);
+ else if (IsEqualGUID(riid, IID_IMFVideoDisplayControl))
+ *ppvObject = static_cast<IMFVideoDisplayControl*>(this);
+ else if (IsEqualGUID(riid, IID_IMFVideoPresenter))
+ *ppvObject = static_cast<IMFVideoPresenter*>(this);
+ else if (IsEqualGUID(riid, IID_IMFClockStateSink))
+ *ppvObject = static_cast<IMFClockStateSink*>(this);
+ else if (IsEqualGUID(riid, IID_IMFVideoDeviceID))
+ *ppvObject = static_cast<IMFVideoDeviceID*>(this);
+ else if (IsEqualGUID(riid, IID_IMFTopologyServiceLookupClient))
+ *ppvObject = static_cast<IMFTopologyServiceLookupClient*>(this);
+ else if (IsEqualGUID(riid, IID_IUnknown))
+ *ppvObject = static_cast<IMFVideoPresenter*>(this);
+ else if (IsEqualGUID(riid, IID_IMFAsyncCallback))
+ *ppvObject = static_cast<IMFAsyncCallback*>(this);
+ else
+ return E_NOINTERFACE;
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::AddRef()
+{
+ m_refCount++;
+ return m_refCount;
+}
+
+ULONG MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::Release()
+{
+ m_refCount--;
+ ULONG refCount = m_refCount;
+ if (!refCount)
+ delete this;
+ return refCount;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset)
+{
+ LockHolder locker(m_lock);
+
+ // After shutdown, we cannot start.
+ HRESULT hr = checkShutdown();
+ if (FAILED(hr))
+ return hr;
+
+ m_renderState = RenderStateStarted;
+
+ if (isActive()) {
+ if (llClockStartOffset != PRESENTATION_CURRENT_POSITION) {
+ // This is a seek request, flush pending samples.
+ flush();
+ }
+ }
+
+ processOutputLoop();
+
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::OnClockStop(MFTIME hnsSystemTime)
+{
+ LockHolder locker(m_lock);
+
+ HRESULT hr = checkShutdown();
+ if (FAILED(hr))
+ return hr;
+
+ if (m_renderState != RenderStateStopped) {
+ m_renderState = RenderStateStopped;
+ flush();
+ }
+
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::OnClockPause(MFTIME hnsSystemTime)
+{
+ LockHolder locker(m_lock);
+
+ // After shutdown, we cannot pause.
+ HRESULT hr = checkShutdown();
+ if (FAILED(hr))
+ return hr;
+
+ m_renderState = RenderStatePaused;
+
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::OnClockRestart(MFTIME hnsSystemTime)
+{
+ LockHolder locker(m_lock);
+
+ HRESULT hr = checkShutdown();
+ if (FAILED(hr))
+ return hr;
+
+ ASSERT(m_renderState == RenderStatePaused);
+
+ m_renderState = RenderStateStarted;
+
+ processOutputLoop();
+
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::OnClockSetRate(MFTIME hnsSystemTime, float rate)
+{
+ LockHolder locker(m_lock);
+
+ HRESULT hr = checkShutdown();
+ if (FAILED(hr))
+ return hr;
+
+ m_rate = rate;
+
+ m_scheduler.setClockRate(rate);
+
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::ProcessMessage(MFVP_MESSAGE_TYPE eMessage, ULONG_PTR ulParam)
+{
+ LockHolder locker(m_lock);
+
+ HRESULT hr = checkShutdown();
+ if (FAILED(hr))
+ return hr;
+
+ switch (eMessage) {
+ case MFVP_MESSAGE_FLUSH:
+ hr = flush();
+ break;
+
+ case MFVP_MESSAGE_INVALIDATEMEDIATYPE:
+ hr = renegotiateMediaType();
+ break;
+
+ case MFVP_MESSAGE_PROCESSINPUTNOTIFY:
+ // A new input sample is available.
+ hr = processInputNotify();
+ break;
+
+ case MFVP_MESSAGE_BEGINSTREAMING:
+ hr = beginStreaming();
+ break;
+
+ case MFVP_MESSAGE_ENDSTREAMING:
+ hr = endStreaming();
+ break;
+
+ case MFVP_MESSAGE_ENDOFSTREAM:
+ m_endStreaming = true;
+ hr = checkEndOfStream();
+ break;
+
+ default:
+ hr = E_INVALIDARG;
+ break;
+ }
+
+ return hr;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::GetCurrentMediaType(_Outptr_ IMFVideoMediaType **ppMediaType)
+{
+ LockHolder locker(m_lock);
+
+ if (!ppMediaType)
+ return E_POINTER;
+
+ HRESULT hr = checkShutdown();
+ if (FAILED(hr))
+ return hr;
+
+ if (!m_mediaType)
+ return MF_E_NOT_INITIALIZED;
+
+ return m_mediaType->QueryInterface(__uuidof(IMFVideoMediaType), (void**)&ppMediaType);
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::GetDeviceID(IID* pDeviceID)
+{
+ if (!pDeviceID)
+ return E_POINTER;
+
+ *pDeviceID = __uuidof(IDirect3DDevice9);
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::InitServicePointers(IMFTopologyServiceLookup *pLookup)
+{
+ if (!pLookup)
+ return E_POINTER;
+
+ HRESULT hr = S_OK;
+
+ LockHolder locker(m_lock);
+
+ if (isActive())
+ return MF_E_INVALIDREQUEST;
+
+ m_clock = nullptr;
+ m_mixer = nullptr;
+ m_mediaEventSink = nullptr;
+
+ // Lookup the services.
+
+ DWORD objectCount = 1;
+ hr = pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_clock), &objectCount);
+ // The clock service is optional.
+
+ objectCount = 1;
+ hr = pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_MIXER_SERVICE, IID_PPV_ARGS(&m_mixer), &objectCount);
+ if (FAILED(hr))
+ return hr;
+
+ hr = configureMixer(m_mixer.get());
+ if (FAILED(hr))
+ return hr;
+
+ objectCount = 1;
+ hr = pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_mediaEventSink), &objectCount);
+ if (FAILED(hr))
+ return hr;
+
+ m_renderState = RenderStateStopped;
+
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::ReleaseServicePointers()
+{
+ LockHolder locker(m_lock);
+
+ m_renderState = RenderStateShutdown;
+
+ flush();
+
+ setMediaType(nullptr);
+
+ m_clock = nullptr;
+ m_mixer = nullptr;
+ m_mediaEventSink = nullptr;
+
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::GetService(REFGUID guidService, REFIID riid, LPVOID* ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+
+ // We only support MR_VIDEO_RENDER_SERVICE.
+ if (guidService != MR_VIDEO_RENDER_SERVICE)
+ return MF_E_UNSUPPORTED_SERVICE;
+
+ HRESULT hr = m_presenterEngine->getService(guidService, riid, ppvObject);
+
+ if (FAILED(hr))
+ hr = QueryInterface(riid, ppvObject);
+
+ return hr;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::ActivateObject(REFIID riid, void **ppv)
+{
+ if (!ppv)
+ return E_POINTER;
+
+ if (riid == IID_IMFVideoPresenter) {
+ *ppv = static_cast<IMFVideoPresenter*>(this);
+ AddRef();
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::DetachObject()
+{
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::ShutdownObject()
+{
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::SetVideoWindow(HWND hwndVideo)
+{
+ LockHolder locker(m_lock);
+
+ if (!IsWindow(hwndVideo))
+ return E_INVALIDARG;
+
+ HRESULT hr = S_OK;
+ HWND oldHwnd = m_presenterEngine->getVideoWindow();
+
+ if (oldHwnd != hwndVideo) {
+ // This will create a new Direct3D device.
+ hr = m_presenterEngine->setVideoWindow(hwndVideo);
+
+ notifyEvent(EC_DISPLAY_CHANGED, 0, 0);
+ }
+
+ return hr;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::GetVideoWindow(HWND* phwndVideo)
+{
+ LockHolder locker(m_lock);
+
+ if (!phwndVideo)
+ return E_POINTER;
+
+ *phwndVideo = m_presenterEngine->getVideoWindow();
+
+ return S_OK;
+}
+
+static HRESULT setMixerSourceRect(IMFTransform* mixer, const MFVideoNormalizedRect& sourceRect)
+{
+ if (!mixer)
+ return E_POINTER;
+
+ COMPtr<IMFAttributes> attributes;
+
+ HRESULT hr = mixer->GetAttributes(&attributes);
+ if (FAILED(hr))
+ return hr;
+
+ return attributes->SetBlob(VIDEO_ZOOM_RECT, (const UINT8*)&sourceRect, sizeof(sourceRect));
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::SetVideoPosition(const MFVideoNormalizedRect* pnrcSource, const LPRECT prcDest)
+{
+ LockHolder locker(m_lock);
+
+ // First, check that the parameters are valid.
+
+ if (!pnrcSource && !prcDest)
+ return E_POINTER;
+
+ if (pnrcSource) {
+ if ((pnrcSource->left > pnrcSource->right) || (pnrcSource->top > pnrcSource->bottom))
+ return E_INVALIDARG;
+
+ // The source rectangle must be normalized.
+ if ((pnrcSource->left < 0) || (pnrcSource->right > 1) || (pnrcSource->top < 0) || (pnrcSource->bottom > 1))
+ return E_INVALIDARG;
+ }
+
+ if (prcDest) {
+ if ((prcDest->left > prcDest->right) || (prcDest->top > prcDest->bottom))
+ return E_INVALIDARG;
+ }
+
+ HRESULT hr = S_OK;
+
+ // Set the source rectangle.
+ if (pnrcSource) {
+ m_sourceRect = *pnrcSource;
+
+ if (m_mixer) {
+ hr = setMixerSourceRect(m_mixer.get(), m_sourceRect);
+ if (FAILED(hr))
+ return hr;
+ }
+ }
+
+ // Set the destination rectangle.
+ if (prcDest) {
+ RECT rcOldDest = m_presenterEngine->getDestinationRect();
+
+ // If the destination rectangle hasn't changed, we are done.
+ if (!EqualRect(&rcOldDest, prcDest)) {
+ hr = m_presenterEngine->setDestinationRect(*prcDest);
+ if (FAILED(hr))
+ return hr;
+
+ // We need to change the media type when the destination rectangle has changed.
+ if (m_mixer) {
+ hr = renegotiateMediaType();
+ if (hr == MF_E_TRANSFORM_TYPE_NOT_SET) {
+ // This is not a critical failure; the EVR will let us know when
+ // we have to set the mixer media type.
+ hr = S_OK;
+ } else {
+ if (FAILED(hr))
+ return hr;
+
+ // We have successfully changed the media type,
+ // ask for a repaint of the current frame.
+ m_repaint = true;
+ processOutput();
+ }
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::GetVideoPosition(MFVideoNormalizedRect* pnrcSource, LPRECT prcDest)
+{
+ LockHolder locker(m_lock);
+
+ if (!pnrcSource || !prcDest)
+ return E_POINTER;
+
+ *pnrcSource = m_sourceRect;
+ *prcDest = m_presenterEngine->getDestinationRect();
+
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::RepaintVideo()
+{
+ LockHolder locker(m_lock);
+
+ HRESULT hr = checkShutdown();
+ if (FAILED(hr))
+ return hr;
+
+ // Check that at least one sample has been presented.
+ if (m_prerolled) {
+ m_repaint = true;
+ processOutput();
+ }
+
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::Invoke(IMFAsyncResult* pAsyncResult)
+{
+ return onSampleFree(pAsyncResult);
+}
+
+void MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::onMediaPlayerDeleted()
+{
+ m_mediaPlayer = nullptr;
+}
+
+void MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::paintCurrentFrame(GraphicsContext& context, const FloatRect& r)
+{
+ if (m_presenterEngine)
+ m_presenterEngine->paintCurrentFrame(context, r);
+}
+
+float MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::currentTime()
+{
+ if (!m_clock)
+ return 0.0f;
+
+ LONGLONG clockTime;
+ MFTIME systemTime;
+ HRESULT hr = m_clock->GetCorrelatedTime(0, &clockTime, &systemTime);
+
+ if (FAILED(hr))
+ return 0.0f;
+
+ // clockTime is in 100 nanoseconds, we need to convert to seconds.
+ float currentTime = clockTime / tenMegahertz;
+
+ if (currentTime > m_maxTimeLoaded)
+ m_maxTimeLoaded = currentTime;
+
+ return currentTime;
+}
+
+bool MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::isActive() const
+{
+ return ((m_renderState == RenderStateStarted) || (m_renderState == RenderStatePaused));
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::configureMixer(IMFTransform* mixer)
+{
+ COMPtr<IMFVideoDeviceID> videoDeviceID;
+ HRESULT hr = mixer->QueryInterface(__uuidof(IMFVideoDeviceID), (void**)&videoDeviceID);
+ if (FAILED(hr))
+ return hr;
+
+ IID deviceID = GUID_NULL;
+ hr = videoDeviceID->GetDeviceID(&deviceID);
+ if (FAILED(hr))
+ return hr;
+
+ // The mixer must have this device ID.
+ if (!IsEqualGUID(deviceID, __uuidof(IDirect3DDevice9)))
+ return MF_E_INVALIDREQUEST;
+
+ setMixerSourceRect(mixer, m_sourceRect);
+
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::flush()
+{
+ m_prerolled = false;
+
+ // Flush the sceduler.
+ // This call will block until the scheduler thread has finished flushing.
+ m_scheduler.flush();
+
+ if (m_renderState == RenderStateStopped)
+ m_presenterEngine->presentSample(nullptr, 0);
+
+ return S_OK;
+}
+
+static bool areMediaTypesEqual(IMFMediaType* type1, IMFMediaType* type2)
+{
+ if (!type1 && !type2)
+ return true;
+ if (!type1 || !type2)
+ return false;
+
+ DWORD flags = 0;
+ return S_OK == type1->IsEqual(type2, &flags);
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::setMediaType(IMFMediaType* mediaType)
+{
+ if (!mediaType) {
+ m_mediaType = nullptr;
+ releaseResources();
+ return S_OK;
+ }
+
+ // If we have shut down, we cannot set the media type.
+ HRESULT hr = checkShutdown();
+ if (FAILED(hr)) {
+ releaseResources();
+ return hr;
+ }
+
+ if (areMediaTypesEqual(m_mediaType.get(), mediaType))
+ return S_OK;
+
+ m_mediaType = nullptr;
+ releaseResources();
+
+ // Get allocated samples from the presenter.
+ VideoSampleList sampleQueue;
+ hr = m_presenterEngine->createVideoSamples(mediaType, sampleQueue);
+ if (FAILED(hr)) {
+ releaseResources();
+ return hr;
+ }
+
+ // Set the token counter on each sample.
+ // This will help us to determine when they are invalid, and can be released.
+ for (auto sample : sampleQueue) {
+ hr = sample->SetUINT32(MFSamplePresenterSampleCounter, m_tokenCounter);
+ if (FAILED(hr)) {
+ releaseResources();
+ return hr;
+ }
+ }
+
+ // Add the samples to the sample pool.
+ hr = m_samplePool.initialize(sampleQueue);
+ if (FAILED(hr)) {
+ releaseResources();
+ return hr;
+ }
+
+ // Set the frame rate.
+ MFRatio fps = { 0, 0 };
+ hr = MFGetAttributeRatio(mediaType, MF_MT_FRAME_RATE, (UINT32*)&fps.Numerator, (UINT32*)&fps.Denominator);
+ if (SUCCEEDED(hr) && fps.Numerator && fps.Denominator)
+ m_scheduler.setFrameRate(fps);
+ else {
+ // We could not get the frame ret, use default.
+ const MFRatio defaultFrameRate = { 30, 1 };
+ m_scheduler.setFrameRate(defaultFrameRate);
+ }
+
+ ASSERT(mediaType);
+ m_mediaType = mediaType;
+
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::checkShutdown() const
+{
+ if (m_renderState == RenderStateShutdown)
+ return MF_E_SHUTDOWN;
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::renegotiateMediaType()
+{
+ HRESULT hr = S_OK;
+
+ if (!m_mixer)
+ return MF_E_INVALIDREQUEST;
+
+ // Iterate over the available output types of the mixer.
+
+ DWORD typeIndex = 0;
+ bool foundMediaType = false;
+ while (!foundMediaType && (hr != MF_E_NO_MORE_TYPES)) {
+ // Get the next available media type.
+ COMPtr<IMFMediaType> mixerType;
+ hr = m_mixer->GetOutputAvailableType(0, typeIndex++, &mixerType);
+ if (FAILED(hr))
+ break;
+
+ // Do we support this media type?
+ hr = isMediaTypeSupported(mixerType.get());
+ if (FAILED(hr))
+ break;
+
+ // Make adjustments to proposed media type.
+ COMPtr<IMFMediaType> optimalType;
+ hr = createOptimalVideoType(mixerType.get(), &optimalType);
+ if (FAILED(hr))
+ break;
+
+ // Test whether the mixer can accept the modified media type
+ hr = m_mixer->SetOutputType(0, optimalType.get(), MFT_SET_TYPE_TEST_ONLY);
+ if (FAILED(hr))
+ break;
+
+ // Try to set the new media type
+
+ hr = setMediaType(optimalType.get());
+ if (FAILED(hr))
+ break;
+
+ hr = m_mixer->SetOutputType(0, optimalType.get(), 0);
+
+ ASSERT(SUCCEEDED(hr));
+
+ if (FAILED(hr))
+ setMediaType(nullptr);
+ else
+ foundMediaType = true;
+ }
+
+ return hr;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::processInputNotify()
+{
+ // We have a new sample.
+ m_sampleNotify = true;
+
+ if (!m_mediaType) {
+ // The media type is not valid.
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+ }
+
+ // Invalidate the video area
+ if (m_mediaPlayer) {
+ auto weakPtr = m_mediaPlayer->m_weakPtrFactory.createWeakPtr();
+ callOnMainThread([weakPtr] {
+ if (weakPtr)
+ weakPtr->invalidateFrameView();
+ });
+ }
+
+ // Process sample
+ processOutputLoop();
+
+ return S_OK;
+}
+
+static float MFOffsetToFloat(const MFOffset& offset)
+{
+ const int denominator = std::numeric_limits<WORD>::max() + 1;
+ return offset.value + (float(offset.fract) / denominator);
+}
+
+static MFOffset MakeOffset(float v)
+{
+ // v = offset.value + (offset.fract / denominator), where denominator = 65536.0f.
+ const int denominator = std::numeric_limits<WORD>::max() + 1;
+ MFOffset offset;
+ offset.value = short(v);
+ offset.fract = WORD(denominator * (v - offset.value));
+ return offset;
+}
+
+static MFVideoArea MakeArea(float x, float y, DWORD width, DWORD height)
+{
+ MFVideoArea area;
+ area.OffsetX = MakeOffset(x);
+ area.OffsetY = MakeOffset(y);
+ area.Area.cx = width;
+ area.Area.cy = height;
+ return area;
+}
+
+static HRESULT validateVideoArea(const MFVideoArea& area, UINT32 width, UINT32 height)
+{
+ float fOffsetX = MFOffsetToFloat(area.OffsetX);
+ float fOffsetY = MFOffsetToFloat(area.OffsetY);
+
+ if (((LONG)fOffsetX + area.Area.cx > width) || ((LONG)fOffsetY + area.Area.cy > height))
+ return MF_E_INVALIDMEDIATYPE;
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::beginStreaming()
+{
+ return m_scheduler.startScheduler(m_clock.get());
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::endStreaming()
+{
+ return m_scheduler.stopScheduler();
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::checkEndOfStream()
+{
+ if (!m_endStreaming) {
+ // We have not received the end-of-stream message from the EVR.
+ return S_OK;
+ }
+
+ if (m_sampleNotify) {
+ // There is still input samples available for the mixer.
+ return S_OK;
+ }
+
+ if (m_samplePool.areSamplesPending()) {
+ // There are samples scheduled for rendering.
+ return S_OK;
+ }
+
+ // We are done, notify the EVR.
+ notifyEvent(EC_COMPLETE, (LONG_PTR)S_OK, 0);
+ m_endStreaming = false;
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::isMediaTypeSupported(IMFMediaType* mediaType)
+{
+ COMPtr<IMFMediaType> proposedVideoType = mediaType;
+
+ // We don't support compressed media types.
+ BOOL compressed = FALSE;
+ HRESULT hr = proposedVideoType->IsCompressedFormat(&compressed);
+ if (FAILED(hr))
+ return hr;
+ if (compressed)
+ return MF_E_INVALIDMEDIATYPE;
+
+ // Validate the format.
+ GUID guidSubType = GUID_NULL;
+ hr = proposedVideoType->GetGUID(MF_MT_SUBTYPE, &guidSubType);
+ if (FAILED(hr))
+ return hr;
+ D3DFORMAT d3dFormat = (D3DFORMAT)guidSubType.Data1;
+
+ // Check if the format can be used as backbuffer format.
+ hr = m_presenterEngine->checkFormat(d3dFormat);
+ if (FAILED(hr))
+ return hr;
+
+ // Check interlaced formats.
+ MFVideoInterlaceMode interlaceMode = MFVideoInterlace_Unknown;
+ hr = proposedVideoType->GetUINT32(MF_MT_INTERLACE_MODE, (UINT32*)&interlaceMode);
+ if (FAILED(hr))
+ return hr;
+
+ if (interlaceMode != MFVideoInterlace_Progressive)
+ return MF_E_INVALIDMEDIATYPE;
+
+ UINT32 width = 0, height = 0;
+ hr = MFGetAttributeSize(proposedVideoType.get(), MF_MT_FRAME_SIZE, &width, &height);
+ if (FAILED(hr))
+ return hr;
+
+ // Validate apertures.
+ MFVideoArea videoCropArea;
+ if (SUCCEEDED(proposedVideoType->GetBlob(MF_MT_PAN_SCAN_APERTURE, (UINT8*)&videoCropArea, sizeof(MFVideoArea), nullptr)))
+ validateVideoArea(videoCropArea, width, height);
+ if (SUCCEEDED(proposedVideoType->GetBlob(MF_MT_GEOMETRIC_APERTURE, (UINT8*)&videoCropArea, sizeof(MFVideoArea), nullptr)))
+ validateVideoArea(videoCropArea, width, height);
+ if (SUCCEEDED(proposedVideoType->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE, (UINT8*)&videoCropArea, sizeof(MFVideoArea), nullptr)))
+ validateVideoArea(videoCropArea, width, height);
+
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::createOptimalVideoType(IMFMediaType* proposedType, IMFMediaType** optimalType)
+{
+ COMPtr<IMFMediaType> optimalVideoType;
+ HRESULT hr = MFCreateMediaTypePtr()(&optimalVideoType);
+ if (FAILED(hr))
+ return hr;
+ hr = optimalVideoType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
+ if (FAILED(hr))
+ return hr;
+
+ hr = proposedType->CopyAllItems(optimalVideoType.get());
+ if (FAILED(hr))
+ return hr;
+
+ // We now modify the new media type.
+
+ // We assume that the monitor's pixel aspect ratio is 1:1,
+ // and that the pixel aspect ratio is preserved by the presenter.
+ hr = MFSetAttributeRatio(optimalVideoType.get(), MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
+ if (FAILED(hr))
+ return hr;
+
+ // Get the output rectangle.
+ RECT rcOutput = m_presenterEngine->getDestinationRect();
+ if (IsRectEmpty(&rcOutput)) {
+ hr = calculateOutputRectangle(proposedType, rcOutput);
+ if (FAILED(hr))
+ return hr;
+ }
+
+ hr = optimalVideoType->SetUINT32(MF_MT_YUV_MATRIX, MFVideoTransferMatrix_BT709);
+ if (FAILED(hr))
+ return hr;
+
+ hr = optimalVideoType->SetUINT32(MF_MT_TRANSFER_FUNCTION, MFVideoTransFunc_709);
+ if (FAILED(hr))
+ return hr;
+
+ hr = optimalVideoType->SetUINT32(MF_MT_VIDEO_PRIMARIES, MFVideoPrimaries_BT709);
+ if (FAILED(hr))
+ return hr;
+
+ hr = optimalVideoType->SetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_16_235);
+ if (FAILED(hr))
+ return hr;
+
+ hr = optimalVideoType->SetUINT32(MF_MT_VIDEO_LIGHTING, MFVideoLighting_dim);
+ if (FAILED(hr))
+ return hr;
+
+ hr = MFSetAttributeSize(optimalVideoType.get(), MF_MT_FRAME_SIZE, rcOutput.right, rcOutput.bottom);
+ if (FAILED(hr))
+ return hr;
+
+ MFVideoArea displayArea = MakeArea(0, 0, rcOutput.right, rcOutput.bottom);
+
+ hr = optimalVideoType->SetUINT32(MF_MT_PAN_SCAN_ENABLED, FALSE);
+ if (FAILED(hr))
+ return hr;
+
+ hr = optimalVideoType->SetBlob(MF_MT_GEOMETRIC_APERTURE, (UINT8*)&displayArea, sizeof(MFVideoArea));
+ if (FAILED(hr))
+ return hr;
+
+ hr = optimalVideoType->SetBlob(MF_MT_PAN_SCAN_APERTURE, (UINT8*)&displayArea, sizeof(MFVideoArea));
+ if (FAILED(hr))
+ return hr;
+
+ hr = optimalVideoType->SetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE, (UINT8*)&displayArea, sizeof(MFVideoArea));
+ if (FAILED(hr))
+ return hr;
+
+ *optimalType = optimalVideoType.leakRef();
+
+ return S_OK;
+}
+
+static RECT correctAspectRatio(const RECT& src, const MFRatio& srcPAR, const MFRatio& destPAR)
+{
+ RECT rc = { 0, 0, src.right - src.left, src.bottom - src.top };
+
+ if ((srcPAR.Numerator * destPAR.Denominator) != (srcPAR.Denominator * destPAR.Numerator)) {
+ // The source and destination aspect ratios are different
+
+ // Transform the source aspect ratio to 1:1
+ if (srcPAR.Numerator > srcPAR.Denominator)
+ rc.right = MulDiv(rc.right, srcPAR.Numerator, srcPAR.Denominator);
+ else if (srcPAR.Numerator < srcPAR.Denominator)
+ rc.bottom = MulDiv(rc.bottom, srcPAR.Denominator, srcPAR.Numerator);
+
+
+ // Transform to destination aspect ratio.
+ if (destPAR.Numerator > destPAR.Denominator)
+ rc.bottom = MulDiv(rc.bottom, destPAR.Numerator, destPAR.Denominator);
+ else if (destPAR.Numerator < destPAR.Denominator)
+ rc.right = MulDiv(rc.right, destPAR.Denominator, destPAR.Numerator);
+
+ }
+
+ return rc;
+}
+
+static HRESULT GetVideoDisplayArea(IMFMediaType* type, MFVideoArea* area)
+{
+ if (!type || !area)
+ return E_POINTER;
+
+ HRESULT hr = S_OK;
+ UINT32 width = 0, height = 0;
+
+ BOOL bPanScan = MFGetAttributeUINT32(type, MF_MT_PAN_SCAN_ENABLED, FALSE);
+
+ if (bPanScan)
+ hr = type->GetBlob(MF_MT_PAN_SCAN_APERTURE, (UINT8*)area, sizeof(MFVideoArea), nullptr);
+
+ if (!bPanScan || hr == MF_E_ATTRIBUTENOTFOUND) {
+ hr = type->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE, (UINT8*)area, sizeof(MFVideoArea), nullptr);
+
+ if (hr == MF_E_ATTRIBUTENOTFOUND)
+ hr = type->GetBlob(MF_MT_GEOMETRIC_APERTURE, (UINT8*)area, sizeof(MFVideoArea), nullptr);
+
+ if (hr == MF_E_ATTRIBUTENOTFOUND) {
+ hr = MFGetAttributeSize(type, MF_MT_FRAME_SIZE, &width, &height);
+ if (SUCCEEDED(hr))
+ *area = MakeArea(0.0, 0.0, width, height);
+ }
+ }
+
+ return hr;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::calculateOutputRectangle(IMFMediaType* proposedType, RECT& outputRect)
+{
+ COMPtr<IMFMediaType> proposedVideoType = proposedType;
+
+ UINT32 srcWidth = 0, srcHeight = 0;
+ HRESULT hr = MFGetAttributeSize(proposedVideoType.get(), MF_MT_FRAME_SIZE, &srcWidth, &srcHeight);
+ if (FAILED(hr))
+ return hr;
+
+ MFVideoArea displayArea;
+ ZeroMemory(&displayArea, sizeof(displayArea));
+
+ hr = GetVideoDisplayArea(proposedVideoType.get(), &displayArea);
+ if (FAILED(hr))
+ return hr;
+
+ LONG offsetX = (LONG)MFOffsetToFloat(displayArea.OffsetX);
+ LONG offsetY = (LONG)MFOffsetToFloat(displayArea.OffsetY);
+
+ // Check if the display area is valid.
+ // If it is valid, we use it. If not, we use the frame dimensions.
+
+ RECT rcOutput;
+
+ if (displayArea.Area.cx != 0
+ && displayArea.Area.cy != 0
+ && offsetX + displayArea.Area.cx <= srcWidth
+ && offsetY + displayArea.Area.cy <= srcHeight) {
+ rcOutput.left = offsetX;
+ rcOutput.right = offsetX + displayArea.Area.cx;
+ rcOutput.top = offsetY;
+ rcOutput.bottom = offsetY + displayArea.Area.cy;
+ } else {
+ rcOutput.left = 0;
+ rcOutput.top = 0;
+ rcOutput.right = srcWidth;
+ rcOutput.bottom = srcHeight;
+ }
+
+ // Correct aspect ratio.
+
+ MFRatio inputPAR = { 1, 1 };
+ MFRatio outputPAR = { 1, 1 }; // We assume the monitor's pixels are square.
+ MFGetAttributeRatio(proposedVideoType.get(), MF_MT_PIXEL_ASPECT_RATIO, (UINT32*)&inputPAR.Numerator, (UINT32*)&inputPAR.Denominator);
+ outputRect = correctAspectRatio(rcOutput, inputPAR, outputPAR);
+
+ return S_OK;
+}
+
+void MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::processOutputLoop()
+{
+ // Get video frames from the mixer and schedule them for presentation.
+ HRESULT hr = S_OK;
+
+ while (hr == S_OK) {
+ if (!m_sampleNotify) {
+ // Currently no more input samples.
+ hr = MF_E_TRANSFORM_NEED_MORE_INPUT;
+ break;
+ }
+
+ // We break from the loop if we fail to process a sample.
+ hr = processOutput();
+ }
+
+ if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
+ checkEndOfStream();
+}
+
+static HRESULT setDesiredSampleTime(IMFSample* sample, const LONGLONG& sampleTime, const LONGLONG& duration)
+{
+ // To tell the mixer to give us an earlier frame for repainting, we can set the desired sample time.
+ // We have to clear the desired sample time before reusing the sample.
+
+ if (!sample)
+ return E_POINTER;
+
+ COMPtr<IMFDesiredSample> desired;
+
+ HRESULT hr = sample->QueryInterface(__uuidof(IMFDesiredSample), (void**)&desired);
+
+ if (SUCCEEDED(hr))
+ desired->SetDesiredSampleTimeAndDuration(sampleTime, duration);
+
+ return hr;
+}
+
+static HRESULT clearDesiredSampleTime(IMFSample* sample)
+{
+ if (!sample)
+ return E_POINTER;
+
+ // We need to retrieve some attributes we have set on the sample before we call
+ // IMFDesiredSample::Clear(), and set them once more, since they are cleared by
+ // the Clear() call.
+
+ UINT32 counter = MFGetAttributeUINT32(sample, MFSamplePresenterSampleCounter, (UINT32)-1);
+
+ COMPtr<IMFDesiredSample> desired;
+ HRESULT hr = sample->QueryInterface(__uuidof(IMFDesiredSample), (void**)&desired);
+ if (SUCCEEDED(hr)) {
+ desired->Clear();
+
+ hr = sample->SetUINT32(MFSamplePresenterSampleCounter, counter);
+ if (FAILED(hr))
+ return hr;
+ }
+
+ return hr;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::processOutput()
+{
+ // This method will try to get a new sample from the mixer.
+ // It is called when the mixer has a new sample, or when repainting the last frame.
+
+ ASSERT(m_sampleNotify || m_repaint);
+
+ LONGLONG mixerStartTime = 0, mixerEndTime = 0;
+ MFTIME systemTime = 0;
+ bool repaint = m_repaint;
+
+ // If the clock has not started, we only present the first sample.
+
+ if ((m_renderState != RenderStateStarted) && !m_repaint && m_prerolled)
+ return S_FALSE;
+
+ if (!m_mixer)
+ return MF_E_INVALIDREQUEST;
+
+ // Get a free sample from the pool.
+ COMPtr<IMFSample> sample;
+ HRESULT hr = m_samplePool.getSample(sample);
+ if (hr == MF_E_SAMPLEALLOCATOR_EMPTY)
+ return S_FALSE; // We will try again later when there are free samples
+
+ if (FAILED(hr))
+ return hr;
+
+ ASSERT(sample);
+
+ ASSERT(MFGetAttributeUINT32(sample.get(), MFSamplePresenterSampleCounter, (UINT32)-1) == m_tokenCounter);
+
+ if (m_repaint) {
+ // Get the most recent sample from the mixer.
+ setDesiredSampleTime(sample.get(), m_scheduler.lastSampleTime(), m_scheduler.frameDuration());
+ m_repaint = false;
+ } else {
+ // Clear the desired sample time to get the next sample in the stream.
+ clearDesiredSampleTime(sample.get());
+
+ if (m_clock) {
+ // Get the starting time of the ProcessOutput call.
+ m_clock->GetCorrelatedTime(0, &mixerStartTime, &systemTime);
+ }
+ }
+
+ // Get a sample from the mixer.
+ MFT_OUTPUT_DATA_BUFFER dataBuffer;
+ ZeroMemory(&dataBuffer, sizeof(dataBuffer));
+
+ dataBuffer.dwStreamID = 0;
+ dataBuffer.pSample = sample.get();
+ dataBuffer.dwStatus = 0;
+
+ DWORD status = 0;
+ hr = m_mixer->ProcessOutput(0, 1, &dataBuffer, &status);
+
+ // Release events. There are usually no events returned,
+ // but in case there are, we should release them.
+ if (dataBuffer.pEvents)
+ dataBuffer.pEvents->Release();
+
+ if (FAILED(hr)) {
+ HRESULT hr2 = m_samplePool.returnSample(sample.get());
+ if (FAILED(hr2))
+ return hr2;
+
+ if (hr == MF_E_TRANSFORM_TYPE_NOT_SET) {
+ // The media type has not been set, renegotiate.
+ hr = renegotiateMediaType();
+ } else if (hr == MF_E_TRANSFORM_STREAM_CHANGE) {
+ // The media type changed, reset it.
+ setMediaType(nullptr);
+ } else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
+ // The mixer needs more input.
+ m_sampleNotify = false;
+ }
+ } else {
+ // We have got a sample from the mixer.
+
+ if (m_clock && !repaint) {
+ // Notify the EVR about latency.
+ m_clock->GetCorrelatedTime(0, &mixerEndTime, &systemTime);
+
+ LONGLONG latencyTime = mixerEndTime - mixerStartTime;
+ notifyEvent(EC_PROCESSING_LATENCY, (LONG_PTR)&latencyTime, 0);
+ }
+
+ // Make sure we are notified when the sample is released
+ hr = trackSample(sample.get());
+ if (FAILED(hr))
+ return hr;
+
+ // Deliver the sample for scheduling
+ hr = deliverSample(sample.get(), repaint);
+ if (FAILED(hr))
+ return hr;
+
+ // At least one sample has been presented now.
+ m_prerolled = true;
+ }
+
+ return hr;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::deliverSample(IMFSample* sample, bool repaint)
+{
+ if (!sample)
+ return E_POINTER;
+
+ Direct3DPresenter::DeviceState state = Direct3DPresenter::DeviceOK;
+
+ // Determine if the sample should be presented immediately.
+ bool presentNow = ((m_renderState != RenderStateStarted) || isScrubbing() || repaint);
+
+ HRESULT hr = m_presenterEngine->checkDeviceState(state);
+
+ if (SUCCEEDED(hr))
+ hr = m_scheduler.scheduleSample(sample, presentNow);
+
+ if (FAILED(hr)) {
+ // Streaming has failed, notify the EVR.
+ notifyEvent(EC_ERRORABORT, hr, 0);
+ } else if (state == Direct3DPresenter::DeviceReset)
+ notifyEvent(EC_DISPLAY_CHANGED, S_OK, 0);
+
+ return hr;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::trackSample(IMFSample* sample)
+{
+ if (!sample)
+ return E_POINTER;
+
+ COMPtr<IMFTrackedSample> tracked;
+
+ HRESULT hr = sample->QueryInterface(__uuidof(IMFTrackedSample), (void**)&tracked);
+ if (FAILED(hr))
+ return hr;
+
+ if (!tracked)
+ return E_POINTER;
+
+ // Set callback object on which the onSampleFree method is invoked when the sample is no longer used.
+ return tracked->SetAllocator(this, nullptr);
+}
+
+void MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::releaseResources()
+{
+ // The token counter is incremented to indicate that existing samples are
+ // invalid and can be disposed in the method onSampleFree.
+ m_tokenCounter++;
+
+ flush();
+
+ m_samplePool.clear();
+
+ if (m_presenterEngine)
+ m_presenterEngine->releaseResources();
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::onSampleFree(IMFAsyncResult* result)
+{
+ if (!result)
+ return E_POINTER;
+
+ COMPtr<IUnknown> object;
+ HRESULT hr = result->GetObject(&object);
+ if (FAILED(hr)) {
+ notifyEvent(EC_ERRORABORT, hr, 0);
+ return hr;
+ }
+
+ COMPtr<IMFSample> sample;
+ hr = object->QueryInterface(__uuidof(IMFSample), (void**)&sample);
+ if (FAILED(hr)) {
+ notifyEvent(EC_ERRORABORT, hr, 0);
+ return hr;
+ }
+
+ m_lock.lock();
+
+ if (MFGetAttributeUINT32(sample.get(), MFSamplePresenterSampleCounter, (UINT32)-1) == m_tokenCounter) {
+ hr = m_samplePool.returnSample(sample.get());
+
+ // Do more processing, since a free sample is available
+ if (SUCCEEDED(hr))
+ processOutputLoop();
+ }
+
+ m_lock.unlock();
+
+ if (FAILED(hr))
+ notifyEvent(EC_ERRORABORT, hr, 0);
+
+ return hr;
+}
+
+void MediaPlayerPrivateMediaFoundation::CustomVideoPresenter::notifyEvent(long EventCode, LONG_PTR Param1, LONG_PTR Param2)
+{
+ if (m_mediaEventSink)
+ m_mediaEventSink->Notify(EventCode, Param1, Param2);
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::VideoSamplePool::getSample(COMPtr<IMFSample>& sample)
+{
+ LockHolder locker(m_lock);
+
+ if (!m_initialized)
+ return MF_E_NOT_INITIALIZED;
+
+ if (m_videoSampleQueue.isEmpty())
+ return MF_E_SAMPLEALLOCATOR_EMPTY;
+
+ sample = m_videoSampleQueue.takeFirst();
+
+ m_pending++;
+
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::VideoSamplePool::returnSample(IMFSample* sample)
+{
+ if (!sample)
+ return E_POINTER;
+
+ LockHolder locker(m_lock);
+
+ if (!m_initialized)
+ return MF_E_NOT_INITIALIZED;
+
+ m_videoSampleQueue.append(sample);
+ m_pending--;
+ return S_OK;
+}
+
+bool MediaPlayerPrivateMediaFoundation::VideoSamplePool::areSamplesPending()
+{
+ LockHolder locker(m_lock);
+
+ if (!m_initialized)
+ return FALSE;
+
+ return (m_pending > 0);
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::VideoSamplePool::initialize(VideoSampleList& samples)
+{
+ LockHolder locker(m_lock);
+
+ if (m_initialized)
+ return MF_E_INVALIDREQUEST;
+
+ // Copy the samples
+ for (auto sample : samples)
+ m_videoSampleQueue.append(sample);
+
+ m_initialized = true;
+ samples.clear();
+
+ return S_OK;
+}
+
+void MediaPlayerPrivateMediaFoundation::VideoSamplePool::clear()
+{
+ LockHolder locker(m_lock);
+
+ m_videoSampleQueue.clear();
+ m_initialized = false;
+ m_pending = 0;
+}
+
+
+// Scheduler thread messages.
+
+enum ScheduleEvent {
+ EventTerminate = WM_USER,
+ EventSchedule,
+ EventFlush
+};
+
+void MediaPlayerPrivateMediaFoundation::VideoScheduler::setFrameRate(const MFRatio& fps)
+{
+ UINT64 avgTimePerFrame = 0;
+ MFFrameRateToAverageTimePerFramePtr()(fps.Numerator, fps.Denominator, &avgTimePerFrame);
+
+ m_frameDuration = (MFTIME)avgTimePerFrame;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::VideoScheduler::startScheduler(IMFClock* clock)
+{
+ if (m_schedulerThread.isValid())
+ return E_UNEXPECTED;
+
+ HRESULT hr = S_OK;
+
+ m_clock = clock;
+
+ // Use high timer resolution.
+ timeBeginPeriod(1);
+
+ // Create an event to signal that the scheduler thread has started.
+ m_threadReadyEvent = ::CreateEvent(nullptr, FALSE, FALSE, nullptr);
+ if (!m_threadReadyEvent.isValid())
+ return HRESULT_FROM_WIN32(GetLastError());
+
+ // Create an event to signal that the flush has completed.
+ m_flushEvent = ::CreateEvent(nullptr, FALSE, FALSE, nullptr);
+ if (!m_flushEvent.isValid())
+ return HRESULT_FROM_WIN32(GetLastError());
+
+ // Start scheduler thread.
+ DWORD threadID = 0;
+ m_schedulerThread = ::CreateThread(nullptr, 0, schedulerThreadProc, (LPVOID)this, 0, &threadID);
+ if (!m_schedulerThread.isValid())
+ return HRESULT_FROM_WIN32(GetLastError());
+
+ HANDLE hObjects[] = { m_threadReadyEvent.get(), m_schedulerThread.get() };
+
+ // Wait for the thread to start
+ DWORD result = ::WaitForMultipleObjects(2, hObjects, FALSE, INFINITE);
+ if (WAIT_OBJECT_0 != result) {
+ // The thread has terminated.
+ m_schedulerThread.clear();
+ return E_UNEXPECTED;
+ }
+
+ m_threadID = threadID;
+
+ return hr;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::VideoScheduler::stopScheduler()
+{
+ if (!m_schedulerThread.isValid())
+ return S_OK;
+
+ // Terminate the scheduler thread
+ stopThread();
+ ::PostThreadMessage(m_threadID, EventTerminate, 0, 0);
+
+ // Wait for the scheduler thread to finish.
+ ::WaitForSingleObject(m_schedulerThread.get(), INFINITE);
+
+ LockHolder locker(m_lock);
+
+ m_scheduledSamples.clear();
+ m_schedulerThread.clear();
+ m_flushEvent.clear();
+
+ // Clear previously set timer resolution.
+ timeEndPeriod(1);
+
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::VideoScheduler::flush()
+{
+ // This method will wait for the flush to finish on the worker thread.
+
+ if (m_schedulerThread.isValid()) {
+ ::PostThreadMessage(m_threadID, EventFlush, 0, 0);
+
+ HANDLE objects[] = { m_flushEvent.get(), m_schedulerThread.get() };
+
+ const int schedulerTimeout = 5000;
+
+ // Wait for the flush to finish or the thread to terminate.
+ ::WaitForMultipleObjects(2, objects, FALSE, schedulerTimeout);
+ }
+
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::VideoScheduler::scheduleSample(IMFSample* sample, bool presentNow)
+{
+ if (!sample)
+ return E_POINTER;
+
+ if (!m_presenter)
+ return MF_E_NOT_INITIALIZED;
+
+ if (!m_schedulerThread.isValid())
+ return MF_E_NOT_INITIALIZED;
+
+ DWORD exitCode = 0;
+ ::GetExitCodeThread(m_schedulerThread.get(), &exitCode);
+
+ if (exitCode != STILL_ACTIVE)
+ return E_FAIL;
+
+ if (presentNow || !m_clock)
+ m_presenter->presentSample(sample, 0);
+ else {
+ // Submit the sample for scheduling.
+ LockHolder locker(m_lock);
+ m_scheduledSamples.append(sample);
+
+ ::PostThreadMessage(m_threadID, EventSchedule, 0, 0);
+ }
+
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::VideoScheduler::processSamplesInQueue(LONG& nextSleep)
+{
+ HRESULT hr = S_OK;
+ LONG wait = 0;
+
+ // Process samples as long as there are samples in the queue, and they have not arrived too early.
+
+ while (!m_exitThread) {
+ COMPtr<IMFSample> sample;
+
+ if (true) {
+ LockHolder locker(m_lock);
+ if (m_scheduledSamples.isEmpty())
+ break;
+ sample = m_scheduledSamples.takeFirst();
+ }
+
+ // Process the sample.
+ // If the sample has arrived too early, wait will be > 0,
+ // and the scheduler should go to sleep.
+ hr = processSample(sample.get(), wait);
+
+ if (FAILED(hr))
+ break;
+
+ if (wait > 0)
+ break;
+ }
+
+ if (!wait) {
+ // The queue is empty. Sleep until the next message arrives.
+ wait = INFINITE;
+ }
+
+ nextSleep = wait;
+ return hr;
+}
+
+// MFTimeToMilliseconds: Convert 100-nanosecond time to milliseconds.
+static LONG MFTimeToMilliseconds(const LONGLONG& time)
+{
+ return (time / 10000);
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::VideoScheduler::processSample(IMFSample* sample, LONG& nextSleep)
+{
+ if (!sample)
+ return E_POINTER;
+
+ HRESULT hr = S_OK;
+
+ LONGLONG presentationTime = 0;
+ LONGLONG timeNow = 0;
+ MFTIME systemTime = 0;
+
+ bool presentNow = true;
+ LONG nextSleepTime = 0;
+
+ if (m_clock) {
+ // Get the time stamp of the sample.
+ // A sample can possibly have no time stamp.
+ hr = sample->GetSampleTime(&presentationTime);
+
+ // Get the clock time.
+ // If the sample does not have a time stamp, the clock time is not needed.
+ if (SUCCEEDED(hr))
+ hr = m_clock->GetCorrelatedTime(0, &timeNow, &systemTime);
+
+ // Determine the time until the sample should be presented.
+ // Samples arriving late, will have negative values.
+ LONGLONG timeDelta = presentationTime - timeNow;
+ if (m_playbackRate < 0) {
+ // Reverse delta for reverse playback.
+ timeDelta = -timeDelta;
+ }
+
+ LONGLONG frameDurationOneFourth = m_frameDuration / 4;
+
+ if (timeDelta < -frameDurationOneFourth) {
+ // The sample has arrived late.
+ presentNow = true;
+ } else if (timeDelta > (3 * frameDurationOneFourth)) {
+ // We can sleep, the sample has arrived too early.
+ nextSleepTime = MFTimeToMilliseconds(timeDelta - (3 * frameDurationOneFourth));
+
+ // Since sleeping is using the system clock, we need to convert the sleep time
+ // from presentation time to system time.
+ nextSleepTime = (LONG)(nextSleepTime / fabsf(m_playbackRate));
+
+ presentNow = false;
+ }
+ }
+
+ if (presentNow)
+ hr = m_presenter->presentSample(sample, presentationTime);
+ else {
+ // Return the sample to the queue, since it is not ready.
+ LockHolder locker(m_lock);
+ m_scheduledSamples.prepend(sample);
+ }
+
+ nextSleep = nextSleepTime;
+
+ return hr;
+}
+
+DWORD WINAPI MediaPlayerPrivateMediaFoundation::VideoScheduler::schedulerThreadProc(LPVOID lpParameter)
+{
+ VideoScheduler* scheduler = reinterpret_cast<VideoScheduler*>(lpParameter);
+ if (!scheduler)
+ return static_cast<DWORD>(-1);
+ return scheduler->schedulerThreadProcPrivate();
+}
+
+DWORD MediaPlayerPrivateMediaFoundation::VideoScheduler::schedulerThreadProcPrivate()
+{
+ HRESULT hr = S_OK;
+
+ // This will force a message queue to be created for the thread.
+ MSG msg;
+ PeekMessage(&msg, nullptr, WM_USER, WM_USER, PM_NOREMOVE);
+
+ // The thread is ready.
+ SetEvent(m_threadReadyEvent.get());
+
+ LONG wait = INFINITE;
+ m_exitThread = false;
+ while (!m_exitThread) {
+ // Wait for messages
+ DWORD result = MsgWaitForMultipleObjects(0, nullptr, FALSE, wait, QS_POSTMESSAGE);
+
+ if (result == WAIT_TIMEOUT) {
+ hr = processSamplesInQueue(wait);
+ if (FAILED(hr))
+ m_exitThread = true;
+ }
+
+ while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
+ bool processSamples = true;
+
+ switch (msg.message) {
+ case EventTerminate:
+ m_exitThread = true;
+ break;
+
+ case EventFlush:
+ {
+ LockHolder lock(m_lock);
+ m_scheduledSamples.clear();
+ }
+ wait = INFINITE;
+ SetEvent(m_flushEvent.get());
+ break;
+
+ case EventSchedule:
+ if (processSamples) {
+ hr = processSamplesInQueue(wait);
+ if (FAILED(hr))
+ m_exitThread = true;
+ processSamples = (wait != INFINITE);
+ }
+ break;
+ }
+ }
+ }
+ return (SUCCEEDED(hr) ? 0 : 1);
+}
+
+static HRESULT findAdapter(IDirect3D9* direct3D9, HMONITOR monitor, UINT& adapterID)
+{
+ HRESULT hr = E_FAIL;
+
+ UINT adapterCount = direct3D9->GetAdapterCount();
+ for (UINT i = 0; i < adapterCount; i++) {
+ HMONITOR monitorTmp = direct3D9->GetAdapterMonitor(i);
+
+ if (!monitorTmp)
+ break;
+
+ if (monitorTmp == monitor) {
+ adapterID = i;
+ hr = S_OK;
+ break;
+ }
+ }
+
+ return hr;
+}
+
+MediaPlayerPrivateMediaFoundation::Direct3DPresenter::Direct3DPresenter()
+{
+ SetRectEmpty(&m_destRect);
+
+ ZeroMemory(&m_displayMode, sizeof(m_displayMode));
+
+ HRESULT hr = initializeD3D();
+
+ if (FAILED(hr))
+ return;
+
+ createD3DDevice();
+}
+
+MediaPlayerPrivateMediaFoundation::Direct3DPresenter::~Direct3DPresenter()
+{
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::Direct3DPresenter::getService(REFGUID guidService, REFIID riid, void** ppv)
+{
+ ASSERT(ppv);
+
+ HRESULT hr = S_OK;
+
+ if (riid == __uuidof(IDirect3DDeviceManager9)) {
+ if (!m_deviceManager)
+ hr = MF_E_UNSUPPORTED_SERVICE;
+ else {
+ *ppv = m_deviceManager.get();
+ m_deviceManager->AddRef();
+ }
+ } else
+ hr = MF_E_UNSUPPORTED_SERVICE;
+
+ return hr;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::Direct3DPresenter::checkFormat(D3DFORMAT format)
+{
+ HRESULT hr = S_OK;
+
+ UINT adapter = D3DADAPTER_DEFAULT;
+ D3DDEVTYPE type = D3DDEVTYPE_HAL;
+
+ if (m_device) {
+ D3DDEVICE_CREATION_PARAMETERS params;
+ hr = m_device->GetCreationParameters(&params);
+ if (FAILED(hr))
+ return hr;
+
+ adapter = params.AdapterOrdinal;
+ type = params.DeviceType;
+ }
+
+ D3DDISPLAYMODE mode;
+ hr = m_direct3D9->GetAdapterDisplayMode(adapter, &mode);
+ if (FAILED(hr))
+ return hr;
+
+ return m_direct3D9->CheckDeviceType(adapter, type, mode.Format, format, TRUE);
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::Direct3DPresenter::setVideoWindow(HWND hwnd)
+{
+ ASSERT(IsWindow(hwnd));
+ ASSERT(hwnd != m_hwnd);
+
+ {
+ LockHolder locker(m_lock);
+ m_hwnd = hwnd;
+ updateDestRect();
+ }
+
+ return createD3DDevice();
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::Direct3DPresenter::setDestinationRect(const RECT& rcDest)
+{
+ if (EqualRect(&rcDest, &m_destRect))
+ return S_OK;
+
+ LockHolder locker(m_lock);
+
+ m_destRect = rcDest;
+ updateDestRect();
+
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::Direct3DPresenter::createVideoSamples(IMFMediaType* format, VideoSampleList& videoSampleQueue)
+{
+ // Create video samples matching the supplied format.
+ // A swap chain with a single back buffer will be created for each video sample.
+ // The mixer will render to the back buffer through a surface kept by the sample.
+ // The surface can be rendered to a window by presenting the swap chain.
+ // In our case the surface is transferred to system memory, and rendered to a graphics context.
+
+ if (!m_hwnd)
+ return MF_E_INVALIDREQUEST;
+
+ if (!format)
+ return MF_E_UNEXPECTED;
+
+
+ LockHolder locker(m_lock);
+
+ releaseResources();
+
+ D3DPRESENT_PARAMETERS presentParameters;
+ HRESULT hr = getSwapChainPresentParameters(format, &presentParameters);
+ if (FAILED(hr)) {
+ releaseResources();
+ return hr;
+ }
+
+ updateDestRect();
+
+ static const int presenterBufferCount = 3;
+
+ for (int i = 0; i < presenterBufferCount; i++) {
+ COMPtr<IDirect3DSwapChain9> swapChain;
+ hr = m_device->CreateAdditionalSwapChain(&presentParameters, &swapChain);
+ if (FAILED(hr)) {
+ releaseResources();
+ return hr;
+ }
+
+ COMPtr<IMFSample> videoSample;
+ hr = createD3DSample(swapChain.get(), videoSample);
+ if (FAILED(hr)) {
+ releaseResources();
+ return hr;
+ }
+
+ videoSampleQueue.append(videoSample);
+ }
+
+ return hr;
+}
+
+void MediaPlayerPrivateMediaFoundation::Direct3DPresenter::releaseResources()
+{
+ m_surfaceRepaint = nullptr;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::Direct3DPresenter::checkDeviceState(DeviceState& state)
+{
+ LockHolder locker(m_lock);
+
+ HRESULT hr = m_device->CheckDeviceState(m_hwnd);
+
+ state = DeviceOK;
+
+ // Not all failure codes are critical.
+
+ switch (hr) {
+ case S_OK:
+ case S_PRESENT_OCCLUDED:
+ case S_PRESENT_MODE_CHANGED:
+ hr = S_OK;
+ break;
+
+ case D3DERR_DEVICELOST:
+ case D3DERR_DEVICEHUNG:
+ hr = createD3DDevice();
+ if (FAILED(hr))
+ return hr;
+ state = DeviceReset;
+ hr = S_OK;
+ break;
+
+ case D3DERR_DEVICEREMOVED:
+ state = DeviceRemoved;
+ break;
+
+ case E_INVALIDARG:
+ // This might happen if the window has been destroyed, or is not valid.
+ // A new device will be created if a new window is set.
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::Direct3DPresenter::presentSample(IMFSample* sample, LONGLONG targetPresentationTime)
+{
+ HRESULT hr = S_OK;
+
+ LockHolder locker(m_lock);
+
+ COMPtr<IDirect3DSurface9> surface;
+
+ if (sample) {
+ COMPtr<IMFMediaBuffer> buffer;
+ hr = sample->GetBufferByIndex(0, &buffer);
+ hr = MFGetServicePtr()(buffer.get(), MR_BUFFER_SERVICE, __uuidof(IDirect3DSurface9), (void**)&surface);
+ } else if (m_surfaceRepaint) {
+ // Use the last surface.
+ surface = m_surfaceRepaint;
+ }
+
+ if (surface) {
+ UINT width = m_destRect.right - m_destRect.left;
+ UINT height = m_destRect.bottom - m_destRect.top;
+
+ if (width > 0 && height > 0) {
+ if (!m_memSurface || m_width != width || m_height != height) {
+ D3DFORMAT format = D3DFMT_A8R8G8B8;
+ D3DSURFACE_DESC desc;
+ if (SUCCEEDED(surface->GetDesc(&desc)))
+ format = desc.Format;
+ hr = m_device->CreateOffscreenPlainSurface(width, height, format, D3DPOOL_SYSTEMMEM, &m_memSurface, nullptr);
+ m_width = width;
+ m_height = height;
+ }
+ // Copy data from video memory to system memory
+ hr = m_device->GetRenderTargetData(surface.get(), m_memSurface.get());
+ if (FAILED(hr)) {
+ m_memSurface = nullptr;
+ hr = S_OK;
+ }
+ }
+
+ // Since we want to draw to the GraphicsContext provided in the paint method,
+ // and not draw directly to the window, we skip presenting the swap chain:
+
+ // COMPtr<IDirect3DSwapChain9> swapChain;
+ // hr = surface->GetContainer(__uuidof(IDirect3DSwapChain9), (LPVOID*)&swapChain));
+ // hr = presentSwapChain(swapChain, surface));
+
+ // Keep the last surface for repaints.
+ m_surfaceRepaint = surface;
+ }
+
+ if (FAILED(hr)) {
+ if (hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICENOTRESET || hr == D3DERR_DEVICEHUNG) {
+ // Ignore this error. We have to reset or recreate the device.
+ // The presenter will handle this when checking the device state the next time.
+ hr = S_OK;
+ }
+ }
+ return hr;
+}
+
+void MediaPlayerPrivateMediaFoundation::Direct3DPresenter::paintCurrentFrame(WebCore::GraphicsContext& context, const WebCore::FloatRect& destRect)
+{
+ UINT width = m_destRect.right - m_destRect.left;
+ UINT height = m_destRect.bottom - m_destRect.top;
+
+ if (!width || !height)
+ return;
+
+ LockHolder locker(m_lock);
+
+ if (!m_memSurface)
+ return;
+
+ D3DLOCKED_RECT lockedRect;
+ if (SUCCEEDED(m_memSurface->LockRect(&lockedRect, nullptr, D3DLOCK_READONLY))) {
+ void* data = lockedRect.pBits;
+ int pitch = lockedRect.Pitch;
+#if USE(CAIRO)
+ D3DFORMAT format = D3DFMT_UNKNOWN;
+ D3DSURFACE_DESC desc;
+ if (SUCCEEDED(m_memSurface->GetDesc(&desc)))
+ format = desc.Format;
+
+ cairo_format_t cairoFormat = CAIRO_FORMAT_INVALID;
+
+ switch (format) {
+ case D3DFMT_A8R8G8B8:
+ cairoFormat = CAIRO_FORMAT_ARGB32;
+ break;
+ case D3DFMT_X8R8G8B8:
+ cairoFormat = CAIRO_FORMAT_RGB24;
+ break;
+ }
+
+ ASSERT(cairoFormat != CAIRO_FORMAT_INVALID);
+
+ cairo_surface_t* image = nullptr;
+ if (cairoFormat != CAIRO_FORMAT_INVALID)
+ image = cairo_image_surface_create_for_data(static_cast<unsigned char*>(data), cairoFormat, width, height, pitch);
+
+ FloatRect srcRect(0, 0, width, height);
+ if (image) {
+ WebCore::PlatformContextCairo* ctxt = context.platformContext();
+ ctxt->drawSurfaceToContext(image, destRect, srcRect, context);
+ cairo_surface_destroy(image);
+ }
+#elif PLATFORM(QT)
+ D3DFORMAT format = D3DFMT_UNKNOWN;
+ D3DSURFACE_DESC desc;
+ if (SUCCEEDED(m_memSurface->GetDesc(&desc)))
+ format = desc.Format;
+
+ QImage::Format imageFormat = QImage::Format_Invalid;
+
+ switch (format) {
+ case D3DFMT_A8R8G8B8:
+ imageFormat = QImage::Format_ARGB32_Premultiplied;
+ break;
+ case D3DFMT_X8R8G8B8:
+ imageFormat = QImage::Format_RGB32;
+ break;
+ }
+
+ ASSERT(imageFormat != QImage::Format_Invalid);
+
+ QImage image(static_cast<unsigned char*>(data), width, height, pitch, imageFormat);
+
+ FloatRect srcRect(0, 0, width, height);
+ QPainter* p = context.platformContext();
+ p->drawImage(destRect, image, srcRect);
+#else
+#error "Platform needs to implement drawing of Direct3D surface to graphics context!"
+#endif
+ m_memSurface->UnlockRect();
+ }
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::Direct3DPresenter::initializeD3D()
+{
+ ASSERT(!m_direct3D9);
+ ASSERT(!m_deviceManager);
+
+ HRESULT hr = Direct3DCreate9ExPtr()(D3D_SDK_VERSION, &m_direct3D9);
+ if (FAILED(hr))
+ return hr;
+
+ return DXVA2CreateDirect3DDeviceManager9Ptr()(&m_deviceResetToken, &m_deviceManager);
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::Direct3DPresenter::createD3DDevice()
+{
+ HRESULT hr = S_OK;
+ UINT adapterID = D3DADAPTER_DEFAULT;
+
+ LockHolder locker(m_lock);
+
+ if (!m_direct3D9 || !m_deviceManager)
+ return MF_E_NOT_INITIALIZED;
+
+ HWND hwnd = GetDesktopWindow();
+
+ // We create additional swap chains to present the video frames,
+ // and do not use the implicit swap chain of the device.
+ // The size of the back buffer is 1 x 1.
+
+ D3DPRESENT_PARAMETERS pp;
+ ZeroMemory(&pp, sizeof(pp));
+
+ pp.BackBufferWidth = 1;
+ pp.BackBufferHeight = 1;
+ pp.Windowed = TRUE;
+ pp.SwapEffect = D3DSWAPEFFECT_COPY;
+ pp.BackBufferFormat = D3DFMT_UNKNOWN;
+ pp.hDeviceWindow = hwnd;
+ pp.Flags = D3DPRESENTFLAG_VIDEO;
+ pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
+
+ if (m_hwnd) {
+ HMONITOR monitor = MonitorFromWindow(m_hwnd, MONITOR_DEFAULTTONEAREST);
+
+ hr = findAdapter(m_direct3D9.get(), monitor, adapterID);
+ if (FAILED(hr))
+ return hr;
+ }
+
+ D3DCAPS9 ddCaps;
+ ZeroMemory(&ddCaps, sizeof(ddCaps));
+
+ hr = m_direct3D9->GetDeviceCaps(adapterID, D3DDEVTYPE_HAL, &ddCaps);
+ if (FAILED(hr))
+ return hr;
+
+ DWORD flags = D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE;
+
+ if (ddCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
+ flags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
+ else
+ flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
+
+ COMPtr<IDirect3DDevice9Ex> device;
+ hr = m_direct3D9->CreateDeviceEx(adapterID, D3DDEVTYPE_HAL, pp.hDeviceWindow, flags, &pp, nullptr, &device);
+ if (FAILED(hr))
+ return hr;
+
+ hr = m_direct3D9->GetAdapterDisplayMode(adapterID, &m_displayMode);
+ if (FAILED(hr))
+ return hr;
+
+ hr = m_deviceManager->ResetDevice(device.get(), m_deviceResetToken);
+ if (FAILED(hr))
+ return hr;
+
+ m_device = device;
+
+ return hr;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::Direct3DPresenter::createD3DSample(IDirect3DSwapChain9* swapChain, COMPtr<IMFSample>& videoSample)
+{
+ COMPtr<IDirect3DSurface9> surface;
+ HRESULT hr = swapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &surface);
+ if (FAILED(hr))
+ return hr;
+
+ D3DCOLOR colorBlack = D3DCOLOR_ARGB(0xFF, 0x00, 0x00, 0x00);
+ hr = m_device->ColorFill(surface.get(), nullptr, colorBlack);
+ if (FAILED(hr))
+ return hr;
+
+ return MFCreateVideoSampleFromSurfacePtr()(surface.get(), &videoSample);
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::Direct3DPresenter::presentSwapChain(IDirect3DSwapChain9* swapChain, IDirect3DSurface9* surface)
+{
+ if (!m_hwnd)
+ return MF_E_INVALIDREQUEST;
+
+ return swapChain->Present(nullptr, &m_destRect, m_hwnd, nullptr, 0);
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::Direct3DPresenter::getSwapChainPresentParameters(IMFMediaType* type, D3DPRESENT_PARAMETERS* presentParams)
+{
+ if (!m_hwnd)
+ return MF_E_INVALIDREQUEST;
+
+ COMPtr<IMFMediaType> videoType = type;
+
+ UINT32 width = 0, height = 0;
+ HRESULT hr = MFGetAttributeSize(videoType.get(), MF_MT_FRAME_SIZE, &width, &height);
+ if (FAILED(hr))
+ return hr;
+
+ GUID guidSubType = GUID_NULL;
+ hr = videoType->GetGUID(MF_MT_SUBTYPE, &guidSubType);
+ if (FAILED(hr))
+ return hr;
+
+ DWORD d3dFormat = guidSubType.Data1;
+
+ ZeroMemory(presentParams, sizeof(D3DPRESENT_PARAMETERS));
+ presentParams->BackBufferWidth = width;
+ presentParams->BackBufferHeight = height;
+ presentParams->Windowed = TRUE;
+ presentParams->SwapEffect = D3DSWAPEFFECT_COPY;
+ presentParams->BackBufferFormat = (D3DFORMAT)d3dFormat;
+ presentParams->hDeviceWindow = m_hwnd;
+ presentParams->Flags = D3DPRESENTFLAG_VIDEO;
+ presentParams->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
+
+ D3DDEVICE_CREATION_PARAMETERS params;
+ hr = m_device->GetCreationParameters(&params);
+ if (FAILED(hr))
+ return hr;
+
+ if (params.DeviceType != D3DDEVTYPE_HAL)
+ presentParams->Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
+
+ return S_OK;
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::Direct3DPresenter::updateDestRect()
+{
+ if (!m_hwnd)
+ return S_FALSE;
+
+ RECT rcView;
+ if (!GetClientRect(m_hwnd, &rcView))
+ return E_FAIL;
+
+ // Clip to the client area of the window.
+ if (m_destRect.right > rcView.right)
+ m_destRect.right = rcView.right;
+
+ if (m_destRect.bottom > rcView.bottom)
+ m_destRect.bottom = rcView.bottom;
+
+ return S_OK;
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/platform/network/ParsedContentRange.cpp b/Source/WebCore/platform/network/ParsedContentRange.cpp
index ccb8443d3..4e46ac49e 100644
--- a/Source/WebCore/platform/network/ParsedContentRange.cpp
+++ b/Source/WebCore/platform/network/ParsedContentRange.cpp
@@ -121,10 +121,6 @@ ParsedContentRange::ParsedContentRange(int64_t firstBytePosition, int64_t lastBy
m_isValid = areContentRangeValuesValid(m_firstBytePosition, m_lastBytePosition, m_instanceLength);
}
-#if OS(WINDOWS) && !defined(PRId64)
-#define PRId64 "lld"
-#endif
-
String ParsedContentRange::headerValue() const
{
if (!m_isValid)
diff --git a/Source/WebCore/platform/network/qt/QtMIMETypeSniffer.cpp b/Source/WebCore/platform/network/qt/QtMIMETypeSniffer.cpp
index bd119a8e1..37eb45588 100644
--- a/Source/WebCore/platform/network/qt/QtMIMETypeSniffer.cpp
+++ b/Source/WebCore/platform/network/qt/QtMIMETypeSniffer.cpp
@@ -68,3 +68,5 @@ void QtMIMETypeSniffer::trySniffing()
m_isFinished = true;
emit finished();
}
+
+#include "moc_QtMIMETypeSniffer.cpp"
diff --git a/Source/WebCore/platform/qt/ScrollbarThemeQStyle.cpp b/Source/WebCore/platform/qt/ScrollbarThemeQStyle.cpp
index 7b23db214..8587dccf3 100644
--- a/Source/WebCore/platform/qt/ScrollbarThemeQStyle.cpp
+++ b/Source/WebCore/platform/qt/ScrollbarThemeQStyle.cpp
@@ -168,10 +168,30 @@ ScrollbarPart ScrollbarThemeQStyle::hitTest(Scrollbar& scrollbar, const IntPoint
return scrollbarPart(sc);
}
-bool ScrollbarThemeQStyle::shouldCenterOnThumb(Scrollbar&, const PlatformMouseEvent& evt)
+static bool shouldCenterOnThumb(QStyleFacade& qStyle, const PlatformMouseEvent& evt)
{
// Middle click centers slider thumb (if supported).
- return m_qStyle->scrollBarMiddleClickAbsolutePositionStyleHint() && evt.button() == MiddleButton;
+ return qStyle.scrollBarMiddleClickAbsolutePositionStyleHint() && evt.button() == MiddleButton;
+}
+
+ScrollbarButtonPressAction ScrollbarThemeQStyle::handleMousePressEvent(Scrollbar&, const PlatformMouseEvent& event, ScrollbarPart pressedPart)
+{
+ if (event.button() == RightButton)
+ return ScrollbarButtonPressAction::None;
+
+ switch (pressedPart) {
+ case BackTrackPart:
+ case ForwardTrackPart:
+ if (shouldCenterOnThumb(*m_qStyle, event))
+ return ScrollbarButtonPressAction::CenterOnThumb;
+ break;
+ case ThumbPart:
+ return ScrollbarButtonPressAction::StartDrag;
+ default:
+ break;
+ }
+
+ return ScrollbarButtonPressAction::Scroll;
}
void ScrollbarThemeQStyle::invalidatePart(Scrollbar& scrollbar, ScrollbarPart)
diff --git a/Source/WebCore/platform/qt/ScrollbarThemeQStyle.h b/Source/WebCore/platform/qt/ScrollbarThemeQStyle.h
index 3f50ff58b..b4fc21fad 100644
--- a/Source/WebCore/platform/qt/ScrollbarThemeQStyle.h
+++ b/Source/WebCore/platform/qt/ScrollbarThemeQStyle.h
@@ -44,7 +44,7 @@ public:
ScrollbarPart hitTest(Scrollbar&, const IntPoint&) final;
- virtual bool shouldCenterOnThumb(Scrollbar&, const PlatformMouseEvent&);
+ ScrollbarButtonPressAction handleMousePressEvent(Scrollbar&, const PlatformMouseEvent&, ScrollbarPart) override;
void invalidatePart(Scrollbar&, ScrollbarPart) final;
diff --git a/Source/WebCore/platform/sql/SQLiteFileSystem.cpp b/Source/WebCore/platform/sql/SQLiteFileSystem.cpp
index 98de996b4..484397600 100644
--- a/Source/WebCore/platform/sql/SQLiteFileSystem.cpp
+++ b/Source/WebCore/platform/sql/SQLiteFileSystem.cpp
@@ -28,14 +28,12 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#define __STDC_FORMAT_MACROS
#include "config.h"
#include "SQLiteFileSystem.h"
#include "FileSystem.h"
#include "SQLiteDatabase.h"
#include "SQLiteStatement.h"
-#include <inttypes.h>
#include <sqlite3.h>
#if PLATFORM(IOS)
diff --git a/Source/WebCore/rendering/break_lines.cpp b/Source/WebCore/rendering/break_lines.cpp
index 07576bbc8..b9ece3221 100644
--- a/Source/WebCore/rendering/break_lines.cpp
+++ b/Source/WebCore/rendering/break_lines.cpp
@@ -51,7 +51,7 @@ namespace WebCore {
// - after '-' and '?' (backward-compatible, and compatible with Internet Explorer).
// Please refer to <https://bugs.webkit.org/show_bug.cgi?id=37698> for line breaking matrixes of different browsers
// and the ICU standard.
-WEBCORE_EXPORT const unsigned char asciiLineBreakTable[][asciiLineBreakTableColumnCount] = {
+WEBCORE_EXPORT extern const unsigned char asciiLineBreakTable[][asciiLineBreakTableColumnCount] = {
// ! " # $ % & ' ( ) * + , - . / 0 1-8 9 : ; < = > ? @ A-X Y Z [ \ ] ^ _ ` a-x y z { | } ~ DEL
{ B(0, 0, 0, 0, 0, 0, 0, 1), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 1, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0) }, // !
{ B(0, 0, 0, 0, 0, 0, 0, 1), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 1, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0) }, // "
diff --git a/Source/WebKit/CMakeLists.txt b/Source/WebKit/CMakeLists.txt
index 72f36b19b..b48cc319e 100644
--- a/Source/WebKit/CMakeLists.txt
+++ b/Source/WebKit/CMakeLists.txt
@@ -1,15 +1,6 @@
cmake_minimum_required(VERSION 2.8.12)
include(WebKitCommon)
-# TODO: Unify usage of prefix headers and PCH with WebCore and WebKit2
-macro(ADD_WEBKIT_PREFIX_HEADER _target _header)
- get_target_property(OLD_COMPILE_FLAGS ${_target} COMPILE_FLAGS)
- if (${OLD_COMPILE_FLAGS} STREQUAL "OLD_COMPILE_FLAGS-NOTFOUND")
- set(OLD_COMPILE_FLAGS "")
- endif ()
- set_target_properties(${_target} PROPERTIES COMPILE_FLAGS "${OLD_COMPILE_FLAGS} -include ${_header}")
-endmacro()
-
set(WebKit_SOURCES
Storage/StorageAreaImpl.cpp
Storage/StorageAreaSync.cpp
@@ -76,5 +67,5 @@ if (TARGET WebKitGUID)
endif ()
if (NOT MSVC AND ${PORT} STREQUAL "Qt")
- ADD_WEBKIT_PREFIX_HEADER(WebKit "${WEBKIT_DIR}/qt/WebKitPrefix.h")
+ ADD_PREFIX_HEADER(WebKit "${WEBKIT_DIR}/qt/WebKitPrefix.h")
endif ()
diff --git a/Source/WebKit/PlatformQt.cmake b/Source/WebKit/PlatformQt.cmake
index 8c051974b..85b427b36 100644
--- a/Source/WebKit/PlatformQt.cmake
+++ b/Source/WebKit/PlatformQt.cmake
@@ -8,6 +8,10 @@ macro(generate_header _file _var _content)
set_source_files_properties(${_file} PROPERTIES GENERATED TRUE)
endmacro()
+if (${JavaScriptCore_LIBRARY_TYPE} MATCHES STATIC)
+ add_definitions(-DSTATICALLY_LINKED_WITH_WTF -DSTATICALLY_LINKED_WITH_JavaScriptCore)
+endif ()
+
list(APPEND WebKit_INCLUDE_DIRECTORIES
"${WEBCORE_DIR}"
"${DERIVED_SOURCES_DIR}"
@@ -163,6 +167,7 @@ list(APPEND WebKit_SOURCES
qt/Api/qhttpheader.cpp
qt/Api/qwebdatabase.cpp
qt/Api/qwebelement.cpp
+ qt/Api/qwebfullscreenrequest.cpp
qt/Api/qwebhistory.cpp
qt/Api/qwebhistoryinterface.cpp
qt/Api/qwebkitglobal.cpp
@@ -320,6 +325,7 @@ ecm_generate_headers(
HEADER_NAMES
QWebDatabase
QWebElement,QWebElementCollection
+ QWebFullScreenRequest
QWebHistory,QWebHistoryItem
QWebHistoryInterface
QWebKitPlatformPlugin,QWebHapticFeedbackPlayer,QWebFullScreenVideoHandler,QWebNotificationData,QWebNotificationPresenter,QWebSelectData,QWebSelectMethod,QWebSpellChecker,QWebTouchModifier
@@ -622,11 +628,11 @@ ecm_generate_pri_file(
)
install(FILES ${WebKitWidgets_PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR})
-if (WIN32)
+if (MSVC)
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
enable_language(ASM_MASM)
list(APPEND WebKit_SOURCES
- win/plugins/PaintHooks.asm
+ win/Plugins/PaintHooks.asm
)
endif ()
@@ -653,8 +659,6 @@ if (WIN32)
${DERIVED_SOURCES_WEBKIT_DIR}
)
- set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /NODEFAULTLIB:MSVCRT /NODEFAULTLIB:MSVCRTD")
-
set(WebKit_POST_BUILD_COMMAND "${DERIVED_SOURCES_WEBKIT_DIR}/postBuild.cmd")
file(WRITE "${WebKit_POST_BUILD_COMMAND}" "@xcopy /y /d /i /f \"${CMAKE_CURRENT_SOURCE_DIR}/qt/Api/*.h\" \"${DERIVED_SOURCES_DIR}/ForwardingHeaders/QtWebkit\" >nul 2>nul\n")
file(APPEND "${WebKit_POST_BUILD_COMMAND}" "@xcopy /y /d /i /f \"${CMAKE_CURRENT_SOURCE_DIR}/qt/WidgetApi/*.h\" \"${DERIVED_SOURCES_DIR}/ForwardingHeaders/QtWebkitWidgets\" >nul 2>nul\n")
@@ -689,6 +693,10 @@ install(TARGETS WebKitWidgets EXPORT Qt5WebKitWidgetsTargets
RUNTIME DESTINATION "${BIN_INSTALL_DIR}"
)
+if (NOT MSVC AND WIN32)
+ ADD_PREFIX_HEADER(WebKitWidgets "qt/WebKitWidgetsPrefix.h")
+endif ()
+
if (USE_LINKER_VERSION_SCRIPT)
set(VERSION_SCRIPT "${CMAKE_BINARY_DIR}/QtWebKitWidgets.version")
add_custom_command(TARGET WebKitWidgets PRE_LINK
@@ -711,6 +719,7 @@ if (COMPILER_IS_GCC_OR_CLANG)
qt/WidgetApi/qgraphicswebview.cpp
qt/WidgetApi/qwebframe.cpp
+ qt/WidgetApi/qwebfullscreenrequest.cpp
qt/WidgetApi/qwebinspector.cpp
qt/WidgetApi/qwebpage.cpp
qt/WidgetApi/qwebview.cpp
diff --git a/Source/WebKit/qt/Api/qwebelement.cpp b/Source/WebKit/qt/Api/qwebelement.cpp
index 366dbdf4d..7976ed89a 100644
--- a/Source/WebKit/qt/Api/qwebelement.cpp
+++ b/Source/WebKit/qt/Api/qwebelement.cpp
@@ -152,19 +152,6 @@ QWebElement::QWebElement(WebCore::Element* domElement)
}
/*!
- \internal
-*/
-QWebElement::QWebElement(WebCore::Node* node)
- : d(0)
- , m_element(0)
-{
- if (node && node->isHTMLElement()) {
- m_element = static_cast<HTMLElement*>(node);
- m_element->ref();
- }
-}
-
-/*!
Constructs a copy of \a other.
*/
QWebElement::QWebElement(const QWebElement &other)
@@ -1422,23 +1409,6 @@ void QWebElement::replace(const QString &markup)
}
/*!
- \internal
- Walk \a node's parents until a valid QWebElement is found.
- For example, a WebCore::Text node is not a valid Html QWebElement, but its
- enclosing p tag is.
-*/
-QWebElement QWebElement::enclosingElement(WebCore::Node* node)
-{
- QWebElement element(node);
-
- while (element.isNull() && node) {
- node = node->parentNode();
- element = QWebElement(node);
- }
- return element;
-}
-
-/*!
\fn inline bool QWebElement::operator==(const QWebElement& o) const;
Returns true if this element points to the same underlying DOM object as
@@ -1502,6 +1472,38 @@ void QWebElement::render(QPainter* painter, const QRect& clip)
context.restore();
}
+void QWebElement::beginEnterFullScreen()
+{
+#if ENABLE(FULLSCREEN_API)
+ if (m_element)
+ m_element->document().webkitWillEnterFullScreenForElement(m_element);
+#endif
+}
+
+void QWebElement::endEnterFullScreen()
+{
+#if ENABLE(FULLSCREEN_API)
+ if (m_element)
+ m_element->document().webkitDidEnterFullScreenForElement(m_element);
+#endif
+}
+
+void QWebElement::beginExitFullScreen()
+{
+#if ENABLE(FULLSCREEN_API)
+ if (m_element)
+ m_element->document().webkitWillExitFullScreenForElement(m_element);
+#endif
+}
+
+void QWebElement::endExitFullScreen()
+{
+#if ENABLE(FULLSCREEN_API)
+ if (m_element)
+ m_element->document().webkitDidExitFullScreenForElement(m_element);
+#endif
+}
+
class QWebElementCollectionPrivate : public QSharedData
{
public:
diff --git a/Source/WebKit/qt/Api/qwebelement.h b/Source/WebKit/qt/Api/qwebelement.h
index 92d388dfa..b43809fea 100644
--- a/Source/WebKit/qt/Api/qwebelement.h
+++ b/Source/WebKit/qt/Api/qwebelement.h
@@ -27,9 +27,11 @@
#include <QtCore/qshareddata.h>
#include "qwebkitglobal.h"
+
namespace WebCore {
- class Element;
- class Node;
+class ChromeClientQt;
+class Element;
+class Node;
}
QT_BEGIN_NAMESPACE
@@ -37,6 +39,7 @@ class QPainter;
QT_END_NAMESPACE
class QWebFrame;
+class QWebFullScreenRequest;
class QWebElementCollection;
class QWebElementPrivate;
@@ -145,16 +148,21 @@ public:
private:
explicit QWebElement(WebCore::Element*);
- explicit QWebElement(WebCore::Node*);
- static QWebElement enclosingElement(WebCore::Node*);
+ void beginEnterFullScreen();
+ void endEnterFullScreen();
+ void beginExitFullScreen();
+ void endExitFullScreen();
+ friend class WebCore::ChromeClientQt;
friend class DumpRenderTreeSupportQt;
- friend class QWebFrameAdapter;
friend class QWebElementCollection;
+ friend class QWebFrameAdapter;
+ friend class QWebFullScreenRequest;
friend class QWebHitTestResult;
friend class QWebHitTestResultPrivate;
friend class QWebPage;
+ friend class QWebPageAdapter;
friend class QWebPagePrivate;
friend class QtWebElementRuntime;
diff --git a/Source/WebKit/qt/Api/qwebfullscreenrequest.cpp b/Source/WebKit/qt/Api/qwebfullscreenrequest.cpp
new file mode 100644
index 000000000..56e14f6c8
--- /dev/null
+++ b/Source/WebKit/qt/Api/qwebfullscreenrequest.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2016 Michal Dutkiewicz aka Emdek <michal@emdek.pl>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "qwebfullscreenrequest.h"
+
+#include "Element.h"
+#include "QWebPageAdapter.h"
+
+#include <QPointer>
+
+class QWebFullScreenRequestPrivate {
+public:
+ QWebFullScreenRequestPrivate(QWebPageAdapter* page, const QWebElement& element, bool toggleOn)
+ : element(element)
+ , toggleOn(toggleOn)
+ , accepted(false)
+ , m_handle(page->handle())
+ , m_page(page)
+ {
+ }
+
+ QWebPageAdapter* page() const
+ {
+ return m_handle.isNull() ? nullptr : m_page;
+ }
+
+ QWebElement element;
+ const bool toggleOn;
+ bool accepted;
+
+private:
+ QPointer<QObject> m_handle;
+ QWebPageAdapter* m_page;
+};
+
+QWebFullScreenRequest::QWebFullScreenRequest()
+{
+}
+
+QWebFullScreenRequest::QWebFullScreenRequest(QWebPageAdapter* page, const QWebElement& element, bool toggleOn)
+ : d(new QWebFullScreenRequestPrivate(page, element, toggleOn))
+{
+ if (element.isNull())
+ d->element = page->fullScreenElement();
+}
+
+QWebFullScreenRequest::QWebFullScreenRequest(const QWebFullScreenRequest& other)
+ : d(new QWebFullScreenRequestPrivate(*other.d))
+{
+}
+
+QWebFullScreenRequest::~QWebFullScreenRequest()
+{
+ if (d->accepted && d->page()) {
+ if (d->toggleOn) {
+ d->element.endEnterFullScreen();
+ } else {
+ d->element.endExitFullScreen();
+ d->page()->setFullScreenElement(QWebElement());
+ }
+ }
+}
+
+void QWebFullScreenRequest::accept()
+{
+ if (!d->page()) {
+ qWarning("Cannot accept QWebFullScreenRequest: Originating page is already deleted");
+ return;
+ }
+
+ d->accepted = true;
+
+ if (d->toggleOn) {
+ d->page()->setFullScreenElement(d->element);
+ d->element.beginEnterFullScreen();
+ } else {
+ d->element.beginExitFullScreen();
+ }
+}
+
+void QWebFullScreenRequest::reject()
+{
+}
+
+bool QWebFullScreenRequest::toggleOn() const
+{
+ return d->toggleOn;
+}
+
+QUrl QWebFullScreenRequest::origin() const
+{
+ if (!d->element.isNull())
+ return d->element.m_element->document().url();
+
+ return QUrl();
+}
+
+const QWebElement& QWebFullScreenRequest::element() const
+{
+ return d->element;
+}
diff --git a/Source/WebKit/qt/Api/qwebfullscreenrequest.h b/Source/WebKit/qt/Api/qwebfullscreenrequest.h
new file mode 100644
index 000000000..b86418c19
--- /dev/null
+++ b/Source/WebKit/qt/Api/qwebfullscreenrequest.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 Michal Dutkiewicz aka Emdek <michal@emdek.pl>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef QWEBFULLSCREENREQUEST_H
+#define QWEBFULLSCREENREQUEST_H
+
+#include <QtWebKit/qwebkitglobal.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/qscopedpointer.h>
+#include <QtCore/qurl.h>
+
+namespace WebCore {
+class ChromeClientQt;
+}
+
+class QWebElement;
+class QWebFullScreenRequestPrivate;
+class QWebPageAdapter;
+
+class QWEBKIT_EXPORT QWebFullScreenRequest {
+public:
+ QWebFullScreenRequest();
+ QWebFullScreenRequest(const QWebFullScreenRequest&);
+ ~QWebFullScreenRequest();
+
+ void accept();
+ void reject();
+ bool toggleOn() const;
+ QUrl origin() const;
+ const QWebElement &element() const;
+
+private:
+ friend class WebCore::ChromeClientQt;
+
+ static QWebFullScreenRequest createEnterRequest(QWebPageAdapter* page, const QWebElement& element)
+ {
+ return QWebFullScreenRequest(page, element, true);
+ }
+
+ static QWebFullScreenRequest createExitRequest(QWebPageAdapter* page, const QWebElement& element)
+ {
+ return QWebFullScreenRequest(page, element, false);
+ }
+
+ QWebFullScreenRequest(QWebPageAdapter* page, const QWebElement& element, bool toggleOn);
+ QScopedPointer<QWebFullScreenRequestPrivate> d;
+};
+
+Q_DECLARE_TYPEINFO(QWebFullScreenRequest, Q_MOVABLE_TYPE);
+Q_DECLARE_METATYPE(QWebFullScreenRequest)
+
+#endif
diff --git a/Source/WebKit/qt/Api/qwebsettings.cpp b/Source/WebKit/qt/Api/qwebsettings.cpp
index 98632be63..9adc662b7 100644
--- a/Source/WebKit/qt/Api/qwebsettings.cpp
+++ b/Source/WebKit/qt/Api/qwebsettings.cpp
@@ -272,6 +272,10 @@ void QWebSettingsPrivate::apply()
global->attributes.value(QWebSettings::XSSAuditingEnabled));
settings->setXSSAuditorEnabled(value);
+ value = attributes.value(QWebSettings::WebSecurityEnabled,
+ global->attributes.value(QWebSettings::WebSecurityEnabled));
+ settings->setWebSecurityEnabled(value);
+
#if USE(TILED_BACKING_STORE)
value = attributes.value(QWebSettings::TiledBackingStoreEnabled,
global->attributes.value(QWebSettings::TiledBackingStoreEnabled));
@@ -296,6 +300,9 @@ void QWebSettingsPrivate::apply()
global->attributes.value(QWebSettings::SiteSpecificQuirksEnabled));
settings->setNeedsSiteSpecificQuirks(value);
+ value = attributes.value(QWebSettings::FullScreenSupportEnabled, global->attributes.value(QWebSettings::FullScreenSupportEnabled));
+ settings->setFullScreenEnabled(value);
+
settings->setUsesPageCache(WebCore::PageCache::singleton().maxSize());
} else {
QList<QWebSettingsPrivate*> settings = *::allSettings();
@@ -508,6 +515,11 @@ QWebSettings* QWebSettings::globalSettings()
\value CaretBrowsingEnabled This setting enables caret browsing. It is disabled by default.
\value NotificationsEnabled Specifies whether support for the HTML 5 web notifications is enabled
or not. This is enabled by default.
+ \value WebSecurityEnabled Specifies whether browser should enforce same-origin policy for scripts downloaded
+ from remote servers. This setting is set to true by default. Note that setting this flag to false is
+ strongly discouraged as it makes the browser more prone to malicious code. This setting is intended
+ primarily for site-specific browsers (i.e. when the user can't navigate to unsecure web page) and for testing
+ web applications before deployment.
*/
/*!
@@ -565,6 +577,8 @@ QWebSettings::QWebSettings()
d->attributes.insert(QWebSettings::ScrollAnimatorEnabled, false);
d->attributes.insert(QWebSettings::CaretBrowsingEnabled, false);
d->attributes.insert(QWebSettings::NotificationsEnabled, true);
+ d->attributes.insert(QWebSettings::WebSecurityEnabled, true);
+ d->attributes.insert(QWebSettings::FullScreenSupportEnabled, true);
d->offlineStorageDefaultQuota = 5 * 1024 * 1024;
d->defaultTextEncoding = QLatin1String("iso-8859-1");
d->thirdPartyCookiePolicy = AlwaysAllowThirdPartyCookies;
diff --git a/Source/WebKit/qt/Api/qwebsettings.h b/Source/WebKit/qt/Api/qwebsettings.h
index 0dd48cb90..11fae751f 100644
--- a/Source/WebKit/qt/Api/qwebsettings.h
+++ b/Source/WebKit/qt/Api/qwebsettings.h
@@ -87,7 +87,9 @@ public:
NotificationsEnabled,
WebAudioEnabled,
MediaSourceEnabled,
- MediaEnabled
+ MediaEnabled,
+ WebSecurityEnabled,
+ FullScreenSupportEnabled
};
enum WebGraphic {
MissingImageGraphic,
diff --git a/Source/WebKit/qt/WebCoreSupport/ChromeClientQt.cpp b/Source/WebKit/qt/WebCoreSupport/ChromeClientQt.cpp
index 5ce067db2..1c6504993 100644
--- a/Source/WebKit/qt/WebCoreSupport/ChromeClientQt.cpp
+++ b/Source/WebKit/qt/WebCoreSupport/ChromeClientQt.cpp
@@ -64,6 +64,7 @@
#endif
#include "ViewportArguments.h"
#include "WindowFeatures.h"
+#include "qwebfullscreenrequest.h"
#include "qwebkitplatformplugin.h"
#include "qwebsecurityorigin.h"
#include "qwebsecurityorigin_p.h"
@@ -208,16 +209,24 @@ void ChromeClientQt::takeFocus(FocusDirection)
}
-void ChromeClientQt::focusedElementChanged(Element*)
+void ChromeClientQt::focusedElementChanged(Element* element)
{
+ emit m_webPage->focusedElementChanged(QWebElement(element));
}
void ChromeClientQt::focusedFrameChanged(Frame*)
{
}
-Page* ChromeClientQt::createWindow(Frame*, const FrameLoadRequest& request, const WindowFeatures& features, const NavigationAction&)
+Page* ChromeClientQt::createWindow(Frame* frame, const FrameLoadRequest&, const WindowFeatures& features, const NavigationAction&)
{
+#if ENABLE(FULLSCREEN_API)
+ if (frame->document() && frame->document()->webkitCurrentFullScreenElement())
+ frame->document()->webkitCancelFullScreen();
+#else
+ UNUSED_PARAM(frame);
+#endif
+
QWebPageAdapter* newPage = m_webPage->createWindow(features.dialog);
if (!newPage)
return 0;
@@ -703,6 +712,23 @@ void ChromeClientQt::exitVideoFullscreenForVideoElement(HTMLVideoElement& videoE
}
#endif
+#if ENABLE(FULLSCREEN_API)
+bool ChromeClientQt::supportsFullScreenForElement(const Element*, bool withKeyboard)
+{
+ return !withKeyboard;
+}
+
+void ChromeClientQt::enterFullScreenForElement(Element* element)
+{
+ m_webPage->fullScreenRequested(QWebFullScreenRequest::createEnterRequest(m_webPage, QWebElement(element)));
+}
+
+void ChromeClientQt::exitFullScreenForElement(Element* element)
+{
+ m_webPage->fullScreenRequested(QWebFullScreenRequest::createExitRequest(m_webPage, QWebElement(element)));
+}
+#endif
+
std::unique_ptr<QWebSelectMethod> ChromeClientQt::createSelectPopup() const
{
std::unique_ptr<QWebSelectMethod> result = m_platformPlugin.createSelectInputMethod();
diff --git a/Source/WebKit/qt/WebCoreSupport/ChromeClientQt.h b/Source/WebKit/qt/WebCoreSupport/ChromeClientQt.h
index 9aef6baef..11826d535 100644
--- a/Source/WebKit/qt/WebCoreSupport/ChromeClientQt.h
+++ b/Source/WebKit/qt/WebCoreSupport/ChromeClientQt.h
@@ -163,6 +163,12 @@ public:
FullScreenVideoQt* fullScreenVideo();
#endif
+#if ENABLE(FULLSCREEN_API)
+ bool supportsFullScreenForElement(const Element*, bool) override;
+ void enterFullScreenForElement(Element*) override;
+ void exitFullScreenForElement(Element*) override;
+#endif
+
#if ENABLE(INPUT_TYPE_COLOR)
std::unique_ptr<ColorChooser> createColorChooser(ColorChooserClient*, const Color&) final;
#endif
diff --git a/Source/WebKit/qt/WebCoreSupport/PlatformStrategiesQt.cpp b/Source/WebKit/qt/WebCoreSupport/PlatformStrategiesQt.cpp
index 321044ad3..5a46e61ef 100644
--- a/Source/WebKit/qt/WebCoreSupport/PlatformStrategiesQt.cpp
+++ b/Source/WebKit/qt/WebCoreSupport/PlatformStrategiesQt.cpp
@@ -152,17 +152,14 @@ void PlatformStrategiesQt::getPluginInfo(const WebCore::Page* page, Vector<WebCo
PluginDatabase* db = PluginDatabase::installedPlugins();
const Vector<PluginPackage*> &plugins = db->plugins();
- for (int i = 0; i < plugins.size(); ++i) {
+ for (auto* package : plugins) {
PluginInfo info;
- PluginPackage* package = plugins[i];
-
info.name = package->name();
info.file = package->fileName();
info.desc = package->description();
- const MIMEToDescriptionsMap& mimeToDescriptions = package->mimeToDescriptions();
- MIMEToDescriptionsMap::const_iterator end = mimeToDescriptions.end();
- for (MIMEToDescriptionsMap::const_iterator it = mimeToDescriptions.begin(); it != end; ++it) {
+ const auto& mimeToDescriptions = package->mimeToDescriptions();
+ for (auto it = mimeToDescriptions.begin(); it != mimeToDescriptions.end(); ++it) {
MimeClassInfo mime;
mime.type = it->key;
diff --git a/Source/WebKit/qt/WebCoreSupport/QWebPageAdapter.cpp b/Source/WebKit/qt/WebCoreSupport/QWebPageAdapter.cpp
index 49031d512..e1789f9e2 100644
--- a/Source/WebKit/qt/WebCoreSupport/QWebPageAdapter.cpp
+++ b/Source/WebKit/qt/WebCoreSupport/QWebPageAdapter.cpp
@@ -1368,6 +1368,22 @@ bool QWebPageAdapter::isPlayingAudio() const
return page->mediaState() & MediaProducer::IsPlayingAudio;
}
+const QWebElement& QWebPageAdapter::fullScreenElement() const
+{
+#if ENABLE(FULLSCREEN_API)
+ return m_fullScreenElement;
+#endif
+}
+
+void QWebPageAdapter::setFullScreenElement(const QWebElement& e)
+{
+#if ENABLE(FULLSCREEN_API)
+ m_fullScreenElement = e;
+#else
+ UNUSED_PARAM(e);
+#endif
+}
+
bool QWebPageAdapter::handleKeyEvent(QKeyEvent *ev)
{
Frame& frame = page->focusController().focusedOrMainFrame();
diff --git a/Source/WebKit/qt/WebCoreSupport/QWebPageAdapter.h b/Source/WebKit/qt/WebCoreSupport/QWebPageAdapter.h
index 4017f6fc3..324d0381d 100644
--- a/Source/WebKit/qt/WebCoreSupport/QWebPageAdapter.h
+++ b/Source/WebKit/qt/WebCoreSupport/QWebPageAdapter.h
@@ -21,6 +21,7 @@
#define QWebPageAdapter_h
#include "QWebPageClient.h"
+#include "qwebelement.h"
#include "qwebhistory.h"
#include <qbasictimer.h>
@@ -55,6 +56,7 @@ struct ViewportArguments;
class QtPluginWidgetAdapter;
class QWebFrameAdapter;
+class QWebFullScreenRequest;
class QWebHistoryItem;
class QWebHitTestResultPrivate;
class QWebPageClient;
@@ -206,6 +208,7 @@ public:
#if USE(QT_MULTIMEDIA)
virtual QWebFullScreenVideoHandler* createFullScreenVideoHandler() = 0;
#endif
+ virtual void fullScreenRequested(QWebFullScreenRequest) = 0;
virtual void geolocationPermissionRequested(QWebFrameAdapter*) = 0;
virtual void geolocationPermissionRequestCancelled(QWebFrameAdapter*) = 0;
virtual void notificationsPermissionRequested(QWebFrameAdapter*) = 0;
@@ -286,6 +289,7 @@ public:
virtual bool handleScrollbarContextMenuEvent(QContextMenuEvent*, bool, ScrollDirection*, ScrollGranularity*) = 0;
virtual void recentlyAudibleChanged(bool) = 0;
+ virtual void focusedElementChanged(const QWebElement&) = 0;
void setVisibilityState(VisibilityState);
VisibilityState visibilityState() const;
@@ -383,6 +387,9 @@ public:
bool isPlayingAudio() const;
+ const QWebElement& fullScreenElement() const;
+ void setFullScreenElement(const QWebElement&);
+
QWebSettings *settings;
WebCore::Page *page;
@@ -407,6 +414,10 @@ private:
WebCore::DeviceOrientationClient* m_deviceOrientationClient;
WebCore::DeviceMotionClient* m_deviceMotionClient;
+#if ENABLE(FULLSCREEN_API)
+ QWebElement m_fullScreenElement;
+#endif
+
public:
static bool drtRun;
diff --git a/Source/WebKit/qt/WidgetApi/qwebpage.cpp b/Source/WebKit/qt/WidgetApi/qwebpage.cpp
index 82f59e916..80fbf5697 100644
--- a/Source/WebKit/qt/WidgetApi/qwebpage.cpp
+++ b/Source/WebKit/qt/WidgetApi/qwebpage.cpp
@@ -214,6 +214,11 @@ QWebPagePrivate::QWebPagePrivate(QWebPage *qq)
setSystemTrayIcon(new QSystemTrayIcon);
#endif // QT_NO_SYSTEMTRAYICON
#endif // ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
+
+ qRegisterMetaType<QWebFullScreenRequest>();
+ int fullScreenRequestedIndex = q->metaObject()->indexOfMethod("fullScreenRequested(QWebFullScreenRequest)");
+ Q_ASSERT(fullScreenRequestedIndex != -1);
+ m_fullScreenRequested = q->metaObject()->method(fullScreenRequestedIndex);
}
void QWebPagePrivate::show()
diff --git a/Source/WebKit/qt/WidgetApi/qwebpage.h b/Source/WebKit/qt/WidgetApi/qwebpage.h
index 6b465e557..12340cc75 100644
--- a/Source/WebKit/qt/WidgetApi/qwebpage.h
+++ b/Source/WebKit/qt/WidgetApi/qwebpage.h
@@ -22,6 +22,7 @@
#define QWEBPAGE_H
#include <QtWebKit/qwebkitglobal.h>
+#include <QtWebKit/qwebfullscreenrequest.h>
#include <QtWebKit/qwebsettings.h>
#include <QtCore/qobject.h>
@@ -44,6 +45,7 @@ class QWebNetworkRequest;
class QWebHistory;
class QWebFrameData;
+class QWebFullScreenRequest;
class QWebHistoryItem;
class QWebHitTestResult;
class QWebNetworkInterface;
@@ -438,6 +440,7 @@ Q_SIGNALS:
void unsupportedContent(QNetworkReply *reply);
void downloadRequested(const QNetworkRequest &request);
+ void focusedElementChanged(const QWebElement &element);
void microFocusChanged();
void contentsChanged();
void databaseQuotaExceeded(QWebFrame* frame, QString databaseName);
@@ -450,6 +453,7 @@ Q_SIGNALS:
void featurePermissionRequested(QWebFrame* frame, QWebPage::Feature feature);
void featurePermissionRequestCanceled(QWebFrame* frame, QWebPage::Feature feature);
+ void fullScreenRequested(QWebFullScreenRequest fullScreenRequest);
void consoleMessageReceived(MessageSource source, MessageLevel level, const QString& message, int lineNumber, const QString& sourceID);
@@ -479,6 +483,7 @@ private:
QWebPagePrivate *d;
friend class QWebFrame;
+ friend class QWebFullScreenRequest;
friend class QWebPagePrivate;
friend class QWebView;
friend class QWebViewPrivate;
diff --git a/Source/WebKit/qt/WidgetApi/qwebpage_p.cpp b/Source/WebKit/qt/WidgetApi/qwebpage_p.cpp
index 2fffc7e1c..da20e7266 100644
--- a/Source/WebKit/qt/WidgetApi/qwebpage_p.cpp
+++ b/Source/WebKit/qt/WidgetApi/qwebpage_p.cpp
@@ -23,6 +23,7 @@
#include "qwebpage_p.h"
#include "qwebframe_p.h"
+#include "qwebfullscreenrequest.h"
#include "qwebinspector.h"
#include <QMenu>
#include <QUndoStack>
@@ -53,7 +54,17 @@ QWebPagePrivate::~QWebPagePrivate()
QWebFramePrivate::~QWebFramePrivate() = default;
+void QWebPagePrivate::fullScreenRequested(QWebFullScreenRequest request)
+{
+ m_fullScreenRequested.invoke(q, Qt::QueuedConnection, Q_ARG(QWebFullScreenRequest, request));
+}
+
void QWebPagePrivate::recentlyAudibleChanged(bool recentlyAudible)
{
emit q->recentlyAudibleChanged(recentlyAudible);
}
+
+void QWebPagePrivate::focusedElementChanged(const QWebElement& element)
+{
+ emit q->focusedElementChanged(element);
+}
diff --git a/Source/WebKit/qt/WidgetApi/qwebpage_p.h b/Source/WebKit/qt/WidgetApi/qwebpage_p.h
index 1725eb6d1..630f85b5a 100644
--- a/Source/WebKit/qt/WidgetApi/qwebpage_p.h
+++ b/Source/WebKit/qt/WidgetApi/qwebpage_p.h
@@ -31,6 +31,7 @@
#include <qgesture.h>
#include <qgraphicssceneevent.h>
#include <qgraphicswidget.h>
+#include <qmetaobject.h>
#include <qnetworkproxy.h>
@@ -101,6 +102,7 @@ public:
QColor colorSelectionRequested(const QColor& selectedColor) override;
std::unique_ptr<QWebSelectMethod> createSelectPopup() override;
QRect viewRectRelativeToWindow() override;
+ void fullScreenRequested(QWebFullScreenRequest) override;
void geolocationPermissionRequested(QWebFrameAdapter*) override;
void geolocationPermissionRequestCancelled(QWebFrameAdapter*) override;
void notificationsPermissionRequested(QWebFrameAdapter*) override;
@@ -141,6 +143,7 @@ public:
void createAndSetCurrentContextMenu(const QList<MenuItemDescription>&, QBitArray*) override;
bool handleScrollbarContextMenuEvent(QContextMenuEvent*, bool, ScrollDirection*, ScrollGranularity*) override;
void recentlyAudibleChanged(bool) override;
+ void focusedElementChanged(const QWebElement&) override;
void createMainFrame();
@@ -205,6 +208,8 @@ public:
QWebInspector* inspector;
bool inspectorIsInternalOnly; // True if created through the Inspect context menu action
Qt::DropAction m_lastDropAction;
+
+ QMetaMethod m_fullScreenRequested;
};
#endif
diff --git a/Source/WebKit/qt/tests/CMakeLists.txt b/Source/WebKit/qt/tests/CMakeLists.txt
index 9054ba1ae..8c96f4cbf 100644
--- a/Source/WebKit/qt/tests/CMakeLists.txt
+++ b/Source/WebKit/qt/tests/CMakeLists.txt
@@ -26,7 +26,6 @@ set(QtWK1ApiTests_LIBRARIES
${Qt5Network_LIBRARIES}
${Qt5Test_LIBRARIES}
${Qt5Widgets_LIBRARIES}
- WebCoreTestSupport
WebKitWidgets
)
@@ -36,9 +35,6 @@ set(QtWK1ApiTests_RUNTIME_OUTPUT_DIRECTORY
)
set(QtWK1ApiTests
- keyeddecoderqt
- keyedencoderqt
-
qgraphicswebview
qobjectbridge
qwebelement
diff --git a/Source/WebKit2/NetworkProcess/Downloads/qt/QtFileDownloader.cpp b/Source/WebKit2/NetworkProcess/Downloads/qt/QtFileDownloader.cpp
index 0ec67704c..abed3cd34 100644
--- a/Source/WebKit2/NetworkProcess/Downloads/qt/QtFileDownloader.cpp
+++ b/Source/WebKit2/NetworkProcess/Downloads/qt/QtFileDownloader.cpp
@@ -60,33 +60,6 @@ void QtFileDownloader::init()
connect(m_reply.get(), SIGNAL(error(QNetworkReply::NetworkError)), SLOT(onError(QNetworkReply::NetworkError)));
}
-QString QtFileDownloader::determineFilename()
-{
- ASSERT(!m_destinationFile);
-
- QString filenameCandidate = filenameFromHTTPContentDisposition(QString::fromLatin1(m_reply->rawHeader("Content-Disposition")));
- if (filenameCandidate.isEmpty()) {
- URL kurl = m_reply->url();
- filenameCandidate = decodeURLEscapeSequences(kurl.lastPathComponent());
- }
-
- if (filenameCandidate.isEmpty()) {
- abortDownloadWritingAndEmitError(QtFileDownloader::DownloadErrorCannotDetermineFilename);
- return QString();
- }
-
- // Make sure that we remove possible "../.." parts in the given file name.
- QFileInfo filenameFilter(filenameCandidate);
- QString filename = filenameFilter.fileName();
-
- if (filename.isEmpty()) {
- abortDownloadWritingAndEmitError(QtFileDownloader::DownloadErrorCannotDetermineFilename);
- return QString();
- }
-
- return filename;
-}
-
void QtFileDownloader::startTransfer(const QString& decidedFilePath)
{
ASSERT(!m_destinationFile);
@@ -172,17 +145,12 @@ void QtFileDownloader::handleDownloadResponse()
String contentType = m_reply->header(QNetworkRequest::ContentTypeHeader).toString();
String encoding = extractCharsetFromMediaType(contentType);
String mimeType = extractMIMETypeFromMediaType(contentType);
- String filename = determineFilename();
-
- // If filename is empty it means determineFilename aborted and emitted an error.
- if (filename.isEmpty())
- return;
// Let's try to guess from the extension.
if (mimeType.isEmpty())
mimeType = MIMETypeRegistry::getMIMETypeForPath(m_reply->url().path());
- ResourceResponse response(m_reply->url(), mimeType, m_reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), encoding, filename);
+ ResourceResponse response(m_reply->url(), mimeType, m_reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), encoding);
m_download->didReceiveResponse(response);
}
diff --git a/Source/WebKit2/NetworkProcess/Downloads/qt/QtFileDownloader.h b/Source/WebKit2/NetworkProcess/Downloads/qt/QtFileDownloader.h
index 2b096760c..738f38b9c 100644
--- a/Source/WebKit2/NetworkProcess/Downloads/qt/QtFileDownloader.h
+++ b/Source/WebKit2/NetworkProcess/Downloads/qt/QtFileDownloader.h
@@ -63,7 +63,6 @@ private Q_SLOTS:
private:
void abortDownloadWritingAndEmitError(QtFileDownloader::DownloadError);
- QString determineFilename();
void handleDownloadResponse();
Download* m_download;
diff --git a/Source/WebKit2/Platform/IPC/unix/ConnectionUnix.cpp b/Source/WebKit2/Platform/IPC/unix/ConnectionUnix.cpp
index 71f2e252f..18d02cdd9 100644
--- a/Source/WebKit2/Platform/IPC/unix/ConnectionUnix.cpp
+++ b/Source/WebKit2/Platform/IPC/unix/ConnectionUnix.cpp
@@ -423,7 +423,10 @@ bool Connection::open()
return G_SOURCE_REMOVE;
});
#elif PLATFORM(QT)
- m_socketNotifier = m_connectionQueue->registerSocketEventHandler(m_socketDescriptor, QSocketNotifier::Read, WTF::bind(&Connection::readyReadHandler, this));
+ m_socketNotifier = m_connectionQueue->registerSocketEventHandler(m_socketDescriptor, QSocketNotifier::Read,
+ [protectedThis] {
+ protectedThis->readyReadHandler();
+ });
#elif PLATFORM(EFL)
m_connectionQueue->registerSocketEventHandler(m_socketDescriptor,
[protectedThis] {
@@ -603,7 +606,11 @@ void Connection::didReceiveSyncReply(unsigned flags)
#if PLATFORM(QT)
void Connection::setShouldCloseConnectionOnProcessTermination(WebKit::PlatformProcessIdentifier process)
{
- m_connectionQueue->dispatchOnTermination(process, WTF::bind(&Connection::connectionDidClose, this));
+ RefPtr<Connection> protectedThis(this);
+ m_connectionQueue->dispatchOnTermination(process,
+ [protectedThis] {
+ protectedThis->connectionDidClose();
+ });
}
#endif
diff --git a/Source/WebKit2/Shared/qt/ShareableBitmapQt.cpp b/Source/WebKit2/Shared/qt/ShareableBitmapQt.cpp
index 764567cdc..fd31b5240 100644
--- a/Source/WebKit2/Shared/qt/ShareableBitmapQt.cpp
+++ b/Source/WebKit2/Shared/qt/ShareableBitmapQt.cpp
@@ -58,7 +58,7 @@ PassRefPtr<Image> ShareableBitmap::createImage()
std::unique_ptr<GraphicsContext> ShareableBitmap::createGraphicsContext()
{
- // FIXME: Should this be OwnPtr<QImage>?
+ // QTFIXME: Shallow QImage leaks here, but it should not be destroyed earlier than QPainter
QImage* image = new QImage(createQImage());
QPainter* painter = new QPainter(image);
painter->setRenderHint(QPainter::SmoothPixmapTransform, true);
diff --git a/Source/WebKit2/UIProcess/API/C/WKNativeEvent.h b/Source/WebKit2/UIProcess/API/C/WKNativeEvent.h
index 10bed36ea..bfce62e00 100644
--- a/Source/WebKit2/UIProcess/API/C/WKNativeEvent.h
+++ b/Source/WebKit2/UIProcess/API/C/WKNativeEvent.h
@@ -34,7 +34,7 @@
extern "C" {
#endif
-#if defined(__APPLE__) && !TARGET_OS_IPHONE && !defined(BUILDING_GTK__)
+#if defined(__APPLE__) && !TARGET_OS_IPHONE && !defined(BUILDING_GTK__) && !defined(BUILDING_QT__)
#ifdef __OBJC__
@class NSEvent;
#elif __cplusplus
@@ -48,7 +48,7 @@ typedef const struct tagMSG* WKNativeEventPtr;
#elif defined(BUILDING_GTK__)
typedef union _GdkEvent GdkEvent;
typedef const GdkEvent* WKNativeEventPtr;
-#else
+#elif !defined(BUILDING_QT__)
typedef const void* WKNativeEventPtr;
#endif
@@ -56,4 +56,12 @@ typedef const void* WKNativeEventPtr;
}
#endif
+#if defined(BUILDING_QT__)
+#include <qglobal.h>
+QT_BEGIN_NAMESPACE
+class QEvent;
+QT_END_NAMESPACE
+typedef const QEvent* WKNativeEventPtr;
+#endif
+
#endif /* WKNativeEvent_h */
diff --git a/Source/WebKit2/UIProcess/API/C/qt/WKNativeEvent.h b/Source/WebKit2/UIProcess/API/C/qt/WKNativeEvent.h
deleted file mode 100644
index 974db375f..000000000
--- a/Source/WebKit2/UIProcess/API/C/qt/WKNativeEvent.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#ifndef WKNativeEvent_h
-#define WKNativeEvent_h
-
-// a Qt specific WKNativeEvent.h file is needed because that the use of __APPLE__
-// in original WKNativeEvent.h file breaks Qt build in MacOS
-
-QT_BEGIN_NAMESPACE
-class QEvent;
-QT_END_NAMESPACE
-typedef const QEvent* WKNativeEventPtr;
-
-#endif /* WKNativeEvent_h */
diff --git a/Source/WebKit2/UIProcess/Launcher/qt/ProcessLauncherQt.cpp b/Source/WebKit2/UIProcess/Launcher/qt/ProcessLauncherQt.cpp
index 448f024c4..84cb7ea0b 100644
--- a/Source/WebKit2/UIProcess/Launcher/qt/ProcessLauncherQt.cpp
+++ b/Source/WebKit2/UIProcess/Launcher/qt/ProcessLauncherQt.cpp
@@ -113,7 +113,7 @@ void QtWebProcess::setupChildProcess()
void ProcessLauncher::launchProcess()
{
QString commandLine;
- if (m_launchOptions.processType == WebProcess) {
+ if (m_launchOptions.processType == ProcessType::Web) {
commandLine = QLatin1String("%1 \"%2\" %3");
QByteArray webProcessPrefix = qgetenv("QT_WEBKIT2_WP_CMD_PREFIX");
commandLine = commandLine.arg(QLatin1String(webProcessPrefix.constData())).arg(QString(executablePathOfWebProcess()));
@@ -218,7 +218,10 @@ void ProcessLauncher::launchProcess()
#if OS(UNIX)
setpriority(PRIO_PROCESS, webProcessOrSUIDHelper->pid(), 10);
#endif
- RunLoop::main()->dispatch(bind(&WebKit::ProcessLauncher::didFinishLaunchingProcess, this, webProcessOrSUIDHelper, connector));
+ RefPtr<ProcessLauncher> protector(this);
+ RunLoop::main().dispatch([protector, webProcessOrSUIDHelper, connector] {
+ protector->didFinishLaunchingProcess(webProcessOrSUIDHelper, connector);
+ });
}
void ProcessLauncher::terminateProcess()
diff --git a/Source/WebKit2/UIProcess/WebPageProxy.messages.in b/Source/WebKit2/UIProcess/WebPageProxy.messages.in
index cef2edc6b..fd205c52d 100644
--- a/Source/WebKit2/UIProcess/WebPageProxy.messages.in
+++ b/Source/WebKit2/UIProcess/WebPageProxy.messages.in
@@ -148,7 +148,7 @@ messages -> WebPageProxy {
FrameDidBecomeFrameSet(uint64_t frameID, bool value)
#if PLATFORM(QT)
- ResolveApplicationSchemeRequest(WebKit::QtNetworkRequestData request)
+ ResolveApplicationSchemeRequest(struct WebKit::QtNetworkRequestData request)
#endif
# History client messages.
diff --git a/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in b/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in
index 1177f979a..d6007b331 100644
--- a/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in
+++ b/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in
@@ -139,7 +139,7 @@ messages -> WebPage LegacyReceiver {
StopLoading()
#if PLATFORM(QT)
- ApplicationSchemeReply(WebKit::QtNetworkReplyData reply)
+ ApplicationSchemeReply(struct WebKit::QtNetworkReplyData reply)
RegisterApplicationScheme(String scheme)
#endif
diff --git a/Source/cmake/OptionsQt.cmake b/Source/cmake/OptionsQt.cmake
index 378158615..5d2c315b4 100644
--- a/Source/cmake/OptionsQt.cmake
+++ b/Source/cmake/OptionsQt.cmake
@@ -5,9 +5,24 @@ include(ECMQueryQmake)
set(ECM_MODULE_DIR ${CMAKE_MODULE_PATH})
include(KDEInstallDirs)
-if (CONANBUILDINFO_PATH)
- include(${CONANBUILDINFO_PATH})
+set(QT_CONAN_DIR "" CACHE PATH "Directory containing conanbuildinfo.cmake and conanfile.txt")
+if (QT_CONAN_DIR)
+ include("${QT_CONAN_DIR}/conanbuildinfo.cmake")
conan_basic_setup()
+
+ install(CODE "
+ set(_conan_imports_dest \${CMAKE_INSTALL_PREFIX})
+ if (DEFINED ENV{DESTDIR})
+ get_filename_component(_absolute_destdir \$ENV{DESTDIR} ABSOLUTE)
+ string(REGEX REPLACE \"^[A-z]:\" \"\" _conan_imports_dest \${CMAKE_INSTALL_PREFIX})
+ set(_conan_imports_dest \"\${_absolute_destdir}\${_conan_imports_dest}\")
+ endif ()
+
+ execute_process(
+ COMMAND conan imports -f \"${QT_CONAN_DIR}/conanfile.txt\" --dest \${_conan_imports_dest}
+ WORKING_DIRECTORY \"${QT_CONAN_DIR}\"
+ )
+ ")
endif ()
set(STATIC_DEPENDENCIES_CMAKE_FILE "${CMAKE_BINARY_DIR}/QtStaticDependencies.cmake")
@@ -19,7 +34,10 @@ macro(CONVERT_PRL_LIBS_TO_CMAKE _qt_component)
if (TARGET Qt5::${_qt_component})
get_target_property(_lib_location Qt5::${_qt_component} LOCATION)
execute_process(COMMAND ${PERL_EXECUTABLE} ${TOOLS_DIR}/qt/convert-prl-libs-to-cmake.pl
- ${_lib_location} ${_qt_component} ${STATIC_DEPENDENCIES_CMAKE_FILE}
+ --lib ${_lib_location}
+ --out ${STATIC_DEPENDENCIES_CMAKE_FILE}
+ --component ${_qt_component}
+ --compiler ${CMAKE_CXX_COMPILER_ID}
)
endif ()
endmacro()
@@ -86,6 +104,7 @@ endif ()
WEBKIT_OPTION_DEFINE(USE_GSTREAMER "Use GStreamer implementation of MediaPlayer" PUBLIC ${USE_GSTREAMER_DEFAULT})
WEBKIT_OPTION_DEFINE(USE_LIBHYPHEN "Use automatic hyphenation with LibHyphen" PUBLIC ${USE_LIBHYPHEN_DEFAULT})
+WEBKIT_OPTION_DEFINE(USE_MEDIA_FOUNDATION "Use MediaFoundation implementation of MediaPlayer" PUBLIC OFF)
WEBKIT_OPTION_DEFINE(USE_QT_MULTIMEDIA "Use Qt Multimedia implementation of MediaPlayer" PUBLIC ${USE_QT_MULTIMEDIA_DEFAULT})
WEBKIT_OPTION_DEFINE(USE_WOFF2 "Include support of WOFF2 fonts format" PUBLIC ON)
WEBKIT_OPTION_DEFINE(ENABLE_INSPECTOR_UI "Include Inspector UI into resources" PUBLIC ON)
@@ -94,7 +113,9 @@ WEBKIT_OPTION_DEFINE(ENABLE_PRINT_SUPPORT "Enable support for printing web pages
WEBKIT_OPTION_DEFINE(ENABLE_X11_TARGET "Whether to enable support for the X11 windowing target." PUBLIC ${ENABLE_X11_TARGET_DEFAULT})
option(GENERATE_DOCUMENTATION "Generate HTML and QCH documentation" OFF)
-option(ENABLE_TEST_SUPPORT "Build tools for running layout tests and related library code" ON)
+cmake_dependent_option(ENABLE_TEST_SUPPORT "Build tools for running layout tests and related library code" ON
+ "DEVELOPER_MODE" OFF)
+option(USE_STATIC_RUNTIME "Use static runtime (MSVC only)" OFF)
# Public options shared with other WebKit ports. There must be strong reason
# to support changing the value of the option.
@@ -104,7 +125,7 @@ WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_CSS_GRID_LAYOUT PUBLIC ON)
WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DATABASE_PROCESS PUBLIC OFF)
WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DATALIST_ELEMENT PUBLIC ON)
WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DEVICE_ORIENTATION PUBLIC ON)
-WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_FULLSCREEN_API PUBLIC OFF)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_FULLSCREEN_API PUBLIC ON)
WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_GAMEPAD_DEPRECATED PUBLIC ${ENABLE_GAMEPAD_DEPRECATED_DEFAULT})
WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_INDEXED_DATABASE PUBLIC ON)
WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_LEGACY_WEB_AUDIO PUBLIC ${USE_GSTREAMER_DEFAULT})
@@ -198,6 +219,9 @@ SET_AND_EXPOSE_TO_BUILD(USE_TEXTURE_MAPPER TRUE)
if (WIN32)
# bmalloc is not ported to Windows yet
set(USE_SYSTEM_MALLOC 1)
+endif ()
+
+if (MSVC)
if (NOT WEBKIT_LIBRARIES_DIR)
if (DEFINED ENV{WEBKIT_LIBRARIES})
set(WEBKIT_LIBRARIES_DIR "$ENV{WEBKIT_LIBRARIES}")
@@ -399,6 +423,10 @@ if (COMPILER_IS_GCC_OR_CLANG AND UNIX)
endif ()
endif ()
+if (WIN32 AND COMPILER_IS_GCC_OR_CLANG)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-keep-inline-dllexport")
+endif ()
+
if (ENABLE_MATHML)
SET_AND_EXPOSE_TO_BUILD(ENABLE_OPENTYPE_MATH 1)
endif ()
@@ -525,8 +553,12 @@ endif ()
# set(JavaScriptCore_LIBRARY_TYPE STATIC)
# From OptionsWin.cmake
+if (WIN32)
+ add_definitions(-DNOMINMAX -DUNICODE -D_UNICODE -D_WINDOWS)
+endif ()
+
if (MSVC)
- add_definitions(-DNOMINMAX -DUNICODE -D_UNICODE -D_WINDOWS -DWINVER=0x601)
+ add_definitions(-DWINVER=0x601)
add_definitions(
/wd4018 /wd4068 /wd4099 /wd4100 /wd4127 /wd4138 /wd4146 /wd4180 /wd4189
@@ -537,11 +569,15 @@ if (MSVC)
/wd6246 /wd6255 /wd6387
)
- # Create pdb files for debugging purposes, also for Release builds
- add_compile_options(/Zi /GS)
+ if (CMAKE_SIZEOF_VOID_P EQUAL 8)
+ # Create pdb files for debugging purposes, also for Release builds
+ set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Zi")
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi")
+ set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS} /DEBUG")
+ set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS} /DEBUG")
+ endif ()
- set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DEBUG")
- set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DEBUG")
+ add_compile_options(/GS)
# We do not use exceptions
add_definitions(-D_HAS_EXCEPTIONS=0)
@@ -587,16 +623,18 @@ if (MSVC)
if (NOT ${CMAKE_CXX_FLAGS} STREQUAL "")
string(REGEX REPLACE "(/EH[a-z]+) " "\\1- " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) # Disable C++ exceptions
string(REGEX REPLACE "/EHsc$" "/EHs- /EHc- " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) # Disable C++ exceptions
- string(REGEX REPLACE "/GR " "/GR- " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) # Disable RTTI
+ string(REGEX REPLACE "/EHsc- " "/EHs- /EHc- " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) # Disable C++ exceptions
string(REGEX REPLACE "/W3" "/W4" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) # Warnings are important
endif ()
- foreach (flag_var
- CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
- CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
- # Use the multithreaded static runtime library instead of the default DLL runtime.
- string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
- endforeach ()
+ if (USE_STATIC_RUNTIME)
+ foreach (flag_var
+ CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
+ CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
+ # Use the multithreaded static runtime library instead of the default DLL runtime.
+ string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
+ endforeach ()
+ endif ()
set(ICU_LIBRARIES icuuc${CMAKE_DEBUG_POSTFIX} icuin${CMAKE_DEBUG_POSTFIX} icudt${CMAKE_DEBUG_POSTFIX})
endif ()
diff --git a/Source/cmake/WebKitMacros.cmake b/Source/cmake/WebKitMacros.cmake
index 8879ec75a..dd1625bf5 100644
--- a/Source/cmake/WebKitMacros.cmake
+++ b/Source/cmake/WebKitMacros.cmake
@@ -40,6 +40,18 @@ macro(ADD_PRECOMPILED_HEADER _header _cpp _source)
#FIXME: Add support for Xcode.
endmacro()
+# TODO: Unify usage of prefix headers and PCH with WebCore and WebKit2
+macro(ADD_PREFIX_HEADER _target _header)
+ if (COMPILER_IS_GCC_OR_CLANG)
+ get_target_property(OLD_COMPILE_FLAGS ${_target} COMPILE_FLAGS)
+ if (${OLD_COMPILE_FLAGS} STREQUAL "OLD_COMPILE_FLAGS-NOTFOUND")
+ set(OLD_COMPILE_FLAGS "")
+ endif ()
+ set_target_properties(${_target} PROPERTIES COMPILE_FLAGS "${OLD_COMPILE_FLAGS} -include ${_header}")
+ endif ()
+endmacro()
+
+
# Helper macro which wraps generate-bindings.pl script.
# _output_source is a list name which will contain generated sources.(eg. WebCore_SOURCES)
# _input_files are IDL files to generate.
@@ -307,7 +319,7 @@ endmacro()
macro(WEBKIT_CREATE_FORWARDING_HEADERS _framework)
# On Windows, we copy the entire contents of forwarding headers.
- if (NOT WIN32)
+ if (NOT MSVC)
set(_processing_directories 0)
set(_processing_files 0)
set(_target_directory "${DERIVED_SOURCES_DIR}/ForwardingHeaders/${_framework}")
diff --git a/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp
index b730df61c..e9c39f9b2 100755..100644
--- a/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp
+++ b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp
@@ -109,18 +109,18 @@ void NetworkAccessManager::sslErrorsEncountered(QNetworkReply* reply, const QLis
#if !defined(QT_NO_PRINTER) && HAVE(QTPRINTSUPPORT)
-class NullPrinter : public QPrinter {
+class NullPrinter final : public QPrinter {
public:
class NullPaintEngine : public QPaintEngine {
public:
- virtual bool begin(QPaintDevice*) { return true; }
- virtual bool end() { return true; }
- virtual QPaintEngine::Type type() const { return QPaintEngine::User; }
- virtual void drawPixmap(const QRectF& r, const QPixmap& pm, const QRectF& sr) { }
- virtual void updateState(const QPaintEngineState& state) { }
+ bool begin(QPaintDevice*) final { return true; }
+ bool end() final { return true; }
+ QPaintEngine::Type type() const final { return QPaintEngine::User; }
+ void drawPixmap(const QRectF& r, const QPixmap& pm, const QRectF& sr) final { }
+ void updateState(const QPaintEngineState& state) final { }
};
- virtual QPaintEngine* paintEngine() const { return const_cast<NullPaintEngine*>(&m_engine); }
+ QPaintEngine* paintEngine() const final { return const_cast<NullPaintEngine*>(&m_engine); }
NullPaintEngine m_engine;
};
@@ -155,6 +155,8 @@ WebPage::WebPage(QObject* parent, DumpRenderTree* drt)
connect(this, SIGNAL(featurePermissionRequested(QWebFrame*, QWebPage::Feature)), this, SLOT(requestPermission(QWebFrame*, QWebPage::Feature)));
connect(this, SIGNAL(featurePermissionRequestCanceled(QWebFrame*, QWebPage::Feature)), this, SLOT(cancelPermission(QWebFrame*, QWebPage::Feature)));
+
+ connect(this, &QWebPage::fullScreenRequested, this, &WebPage::requestFullScreen);
}
WebPage::~WebPage()
@@ -191,6 +193,7 @@ void WebPage::resetSettings()
settings()->resetAttribute(QWebSettings::CSSRegionsEnabled);
settings()->resetAttribute(QWebSettings::CSSGridLayoutEnabled);
settings()->resetAttribute(QWebSettings::AcceleratedCompositingEnabled);
+ settings()->resetAttribute(QWebSettings::FullScreenSupportEnabled);
m_drt->testRunner()->setCaretBrowsingEnabled(false);
m_drt->testRunner()->setAuthorAndUserStylesEnabled(true);
@@ -273,6 +276,11 @@ void WebPage::permissionSet(QWebPage::Feature feature)
}
}
+void WebPage::requestFullScreen(QWebFullScreenRequest request)
+{
+ request.accept();
+}
+
// FIXME (119591): Make this match other platforms better.
static QString urlSuitableForTestResult(const QString& url)
{
diff --git a/Tools/DumpRenderTree/qt/DumpRenderTreeQt.h b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.h
index be1559d33..880f9ca83 100644
--- a/Tools/DumpRenderTree/qt/DumpRenderTreeQt.h
+++ b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.h
@@ -67,7 +67,7 @@ class GCController;
class WebPage;
class NetworkAccessManager;
-class DumpRenderTree : public QObject {
+class DumpRenderTree final : public QObject {
Q_OBJECT
public:
@@ -173,7 +173,7 @@ private:
QString m_redirectErrorFileName;
};
-class NetworkAccessManager : public QNetworkAccessManager {
+class NetworkAccessManager final : public QNetworkAccessManager {
Q_OBJECT
public:
NetworkAccessManager(QObject* parent);
@@ -184,7 +184,7 @@ private Q_SLOTS:
#endif
};
-class WebPage : public QWebPage {
+class WebPage final : public QWebPage {
Q_OBJECT
public:
WebPage(QObject* parent, DumpRenderTree*);
@@ -192,30 +192,31 @@ public:
QWebInspector* webInspector();
void closeWebInspector();
- QWebPage *createWindow(QWebPage::WebWindowType);
+ QWebPage *createWindow(QWebPage::WebWindowType) final;
- void javaScriptAlert(QWebFrame *frame, const QString& message);
- void javaScriptConsoleMessage(const QString& message, int lineNumber, const QString& sourceID);
- bool javaScriptConfirm(QWebFrame *frame, const QString& msg);
- bool javaScriptPrompt(QWebFrame *frame, const QString& msg, const QString& defaultValue, QString* result);
+ void javaScriptAlert(QWebFrame*, const QString& message) final;
+ void javaScriptConsoleMessage(const QString& message, int lineNumber, const QString& sourceID) final;
+ bool javaScriptConfirm(QWebFrame*, const QString& msg) final;
+ bool javaScriptPrompt(QWebFrame*, const QString& msg, const QString& defaultValue, QString* result) final;
void resetSettings();
- virtual bool supportsExtension(QWebPage::Extension extension) const;
- virtual bool extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output);
+ bool supportsExtension(QWebPage::Extension) const final;
+ bool extension(Extension, const ExtensionOption*, ExtensionReturn*) final;
- QObject* createPlugin(const QString&, const QUrl&, const QStringList&, const QStringList&);
+ QObject* createPlugin(const QString&, const QUrl&, const QStringList&, const QStringList&) final;
void permissionSet(QWebPage::Feature feature);
- virtual bool shouldInterruptJavaScript() { return false; }
+ bool shouldInterruptJavaScript() final { return false; }
public Q_SLOTS:
- void requestPermission(QWebFrame* frame, QWebPage::Feature feature);
- void cancelPermission(QWebFrame* frame, QWebPage::Feature feature);
+ void requestPermission(QWebFrame*, QWebPage::Feature);
+ void cancelPermission(QWebFrame*, QWebPage::Feature);
+ void requestFullScreen(QWebFullScreenRequest);
protected:
- bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, NavigationType type);
+ bool acceptNavigationRequest(QWebFrame*, const QNetworkRequest&, NavigationType) final;
bool isTextOutputEnabled() { return m_drt->isTextOutputEnabled(); }
private Q_SLOTS:
@@ -227,7 +228,7 @@ private:
DumpRenderTree *m_drt;
};
-class WebViewGraphicsBased : public QGraphicsView {
+class WebViewGraphicsBased final : public QGraphicsView {
Q_OBJECT
public:
diff --git a/Tools/DumpRenderTree/qt/EventSenderQt.cpp b/Tools/DumpRenderTree/qt/EventSenderQt.cpp
index 352f1de98..666a2475e 100644
--- a/Tools/DumpRenderTree/qt/EventSenderQt.cpp
+++ b/Tools/DumpRenderTree/qt/EventSenderQt.cpp
@@ -291,7 +291,7 @@ void EventSender::keyDown(const QString& string, const QStringList& modifiers, u
code = string.unicode()->unicode();
//qDebug() << ">>>>>>>>> keyDown" << code << (char)code;
// map special keycodes used by the tests to something that works for Qt/X11
- if (code == '\r') {
+ if (code == '\r' || code == '\n') {
code = Qt::Key_Return;
} else if (code == '\t') {
code = Qt::Key_Tab;
diff --git a/Tools/DumpRenderTree/qt/EventSenderQt.h b/Tools/DumpRenderTree/qt/EventSenderQt.h
index 94fb1556f..087d475a7 100644
--- a/Tools/DumpRenderTree/qt/EventSenderQt.h
+++ b/Tools/DumpRenderTree/qt/EventSenderQt.h
@@ -50,11 +50,11 @@
#include <qwebframe.h>
-class EventSender : public QObject {
+class EventSender final : public QObject {
Q_OBJECT
public:
EventSender(QWebPage* parent);
- virtual bool eventFilter(QObject* watched, QEvent*);
+ bool eventFilter(QObject* watched, QEvent*) final;
void resetClickCount() { m_clickCount = 0; }
public Q_SLOTS:
@@ -93,7 +93,7 @@ public Q_SLOTS:
void beginDragWithFiles(const QStringList& files);
protected:
- void timerEvent(QTimerEvent*);
+ void timerEvent(QTimerEvent*) final;
private:
bool isGraphicsBased() const { return qobject_cast<WebViewGraphicsBased*>(m_page->view()); }
diff --git a/Tools/DumpRenderTree/qt/TestRunnerQt.h b/Tools/DumpRenderTree/qt/TestRunnerQt.h
index 8f2ef1f45..daf8dddba 100644
--- a/Tools/DumpRenderTree/qt/TestRunnerQt.h
+++ b/Tools/DumpRenderTree/qt/TestRunnerQt.h
@@ -51,7 +51,7 @@ class QWebFrame;
class DumpRenderTreeSupportQt;
class DumpRenderTree;
-class TestRunnerQt : public QObject {
+class TestRunnerQt final : public QObject {
Q_OBJECT
Q_PROPERTY(int webHistoryItemCount READ webHistoryItemCount)
Q_PROPERTY(bool globalFlag READ globalFlag WRITE setGlobalFlag)
@@ -72,7 +72,7 @@ public:
void setShouldTimeout(bool flag) { m_shouldTimeout = flag; }
protected:
- void timerEvent(QTimerEvent*);
+ void timerEvent(QTimerEvent*) final;
Q_SIGNALS:
void done();
diff --git a/Tools/DumpRenderTree/qt/WorkQueueItemQt.h b/Tools/DumpRenderTree/qt/WorkQueueItemQt.h
index f57abb0e2..22a6a1d66 100644
--- a/Tools/DumpRenderTree/qt/WorkQueueItemQt.h
+++ b/Tools/DumpRenderTree/qt/WorkQueueItemQt.h
@@ -34,7 +34,7 @@
#include <qwebframe.h>
#include <qwebpage.h>
-class LoadAlternateHTMLStringItem : public WorkQueueItem {
+class LoadAlternateHTMLStringItem final : public WorkQueueItem {
public:
LoadAlternateHTMLStringItem(const JSRetainPtr<JSStringRef>& content, const JSRetainPtr<JSStringRef>& baseURL, const JSRetainPtr<JSStringRef>& failingURL)
: m_content(content)
@@ -44,7 +44,7 @@ public:
}
private:
- virtual bool invoke() const;
+ bool invoke() const final;
JSRetainPtr<JSStringRef> m_content;
JSRetainPtr<JSStringRef> m_baseURL;
diff --git a/Tools/DumpRenderTree/qt/testplugin.h b/Tools/DumpRenderTree/qt/testplugin.h
index 3d8a28cf3..bda9f582c 100644
--- a/Tools/DumpRenderTree/qt/testplugin.h
+++ b/Tools/DumpRenderTree/qt/testplugin.h
@@ -28,18 +28,18 @@
#include <qwebpluginfactory.h>
-class TestPlugin : public QWebPluginFactory
+class TestPlugin final : public QWebPluginFactory
{
public:
explicit TestPlugin(QObject *parent = 0);
virtual ~TestPlugin();
- virtual QList<Plugin> plugins() const;
+ QList<Plugin> plugins() const final;
- virtual QObject *create(const QString &mimeType,
+ QObject *create(const QString &mimeType,
const QUrl &url,
const QStringList &argumentNames,
- const QStringList &argumentValues) const;
+ const QStringList &argumentValues) const final;
};
diff --git a/Tools/QtTestBrowser/cookiejar.h b/Tools/QtTestBrowser/cookiejar.h
index da62fb829..701cffc1f 100644
--- a/Tools/QtTestBrowser/cookiejar.h
+++ b/Tools/QtTestBrowser/cookiejar.h
@@ -33,14 +33,14 @@
#include <QNetworkCookieJar>
#include <QTimer>
-class TestBrowserCookieJar : public QNetworkCookieJar {
+class TestBrowserCookieJar final : public QNetworkCookieJar {
Q_OBJECT
public:
TestBrowserCookieJar(QObject* parent = 0);
virtual ~TestBrowserCookieJar();
- virtual bool setCookiesFromUrl(const QList<QNetworkCookie>&, const QUrl&);
+ bool setCookiesFromUrl(const QList<QNetworkCookie>&, const QUrl&) final;
void setDiskStorageEnabled(bool);
diff --git a/Tools/QtTestBrowser/fpstimer.h b/Tools/QtTestBrowser/fpstimer.h
index 256745aa8..833b3cc74 100644
--- a/Tools/QtTestBrowser/fpstimer.h
+++ b/Tools/QtTestBrowser/fpstimer.h
@@ -32,7 +32,7 @@
#include <QSet>
#include <QTime>
-class FpsTimer : public QObject {
+class FpsTimer final : public QObject {
Q_OBJECT
public:
@@ -44,7 +44,7 @@ public Q_SLOTS:
void stop();
protected Q_SLOTS:
- virtual void timerEvent(QTimerEvent*);
+ void timerEvent(QTimerEvent*) final;
private:
int m_timer;
diff --git a/Tools/QtTestBrowser/launcherwindow.cpp b/Tools/QtTestBrowser/launcherwindow.cpp
index 84a4c0873..537eccf64 100644
--- a/Tools/QtTestBrowser/launcherwindow.cpp
+++ b/Tools/QtTestBrowser/launcherwindow.cpp
@@ -381,6 +381,9 @@ void LauncherWindow::createChrome()
toolsMenu->addSeparator();
toolsMenu->addAction("Load URLs from file", this, SLOT(loadURLListFromFile()));
+ toolsMenu->addSeparator();
+ toolsMenu->addAction("Clear memory caches", this, SLOT(clearMemoryCaches()));
+
// GraphicsView sub menu.
QAction* toggleAcceleratedCompositing = graphicsViewMenu->addAction("Toggle Accelerated Compositing", this, SLOT(toggleAcceleratedCompositing(bool)));
toggleAcceleratedCompositing->setCheckable(true);
@@ -1110,6 +1113,12 @@ void LauncherWindow::fileDownloadFinished()
}
#endif
+void LauncherWindow::clearMemoryCaches()
+{
+ QWebSettings::clearMemoryCaches();
+ qDebug() << "Memory caches were cleared";
+}
+
void LauncherWindow::updateFPS(int fps)
{
QString fpsStatusText = QString("Current FPS: %1").arg(fps);
diff --git a/Tools/QtTestBrowser/launcherwindow.h b/Tools/QtTestBrowser/launcherwindow.h
index 9fd41a445..d4a3b832d 100644
--- a/Tools/QtTestBrowser/launcherwindow.h
+++ b/Tools/QtTestBrowser/launcherwindow.h
@@ -91,7 +91,7 @@ public:
bool startMaximized { false };
};
-class LauncherWindow : public MainWindow {
+class LauncherWindow final : public MainWindow {
Q_OBJECT
public:
@@ -100,7 +100,7 @@ public:
void sendTouchEvent();
- bool eventFilter(QObject*, QEvent*);
+ bool eventFilter(QObject*, QEvent*) final;
protected Q_SLOTS:
void loadStarted();
@@ -170,6 +170,8 @@ protected Q_SLOTS:
void fileDownloadFinished();
#endif
+ void clearMemoryCaches();
+
public Q_SLOTS:
LauncherWindow* newWindow();
LauncherWindow* cloneWindow();
diff --git a/Tools/QtTestBrowser/locationedit.h b/Tools/QtTestBrowser/locationedit.h
index 5750cba36..43b30e38d 100644
--- a/Tools/QtTestBrowser/locationedit.h
+++ b/Tools/QtTestBrowser/locationedit.h
@@ -36,7 +36,7 @@
#include <QStyleOptionFrame>
#include <QTimer>
-class LocationEdit : public QLineEdit {
+class LocationEdit final : public QLineEdit {
Q_OBJECT
public:
@@ -51,8 +51,8 @@ private Q_SLOTS:
void reset();
protected:
- virtual void paintEvent(QPaintEvent*);
- virtual void resizeEvent(QResizeEvent*);
+ void paintEvent(QPaintEvent*) final;
+ void resizeEvent(QResizeEvent*) final;
private:
void updateInternalGeometry();
diff --git a/Tools/QtTestBrowser/mainwindow.cpp b/Tools/QtTestBrowser/mainwindow.cpp
index 68217696b..d342147ac 100644
--- a/Tools/QtTestBrowser/mainwindow.cpp
+++ b/Tools/QtTestBrowser/mainwindow.cpp
@@ -42,6 +42,7 @@
#ifndef QT_NO_FILEDIALOG
#include <QFileDialog>
#endif
+#include <QMenuBar>
MainWindow::MainWindow()
: m_page(new WebPage(this))
@@ -118,6 +119,15 @@ void MainWindow::setPage(WebPage* page)
buildUI();
}
+void MainWindow::setToolBarsVisible(bool visible)
+{
+ if (menuBar())
+ menuBar()->setVisible(visible);
+
+ if (m_toolBar)
+ m_toolBar->setVisible(visible);
+}
+
WebPage* MainWindow::page() const
{
return m_page;
diff --git a/Tools/QtTestBrowser/mainwindow.h b/Tools/QtTestBrowser/mainwindow.h
index 70b3e5e1c..6e978576e 100644
--- a/Tools/QtTestBrowser/mainwindow.h
+++ b/Tools/QtTestBrowser/mainwindow.h
@@ -55,6 +55,8 @@ public:
WebPage* page() const;
void setPage(WebPage*);
+ void setToolBarsVisible(bool);
+
protected Q_SLOTS:
void setAddressUrl(const QString&);
void setAddressUrl(const QUrl&);
diff --git a/Tools/QtTestBrowser/webinspector.h b/Tools/QtTestBrowser/webinspector.h
index c75bbdc2f..72a3a3b48 100644
--- a/Tools/QtTestBrowser/webinspector.h
+++ b/Tools/QtTestBrowser/webinspector.h
@@ -30,7 +30,7 @@
#include "qwebinspector.h"
-class WebInspector : public QWebInspector {
+class WebInspector final : public QWebInspector {
Q_OBJECT
public:
@@ -40,12 +40,12 @@ Q_SIGNALS:
void visibleChanged(bool nowVisible);
protected:
- void showEvent(QShowEvent* event)
+ void showEvent(QShowEvent* event) final
{
QWebInspector::showEvent(event);
emit visibleChanged(true);
}
- void hideEvent(QHideEvent* event)
+ void hideEvent(QHideEvent* event) final
{
QWebInspector::hideEvent(event);
emit visibleChanged(false);
diff --git a/Tools/QtTestBrowser/webpage.cpp b/Tools/QtTestBrowser/webpage.cpp
index 1a3ae3c82..a0efed1d8 100644
--- a/Tools/QtTestBrowser/webpage.cpp
+++ b/Tools/QtTestBrowser/webpage.cpp
@@ -33,6 +33,7 @@
#include "webpage.h"
#include "launcherwindow.h"
+#include "mainwindow.h"
#include <QAction>
#include <QApplication>
@@ -47,13 +48,16 @@
#ifndef QT_NO_LINEEDIT
#include <QLineEdit>
#endif
+#include <QMessageBox>
#include <QProgressBar>
+#include <QWindow>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkProxy>
-WebPage::WebPage(QObject* parent)
+WebPage::WebPage(MainWindow* parent)
: QWebPage(parent)
+ , m_mainWindow(parent)
, m_userAgent()
, m_interruptingJavaScriptEnabled(false)
{
@@ -63,6 +67,7 @@ WebPage::WebPage(QObject* parent)
this, SLOT(authenticationRequired(QNetworkReply*, QAuthenticator*)));
connect(this, SIGNAL(featurePermissionRequested(QWebFrame*, QWebPage::Feature)), this, SLOT(requestPermission(QWebFrame*, QWebPage::Feature)));
connect(this, SIGNAL(featurePermissionRequestCanceled(QWebFrame*, QWebPage::Feature)), this, SLOT(featurePermissionRequestCanceled(QWebFrame*, QWebPage::Feature)));
+ connect(this, &QWebPage::fullScreenRequested, this, &WebPage::requestFullScreen);
}
void WebPage::applyProxy()
@@ -201,6 +206,23 @@ void WebPage::featurePermissionRequestCanceled(QWebFrame*, QWebPage::Feature)
{
}
+void WebPage::requestFullScreen(QWebFullScreenRequest request)
+{
+ if (request.toggleOn()) {
+ if (QMessageBox::question(view(), "Enter Full Screen Mode", "Do you want to enter full screen mode?", QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Cancel) == QMessageBox::Ok) {
+ request.accept();
+ m_mainWindow->setToolBarsVisible(false);
+ m_mainWindow->showFullScreen();
+ return;
+ }
+ } else {
+ request.accept();
+ m_mainWindow->setToolBarsVisible(true);
+ m_mainWindow->showNormal();
+ return;
+ }
+ request.reject();
+}
QWebPage* WebPage::createWindow(QWebPage::WebWindowType type)
{
LauncherWindow* mw = new LauncherWindow;
diff --git a/Tools/QtTestBrowser/webpage.h b/Tools/QtTestBrowser/webpage.h
index 1a6ef2e38..0238354aa 100644
--- a/Tools/QtTestBrowser/webpage.h
+++ b/Tools/QtTestBrowser/webpage.h
@@ -36,11 +36,13 @@
#include <qwebframe.h>
#include <qwebpage.h>
+class MainWindow;
+
class WebPage : public QWebPage {
Q_OBJECT
public:
- WebPage(QObject* parent = 0);
+ WebPage(MainWindow* parent);
QWebPage* createWindow(QWebPage::WebWindowType) override;
QObject* createPlugin(const QString&, const QUrl&, const QStringList&, const QStringList&) override;
@@ -62,9 +64,11 @@ public Q_SLOTS:
void authenticationRequired(QNetworkReply*, QAuthenticator*);
void requestPermission(QWebFrame*, QWebPage::Feature);
void featurePermissionRequestCanceled(QWebFrame*, QWebPage::Feature);
+ void requestFullScreen(QWebFullScreenRequest);
private:
void applyProxy();
+ MainWindow *m_mainWindow;
QString m_userAgent;
bool m_interruptingJavaScriptEnabled;
};
diff --git a/Tools/QtTestBrowser/webview.h b/Tools/QtTestBrowser/webview.h
index a45a972b7..de0b273de 100644
--- a/Tools/QtTestBrowser/webview.h
+++ b/Tools/QtTestBrowser/webview.h
@@ -45,31 +45,31 @@ QT_BEGIN_NAMESPACE
class QStateMachine;
QT_END_NAMESPACE
-class WebViewTraditional : public QWebView {
+class WebViewTraditional final : public QWebView {
Q_OBJECT
public:
WebViewTraditional(QWidget* parent) : QWebView(parent) {}
protected:
- virtual void contextMenuEvent(QContextMenuEvent*);
- virtual void mousePressEvent(QMouseEvent*);
+ void contextMenuEvent(QContextMenuEvent*) final;
+ void mousePressEvent(QMouseEvent*) final;
};
-class GraphicsWebView : public QGraphicsWebView {
+class GraphicsWebView final : public QGraphicsWebView {
Q_OBJECT
public:
GraphicsWebView(QGraphicsItem* parent = 0) : QGraphicsWebView(parent) {};
protected:
- virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent*);
- virtual void mousePressEvent(QGraphicsSceneMouseEvent*);
+ void contextMenuEvent(QGraphicsSceneContextMenuEvent*) final;
+ void mousePressEvent(QGraphicsSceneMouseEvent*) final;
};
-class WebViewGraphicsBased : public QGraphicsView {
+class WebViewGraphicsBased final : public QGraphicsView {
Q_OBJECT
Q_PROPERTY(qreal yRotation READ yRotation WRITE setYRotation)
@@ -83,8 +83,8 @@ public:
void setFrameRateMeasurementEnabled(bool);
bool frameRateMeasurementEnabled() const { return m_measureFps; }
- virtual void resizeEvent(QResizeEvent*);
- virtual void paintEvent(QPaintEvent*);
+ void resizeEvent(QResizeEvent*) final;
+ void paintEvent(QPaintEvent*) final;
void setResizesToContents(bool);
bool resizesToContents() const { return m_resizesToContents; }
diff --git a/Tools/Scripts/webkitperl/FeatureList.pm b/Tools/Scripts/webkitperl/FeatureList.pm
index 8301d9bc6..c3e03b3cc 100644
--- a/Tools/Scripts/webkitperl/FeatureList.pm
+++ b/Tools/Scripts/webkitperl/FeatureList.pm
@@ -269,7 +269,7 @@ my @features = (
define => "ENABLE_FTPDIR", default => !isQt(), value => \$ftpDirSupport },
{ option => "fullscreen-api", desc => "Toggle Fullscreen API support",
- define => "ENABLE_FULLSCREEN_API", default => (isAppleMacWebKit() || isEfl() || isGtk()), value => \$fullscreenAPISupport },
+ define => "ENABLE_FULLSCREEN_API", default => (isAppleMacWebKit() || isEfl() || isGtk() || isQt()), value => \$fullscreenAPISupport },
{ option => "gamepad", desc => "Toggle Gamepad support",
define => "ENABLE_GAMEPAD", default => 0, value => \$gamepadSupport },
diff --git a/Tools/qmake/mkspecs/features/functions.prf b/Tools/qmake/mkspecs/features/functions.prf
index daab9b8b5..2dcaa09ca 100644
--- a/Tools/qmake/mkspecs/features/functions.prf
+++ b/Tools/qmake/mkspecs/features/functions.prf
@@ -3,6 +3,11 @@ EOL = $$escape_expand(\\n)
WEBKIT_SUBDIR = $$relative_path($$_PRO_FILE_PWD_, $$ROOT_WEBKIT_DIR)
QTBASE_DIR = $$ROOT_WEBKIT_DIR/../qtbase
+defineReplace(staticLibPath) {
+ lib_basename = $${QMAKE_PREFIX_STATICLIB}$${1}$$qtPlatformTargetSuffix()
+ return($$ROOT_BUILD_DIR/lib/$${lib_basename}.$$QMAKE_EXTENSION_STATICLIB)
+}
+
defineTest(isQtMinimum) {
!equals(QT_MAJOR_VERSION, $$1): return(false)
count(ARGS, 1, greaterThan) {
@@ -59,6 +64,12 @@ defineTest(isPlatformSupported) {
}
win32 {
+ CONFIG(debug, debug|release):!contains(QMAKE_HOST.arch, x86_64) {
+ # debug_and_release is built as release, see Tools/qmake/projects/run_cmake.pro
+ !debug_and_release {
+ skipBuild("QtWebKit requires a 64-bit toolchain for debug build")
+ }
+ }
winrt {
skipBuild("WinRT is not supported.")
}
diff --git a/Tools/qmake/projects/generate_cmake_toolchain_file.pro b/Tools/qmake/projects/generate_cmake_toolchain_file.pro
index db26391b0..845372158 100644
--- a/Tools/qmake/projects/generate_cmake_toolchain_file.pro
+++ b/Tools/qmake/projects/generate_cmake_toolchain_file.pro
@@ -37,9 +37,6 @@ TOOLCHAIN_FILE_VARS += \
"CMAKE_C_COMPILER \"$$QMAKE_CC\"" \
"CMAKE_CXX_COMPILER \"$$QMAKE_CXX\""
-CONANBUILDINFO_PATH = $$ROOT_BUILD_DIR/conanbuildinfo.cmake
-exists($$CONANBUILDINFO_PATH): TOOLCHAIN_FILE_VARS += "CONANBUILDINFO_PATH $$CONANBUILDINFO_PATH"
-
for (var, TOOLCHAIN_FILE_VARS): TOOLCHAIN_FILE_CONTENTS += "set($$var)"
TOOLCHAIN_FILE = $$ROOT_BUILD_DIR/qmake_toolchain.cmake
diff --git a/Tools/qmake/projects/qtjpeg/qtjpeg.pro b/Tools/qmake/projects/qtjpeg/qtjpeg.pro
index 89d3e6113..a0c817a47 100644
--- a/Tools/qmake/projects/qtjpeg/qtjpeg.pro
+++ b/Tools/qmake/projects/qtjpeg/qtjpeg.pro
@@ -8,16 +8,7 @@ CONFIG += \
exceptions_off rtti_off warn_off \
installed
-# Poor man's qt_helper_lib
-TEMPLATE = lib
-CONFIG += staticlib
-CONFIG -= qt
-
-# In debug_and_release build we need only one copy of library, let it be release
-debug_and_release {
- CONFIG -= debug_and_release debug
- CONFIG += release
-}
+load(qt_helper_lib)
DESTDIR = $$ROOT_BUILD_DIR/lib
diff --git a/Tools/qmake/projects/qtpng/qtpng.pro b/Tools/qmake/projects/qtpng/qtpng.pro
index 88b6f9672..b6512f012 100644
--- a/Tools/qmake/projects/qtpng/qtpng.pro
+++ b/Tools/qmake/projects/qtpng/qtpng.pro
@@ -12,16 +12,7 @@ CONFIG += \
exceptions_off rtti_off warn_off \
installed
-# Poor man's qt_helper_lib
-TEMPLATE = lib
-CONFIG += staticlib
-CONFIG -= qt
-
-# In debug_and_release build we need only one copy of library, let it be release
-debug_and_release {
- CONFIG -= debug_and_release debug
- CONFIG += release
-}
+load(qt_helper_lib)
DESTDIR = $$ROOT_BUILD_DIR/lib
PNGDIR = $$QTBASE_DIR/src/3rdparty/libpng
diff --git a/Tools/qmake/projects/run_cmake.pro b/Tools/qmake/projects/run_cmake.pro
index 55e4ccc17..14c248ced 100644
--- a/Tools/qmake/projects/run_cmake.pro
+++ b/Tools/qmake/projects/run_cmake.pro
@@ -4,6 +4,14 @@ ROOT_QT_BUILD_DIR = $$ROOT_BUILD_DIR/..
TEMPLATE = aux
+win32:!contains(QMAKE_HOST.arch, x86_64) {
+ debug_and_release {
+ warning("Skipping debug build of QtWebKit because it requires a 64-bit toolchain")
+ CONFIG -= debug_and_release debug
+ CONFIG += release
+ }
+}
+
CONFIG(debug, debug|release) {
configuration = Debug
} else {
@@ -20,22 +28,25 @@ build_pass|!debug_and_release {
CMAKE_TOOLCHAIN_FILE=$$toolchain_file \
CMAKE_PREFIX_PATH=\"$$[QT_INSTALL_PREFIX];$$ROOT_QT_BUILD_DIR/qtbase;$$ROOT_QT_BUILD_DIR/qtlocation;$$ROOT_QT_BUILD_DIR/qtsensors\" \
CMAKE_INSTALL_PREFIX=\"$$[QT_INSTALL_PREFIX]\" \
- ENABLE_TEST_SUPPORT=OFF \
USE_LIBHYPHEN=OFF
+ static: CMAKE_CONFIG += USE_THIN_ARCHIVES=OFF
+
+ static_runtime: CMAKE_CONFIG += USE_STATIC_RUNTIME=ON
+
QT_FOR_CONFIG += gui-private
!qtConfig(system-jpeg):exists($$QTBASE_DIR) {
CMAKE_CONFIG += \
QT_BUNDLED_JPEG=1 \
JPEG_INCLUDE_DIR=$$QTBASE_DIR/src/3rdparty/libjpeg \
- JPEG_LIBRARIES=$$ROOT_BUILD_DIR/lib/$${QMAKE_PREFIX_STATICLIB}qtjpeg.$$QMAKE_EXTENSION_STATICLIB
+ JPEG_LIBRARIES=$$staticLibPath(qtjpeg)
}
!qtConfig(system-png):qtConfig(png):exists($$QTBASE_DIR) {
CMAKE_CONFIG += \
QT_BUNDLED_PNG=1 \
PNG_INCLUDE_DIRS=$$QTBASE_DIR/src/3rdparty/libpng \
- PNG_LIBRARIES=$$ROOT_BUILD_DIR/lib/$${QMAKE_PREFIX_STATICLIB}qtpng.$$QMAKE_EXTENSION_STATICLIB
+ PNG_LIBRARIES=$$staticLibPath(qtpng)
}
!qtConfig(system-zlib):exists($$QTBASE_DIR) {
@@ -44,6 +55,10 @@ build_pass|!debug_and_release {
ZLIB_INCLUDE_DIRS=$$QTBASE_DIR/src/3rdparty/zlib
}
+ exists($$ROOT_BUILD_DIR/conanbuildinfo.cmake):exists($$ROOT_BUILD_DIR/conanfile.txt) {
+ CMAKE_CONFIG += QT_CONAN_DIR=$$ROOT_BUILD_DIR
+ }
+
equals(QMAKE_HOST.os, Windows) {
if(equals(MAKEFILE_GENERATOR, MSVC.NET)|equals(MAKEFILE_GENERATOR, MSBUILD)) {
cmake_generator = "NMake Makefiles JOM"
diff --git a/Tools/qt/convert-prl-libs-to-cmake.pl b/Tools/qt/convert-prl-libs-to-cmake.pl
index b5b5289f8..1b304228c 100755
--- a/Tools/qt/convert-prl-libs-to-cmake.pl
+++ b/Tools/qt/convert-prl-libs-to-cmake.pl
@@ -27,12 +27,32 @@
use File::Basename;
use File::Spec;
+use Getopt::Long;
+use Text::ParseWords;
+
+use v5.10;
+
use strict;
use warnings;
-my ($qt_lib, $component_name, $out_name) = @ARGV;
+my $qt_lib;
+my $component_name;
+my $out_name;
+my $compiler;
+
+processArgs();
+
+sub processArgs {
+ GetOptions (
+ "lib=s" => \$qt_lib,
+ "component=s" => \$component_name,
+ "out=s" => \$out_name,
+ "compiler=s" => \$compiler
+ )
+}
-my ($qt_lib_base, $qt_lib_dir) = fileparse($qt_lib, qr{\..*});
+my $qt_lib_base = fileparse($qt_lib, qr{\..*});
+my $qt_lib_dir = dirname($qt_lib);
my $prl_name = File::Spec->join($qt_lib_dir, "$qt_lib_base.prl");
my $qmake_prl_libs;
@@ -53,7 +73,7 @@ unless($qmake_prl_libs) {
exit;
}
-my $prl_libs = squash_prl_libs (split /\s+/, $qmake_prl_libs);
+my $prl_libs = squash_prl_libs(shellwords($qmake_prl_libs));
my $template = <<'END_CMAKE';
get_target_property(_link_libs Qt5::${_component} INTERFACE_LINK_LIBRARIES)
@@ -83,13 +103,26 @@ close $out;
sub squash_prl_libs {
my @libs = @_;
my @result;
- for (my $i = 0; $i < $#libs; ++$i) {
+ for (my $i = 0; $i < scalar(@libs); ++$i) {
my $lib = $libs[$i];
if ($lib eq '-framework') {
$lib = "$libs[$i] $libs[$i + 1]";
++$i;
}
$lib =~ s"\$\$\[QT_INSTALL_LIBS\]"$qt_lib_dir"g;
+
+ if (lc($compiler) eq 'msvc') {
+ # convert backslashes
+ $lib =~ s"\\"/"g;
+
+ # MSVC doesn't support -L and -l arguments
+ if ($lib =~ /^-L(.*)$/) {
+ $lib = "-LIBPATH:$1"
+ } else {
+ $lib =~ s/^-l//;
+ }
+ }
+
push @result, $lib;
}
return join ';', @result;
diff --git a/Tools/qt/manifest.txt b/Tools/qt/manifest.txt
index 211fc29f4..624fe3ba1 100644
--- a/Tools/qt/manifest.txt
+++ b/Tools/qt/manifest.txt
@@ -71,6 +71,7 @@ file Source/WebCore/English.lproj/mediaControlsLocalizedStrings.js
# Windows-specific code
file Source/WTF/wtf/win/GDIObject.h
file Source/WebCore/platform/graphics/win/LocalWindowsContext.h
+file Source/WebCore/platform/graphics/win/MediaPlayerPrivateMediaFoundation.cpp
file Source/WebCore/platform/graphics/win/TransformationMatrixWin.cpp
file Source/WebCore/platform/win/BitmapInfo.cpp
file Source/WebCore/platform/win/BitmapInfo.h