<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[225045] trunk/Tools</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/225045">225045</a></dd>
<dt>Author</dt> <dd>carlosgc@webkit.org</dd>
<dt>Date</dt> <dd>2017-11-20 01:47:56 -0800 (Mon, 20 Nov 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>[WPE] Add env var WPE_USE_HEADLESS_VIEW_BACKEND
https://bugs.webkit.org/show_bug.cgi?id=173770

Reviewed by Michael Catanzaro.

Move HeadlessViewBackend implementation to a common place and build it as a private static library to be used by
WTR, GLib API tests and eventually C API tests too. WTR uses the HeadlessViewBackend unconditionally, but GLib
API tests use it only when WPE_USE_HEADLESS_VIEW_BACKEND environment variable is present and not "0".

* CMakeLists.txt: Include wpe/HeadlessViewBackend directory for developer builds.
* TestWebKitAPI/Tests/WebKitGLib/TestAutomationSession.cpp:
(testAutomationSessionRequestSession):
* TestWebKitAPI/Tests/WebKitGLib/TestCookieManager.cpp:
(testCookieManagerEphemeral):
* TestWebKitAPI/Tests/WebKitGLib/TestWebKitFaviconDatabase.cpp:
(testPrivateBrowsing):
* TestWebKitAPI/Tests/WebKitGLib/TestWebKitWebContext.cpp:
(testWebContextProxySettings):
* TestWebKitAPI/Tests/WebKitGLib/TestWebKitWebView.cpp:
(testWebViewWebContext):
(testWebViewEphemeral):
* TestWebKitAPI/glib/PlatformWPE.cmake:
* TestWebKitAPI/glib/WebKitGLib/TestMain.h:
(Test::createWebViewBackend):
(Test::createWebView):
* TestWebKitAPI/glib/WebKitGLib/WebViewTest.cpp:
(WebViewTest::initializeWebView):
* WebKitTestRunner/PlatformWPE.cmake:
* wpe/HeadlessViewBackend/CMakeLists.txt: Added.
* wpe/HeadlessViewBackend/HeadlessViewBackend.cpp: Renamed from Tools/WebKitTestRunner/wpe/HeadlessViewBackend.cpp.
(HeadlessViewBackend::HeadlessViewBackend):
* wpe/HeadlessViewBackend/HeadlessViewBackend.h: Renamed from Tools/WebKitTestRunner/wpe/HeadlessViewBackend.h.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkToolsCMakeListstxt">trunk/Tools/CMakeLists.txt</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKitGLibTestAutomationSessioncpp">trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestAutomationSession.cpp</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKitGLibTestCookieManagercpp">trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestCookieManager.cpp</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKitGLibTestWebKitFaviconDatabasecpp">trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestWebKitFaviconDatabase.cpp</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKitGLibTestWebKitWebContextcpp">trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestWebKitWebContext.cpp</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKitGLibTestWebKitWebViewcpp">trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestWebKitWebView.cpp</a></li>
<li><a href="#trunkToolsTestWebKitAPIglibPlatformWPEcmake">trunk/Tools/TestWebKitAPI/glib/PlatformWPE.cmake</a></li>
<li><a href="#trunkToolsTestWebKitAPIglibWebKitGLibTestMainh">trunk/Tools/TestWebKitAPI/glib/WebKitGLib/TestMain.h</a></li>
<li><a href="#trunkToolsTestWebKitAPIglibWebKitGLibWebViewTestcpp">trunk/Tools/TestWebKitAPI/glib/WebKitGLib/WebViewTest.cpp</a></li>
<li><a href="#trunkToolsWebKitTestRunnerPlatformWPEcmake">trunk/Tools/WebKitTestRunner/PlatformWPE.cmake</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li>trunk/Tools/wpe/HeadlessViewBackend/</li>
<li><a href="#trunkToolswpeHeadlessViewBackendCMakeListstxt">trunk/Tools/wpe/HeadlessViewBackend/CMakeLists.txt</a></li>
<li><a href="#trunkToolswpeHeadlessViewBackendHeadlessViewBackendcpp">trunk/Tools/wpe/HeadlessViewBackend/HeadlessViewBackend.cpp</a></li>
<li><a href="#trunkToolswpeHeadlessViewBackendHeadlessViewBackendh">trunk/Tools/wpe/HeadlessViewBackend/HeadlessViewBackend.h</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#trunkToolsWebKitTestRunnerwpeHeadlessViewBackendcpp">trunk/Tools/WebKitTestRunner/wpe/HeadlessViewBackend.cpp</a></li>
<li><a href="#trunkToolsWebKitTestRunnerwpeHeadlessViewBackendh">trunk/Tools/WebKitTestRunner/wpe/HeadlessViewBackend.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkToolsCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Tools/CMakeLists.txt (225044 => 225045)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/CMakeLists.txt       2017-11-20 08:16:26 UTC (rev 225044)
+++ trunk/Tools/CMakeLists.txt  2017-11-20 09:47:56 UTC (rev 225045)
</span><span class="lines">@@ -27,6 +27,7 @@
</span><span class="cx">     if (DEVELOPER_MODE)
</span><span class="cx">         add_subdirectory(ImageDiff)
</span><span class="cx">         add_subdirectory(WebKitTestRunner)
</span><ins>+        add_subdirectory(wpe/HeadlessViewBackend)
</ins><span class="cx">         if (ENABLE_API_TESTS)
</span><span class="cx">             add_subdirectory(TestWebKitAPI/glib)
</span><span class="cx">         endif ()
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (225044 => 225045)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog    2017-11-20 08:16:26 UTC (rev 225044)
+++ trunk/Tools/ChangeLog       2017-11-20 09:47:56 UTC (rev 225045)
</span><span class="lines">@@ -1,5 +1,40 @@
</span><span class="cx"> 2017-11-20  Carlos Garcia Campos  <cgarcia@igalia.com>
</span><span class="cx"> 
</span><ins>+        [WPE] Add env var WPE_USE_HEADLESS_VIEW_BACKEND
+        https://bugs.webkit.org/show_bug.cgi?id=173770
+
+        Reviewed by Michael Catanzaro.
+
+        Move HeadlessViewBackend implementation to a common place and build it as a private static library to be used by
+        WTR, GLib API tests and eventually C API tests too. WTR uses the HeadlessViewBackend unconditionally, but GLib
+        API tests use it only when WPE_USE_HEADLESS_VIEW_BACKEND environment variable is present and not "0".
+
+        * CMakeLists.txt: Include wpe/HeadlessViewBackend directory for developer builds.
+        * TestWebKitAPI/Tests/WebKitGLib/TestAutomationSession.cpp:
+        (testAutomationSessionRequestSession):
+        * TestWebKitAPI/Tests/WebKitGLib/TestCookieManager.cpp:
+        (testCookieManagerEphemeral):
+        * TestWebKitAPI/Tests/WebKitGLib/TestWebKitFaviconDatabase.cpp:
+        (testPrivateBrowsing):
+        * TestWebKitAPI/Tests/WebKitGLib/TestWebKitWebContext.cpp:
+        (testWebContextProxySettings):
+        * TestWebKitAPI/Tests/WebKitGLib/TestWebKitWebView.cpp:
+        (testWebViewWebContext):
+        (testWebViewEphemeral):
+        * TestWebKitAPI/glib/PlatformWPE.cmake:
+        * TestWebKitAPI/glib/WebKitGLib/TestMain.h:
+        (Test::createWebViewBackend):
+        (Test::createWebView):
+        * TestWebKitAPI/glib/WebKitGLib/WebViewTest.cpp:
+        (WebViewTest::initializeWebView):
+        * WebKitTestRunner/PlatformWPE.cmake:
+        * wpe/HeadlessViewBackend/CMakeLists.txt: Added.
+        * wpe/HeadlessViewBackend/HeadlessViewBackend.cpp: Renamed from Tools/WebKitTestRunner/wpe/HeadlessViewBackend.cpp.
+        (HeadlessViewBackend::HeadlessViewBackend):
+        * wpe/HeadlessViewBackend/HeadlessViewBackend.h: Renamed from Tools/WebKitTestRunner/wpe/HeadlessViewBackend.h.
+
+2017-11-20  Carlos Garcia Campos  <cgarcia@igalia.com>
+
</ins><span class="cx">         [WPE] webkit_web_view_new() should enable specifying wpe_view_backend object
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=178655
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKitGLibTestAutomationSessioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestAutomationSession.cpp (225044 => 225045)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestAutomationSession.cpp     2017-11-20 08:16:26 UTC (rev 225044)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestAutomationSession.cpp        2017-11-20 09:47:56 UTC (rev 225045)
</span><span class="lines">@@ -313,7 +313,13 @@
</span><span class="cx">     g_assert(!test->createTopLevelBrowsingContext(webView.get()));
</span><span class="cx"> 
</span><span class="cx">     // And will work with a proper web view.
</span><del>-    webView = Test::adoptView(g_object_new(WEBKIT_TYPE_WEB_VIEW, "web-context", test->m_webContext.get(), "is-controlled-by-automation", TRUE, nullptr));
</del><ins>+    webView = Test::adoptView(g_object_new(WEBKIT_TYPE_WEB_VIEW,
+#if PLATFORM(WPE)
+        "backend", Test::createWebViewBackend(),
+#endif
+        "web-context", test->m_webContext.get(),
+        "is-controlled-by-automation", TRUE,
+        nullptr));
</ins><span class="cx">     g_assert(webkit_web_view_is_controlled_by_automation(webView.get()));
</span><span class="cx">     g_assert(test->createTopLevelBrowsingContext(webView.get()));
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKitGLibTestCookieManagercpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestCookieManager.cpp (225044 => 225045)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestCookieManager.cpp 2017-11-20 08:16:26 UTC (rev 225044)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestCookieManager.cpp    2017-11-20 09:47:56 UTC (rev 225045)
</span><span class="lines">@@ -340,6 +340,9 @@
</span><span class="cx">     g_assert_cmpint(g_strv_length(domains), ==, 0);
</span><span class="cx"> 
</span><span class="cx">     auto webView = Test::adoptView(g_object_new(WEBKIT_TYPE_WEB_VIEW,
</span><ins>+#if PLATFORM(WPE)
+        "backend", Test::createWebViewBackend(),
+#endif
</ins><span class="cx">         "web-context", webkit_web_view_get_context(test->m_webView),
</span><span class="cx">         "is-ephemeral", TRUE,
</span><span class="cx">         nullptr));
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKitGLibTestWebKitFaviconDatabasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestWebKitFaviconDatabase.cpp (225044 => 225045)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestWebKitFaviconDatabase.cpp 2017-11-20 08:16:26 UTC (rev 225044)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestWebKitFaviconDatabase.cpp    2017-11-20 09:47:56 UTC (rev 225045)
</span><span class="lines">@@ -184,6 +184,9 @@
</span><span class="cx"> static void testPrivateBrowsing(FaviconDatabaseTest* test)
</span><span class="cx"> {
</span><span class="cx">     auto webView = Test::adoptView(g_object_new(WEBKIT_TYPE_WEB_VIEW,
</span><ins>+#if PLATFORM(WPE)
+        "backend", Test::createWebViewBackend(),
+#endif
</ins><span class="cx">         "web-context", test->m_webContext.get(),
</span><span class="cx">         "is-ephemeral", TRUE,
</span><span class="cx">         nullptr));
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKitGLibTestWebKitWebContextcpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestWebKitWebContext.cpp (225044 => 225045)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestWebKitWebContext.cpp      2017-11-20 08:16:26 UTC (rev 225044)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestWebKitWebContext.cpp 2017-11-20 09:47:56 UTC (rev 225045)
</span><span class="lines">@@ -708,6 +708,9 @@
</span><span class="cx"> 
</span><span class="cx">     // Proxy settings also affect ephemeral web views.
</span><span class="cx">     auto webView = Test::adoptView(g_object_new(WEBKIT_TYPE_WEB_VIEW,
</span><ins>+#if PLATFORM(WPE)
+        "backend", Test::createWebViewBackend(),
+#endif
</ins><span class="cx">         "web-context", test->m_webContext.get(),
</span><span class="cx">         "is-ephemeral", TRUE,
</span><span class="cx">         nullptr));
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKitGLibTestWebKitWebViewcpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestWebKitWebView.cpp (225044 => 225045)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestWebKitWebView.cpp 2017-11-20 08:16:26 UTC (rev 225044)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestWebKitWebView.cpp    2017-11-20 09:47:56 UTC (rev 225045)
</span><span class="lines">@@ -51,7 +51,11 @@
</span><span class="cx">     g_assert(webkit_web_context_get_default() != test->m_webContext.get());
</span><span class="cx"> 
</span><span class="cx">     // Check that a web view created with g_object_new has the default context.
</span><del>-    auto webView = Test::adoptView(g_object_new(WEBKIT_TYPE_WEB_VIEW, nullptr));
</del><ins>+    auto webView = Test::adoptView(g_object_new(WEBKIT_TYPE_WEB_VIEW,
+#if PLATFORM(WPE)
+        "backend", Test::createWebViewBackend(),
+#endif
+        nullptr));
</ins><span class="cx">     g_assert(webkit_web_view_get_context(webView.get()) == webkit_web_context_get_default());
</span><span class="cx"> 
</span><span class="cx">     // Check that a web view created with a related view has the related view context.
</span><span class="lines">@@ -60,7 +64,12 @@
</span><span class="cx"> 
</span><span class="cx">     // Check that a web context given as construct parameter is ignored if a related view is also provided.
</span><span class="cx">     webView = Test::adoptView(g_object_new(WEBKIT_TYPE_WEB_VIEW,
</span><del>-        "web-context", webkit_web_context_get_default(), "related-view", test->m_webView, nullptr));
</del><ins>+#if PLATFORM(WPE)
+        "backend", Test::createWebViewBackend(),
+#endif
+        "web-context", webkit_web_context_get_default(),
+        "related-view", test->m_webView,
+        nullptr));
</ins><span class="cx">     g_assert(webkit_web_view_get_context(webView.get()) == test->m_webContext.get());
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -182,6 +191,9 @@
</span><span class="cx"> 
</span><span class="cx">     // A WebView on a non ephemeral context can be ephemeral.
</span><span class="cx">     auto webView = Test::adoptView(g_object_new(WEBKIT_TYPE_WEB_VIEW,
</span><ins>+#if PLATFORM(WPE)
+        "backend", Test::createWebViewBackend(),
+#endif
</ins><span class="cx">         "web-context", webkit_web_view_get_context(test->m_webView),
</span><span class="cx">         "is-ephemeral", TRUE,
</span><span class="cx">         nullptr));
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPIglibPlatformWPEcmake"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/glib/PlatformWPE.cmake (225044 => 225045)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/glib/PlatformWPE.cmake 2017-11-20 08:16:26 UTC (rev 225044)
+++ trunk/Tools/TestWebKitAPI/glib/PlatformWPE.cmake    2017-11-20 09:47:56 UTC (rev 225045)
</span><span class="lines">@@ -9,6 +9,7 @@
</span><span class="cx">     ${DERIVED_SOURCES_WPE_API_DIR}
</span><span class="cx">     ${FORWARDING_HEADERS_WPE_DIR}
</span><span class="cx">     ${FORWARDING_HEADERS_WPE_EXTENSION_DIR}
</span><ins>+    ${TOOLS_DIR}/wpe/HeadlessViewBackend
</ins><span class="cx"> )
</span><span class="cx"> 
</span><span class="cx"> list(APPEND WebKitGLibAPITests_SYSTEM_INCLUDE_DIRECTORIES
</span><span class="lines">@@ -17,4 +18,5 @@
</span><span class="cx"> 
</span><span class="cx"> list(APPEND WebKitGLibAPITest_LIBRARIES
</span><span class="cx">     ${WPE_LIBRARIES}
</span><ins>+    WPEHeadlessViewBackend
</ins><span class="cx"> )
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPIglibWebKitGLibTestMainh"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/glib/WebKitGLib/TestMain.h (225044 => 225045)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/glib/WebKitGLib/TestMain.h     2017-11-20 08:16:26 UTC (rev 225044)
+++ trunk/Tools/TestWebKitAPI/glib/WebKitGLib/TestMain.h        2017-11-20 09:47:56 UTC (rev 225045)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> #if PLATFORM(GTK)
</span><span class="cx"> #include <webkit2/webkit2.h>
</span><span class="cx"> #elif PLATFORM(WPE)
</span><ins>+#include "HeadlessViewBackend.h"
</ins><span class="cx"> #include <wpe/webkit.h>
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="lines">@@ -143,12 +144,25 @@
</span><span class="cx">         webkit_web_context_set_web_extensions_initialization_user_data(m_webContext.get(), g_variant_new_uint32(++s_webExtensionID));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+#if PLATFORM(WPE)
+    static WebKitWebViewBackend* createWebViewBackend()
+    {
+        const char* useHeadlessViewBackend = g_getenv("WPE_USE_HEADLESS_VIEW_BACKEND");
+        if (!useHeadlessViewBackend || !strcmp(useHeadlessViewBackend, "0"))
+            return nullptr;
+        auto* headlessBackend = new HeadlessViewBackend;
+        return webkit_web_view_backend_new(headlessBackend->backend(), [](gpointer userData) {
+            delete static_cast<HeadlessViewBackend*>(userData);
+        }, headlessBackend);
+    }
+#endif
+
</ins><span class="cx">     static WebKitWebView* createWebView()
</span><span class="cx">     {
</span><span class="cx"> #if PLATFORM(GTK)
</span><span class="cx">         return WEBKIT_WEB_VIEW(webkit_web_view_new());
</span><span class="cx"> #elif PLATFORM(WPE)
</span><del>-        return webkit_web_view_new(nullptr);
</del><ins>+        return webkit_web_view_new(createWebViewBackend());
</ins><span class="cx"> #endif
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -157,7 +171,7 @@
</span><span class="cx"> #if PLATFORM(GTK)
</span><span class="cx">         return WEBKIT_WEB_VIEW(webkit_web_view_new_with_context(context));
</span><span class="cx"> #elif PLATFORM(WPE)
</span><del>-        return webkit_web_view_new_with_context(nullptr, context);
</del><ins>+        return webkit_web_view_new_with_context(createWebViewBackend(), context);
</ins><span class="cx"> #endif
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -166,7 +180,7 @@
</span><span class="cx"> #if PLATFORM(GTK)
</span><span class="cx">         return WEBKIT_WEB_VIEW(webkit_web_view_new_with_related_view(relatedView));
</span><span class="cx"> #elif PLATFORM(WPE)
</span><del>-        return webkit_web_view_new_with_related_view(nullptr, relatedView);
</del><ins>+        return webkit_web_view_new_with_related_view(createWebViewBackend(), relatedView);
</ins><span class="cx"> #endif
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -175,7 +189,7 @@
</span><span class="cx"> #if PLATFORM(GTK)
</span><span class="cx">         return WEBKIT_WEB_VIEW(webkit_web_view_new_with_user_content_manager(contentManager));
</span><span class="cx"> #elif PLATFORM(WPE)
</span><del>-        return webkit_web_view_new_with_user_content_manager(nullptr, contentManager);
</del><ins>+        return webkit_web_view_new_with_user_content_manager(createWebViewBackend(), contentManager);
</ins><span class="cx"> #endif
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -184,7 +198,7 @@
</span><span class="cx"> #if PLATFORM(GTK)
</span><span class="cx">         return WEBKIT_WEB_VIEW(webkit_web_view_new_with_settings(settings));
</span><span class="cx"> #elif PLATFORM(WPE)
</span><del>-        return webkit_web_view_new_with_settings(nullptr, settings);
</del><ins>+        return webkit_web_view_new_with_settings(createWebViewBackend(), settings);
</ins><span class="cx"> #endif
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPIglibWebKitGLibWebViewTestcpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/glib/WebKitGLib/WebViewTest.cpp (225044 => 225045)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/glib/WebKitGLib/WebViewTest.cpp        2017-11-20 08:16:26 UTC (rev 225044)
+++ trunk/Tools/TestWebKitAPI/glib/WebKitGLib/WebViewTest.cpp   2017-11-20 09:47:56 UTC (rev 225045)
</span><span class="lines">@@ -48,7 +48,13 @@
</span><span class="cx"> void WebViewTest::initializeWebView()
</span><span class="cx"> {
</span><span class="cx">     g_assert(!m_webView);
</span><del>-    m_webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, "web-context", m_webContext.get(), "user-content-manager", m_userContentManager.get(), nullptr));
</del><ins>+    m_webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW,
+#if PLATFORM(WPE)
+        "backend", Test::createWebViewBackend(),
+#endif
+        "web-context", m_webContext.get(),
+        "user-content-manager", m_userContentManager.get(),
+        nullptr));
</ins><span class="cx">     platformInitializeWebView();
</span><span class="cx">     assertObjectIsDeletedWhenTestFinishes(G_OBJECT(m_webView));
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunnerPlatformWPEcmake"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/PlatformWPE.cmake (225044 => 225045)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/PlatformWPE.cmake   2017-11-20 08:16:26 UTC (rev 225044)
+++ trunk/Tools/WebKitTestRunner/PlatformWPE.cmake      2017-11-20 09:47:56 UTC (rev 225045)
</span><span class="lines">@@ -1,5 +1,3 @@
</span><del>-find_package(LibGBM REQUIRED)
-find_package(WPEBackend-mesa REQUIRED)
</del><span class="cx"> find_package(Libxkbcommon 0.4.0 REQUIRED)
</span><span class="cx"> 
</span><span class="cx"> add_custom_target(WebKitTestRunner-forwarding-headers
</span><span class="lines">@@ -12,7 +10,6 @@
</span><span class="cx">     ${WEBKIT_TESTRUNNER_DIR}/cairo/TestInvocationCairo.cpp
</span><span class="cx"> 
</span><span class="cx">     ${WEBKIT_TESTRUNNER_DIR}/wpe/EventSenderProxyWPE.cpp
</span><del>-    ${WEBKIT_TESTRUNNER_DIR}/wpe/HeadlessViewBackend.cpp
</del><span class="cx">     ${WEBKIT_TESTRUNNER_DIR}/wpe/PlatformWebViewWPE.cpp
</span><span class="cx">     ${WEBKIT_TESTRUNNER_DIR}/wpe/TestControllerWPE.cpp
</span><span class="cx">     ${WEBKIT_TESTRUNNER_DIR}/wpe/main.cpp
</span><span class="lines">@@ -21,22 +18,20 @@
</span><span class="cx"> list(APPEND WebKitTestRunner_INCLUDE_DIRECTORIES
</span><span class="cx">     ${WEBKIT_TESTRUNNER_DIR}/InjectedBundle/wpe
</span><span class="cx">     ${FORWARDING_HEADERS_DIR}
</span><ins>+    ${TOOLS_DIR}/wpe/HeadlessViewBackend
</ins><span class="cx"> )
</span><span class="cx"> 
</span><span class="cx"> list(APPEND WebKitTestRunner_SYSTEM_INCLUDE_DIRECTORIES
</span><span class="cx">     ${CAIRO_INCLUDE_DIRS}
</span><span class="cx">     ${GLIB_INCLUDE_DIRS}
</span><del>-    ${LIBGBM_INCLUDE_DIRS}
</del><span class="cx">     ${LIBXKBCOMMON_INCLUDE_DIRS}
</span><del>-    ${WPE_MESA_INCLUDE_DIRS}
</del><span class="cx"> )
</span><span class="cx"> 
</span><span class="cx"> list(APPEND WebKitTestRunner_LIBRARIES
</span><span class="cx">     ${CAIRO_LIBRARIES}
</span><span class="cx">     ${GLIB_LIBRARIES}
</span><del>-    ${LIBGBM_LIBRARIES}
</del><span class="cx">     ${LIBXKBCOMMON_LIBRARIES}
</span><del>-    ${WPE_MESA_LIBRARIES}
</del><ins>+    WPEHeadlessViewBackend
</ins><span class="cx"> )
</span><span class="cx"> 
</span><span class="cx"> list(APPEND WebKitTestRunnerInjectedBundle_SOURCES
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunnerwpeHeadlessViewBackendcpp"></a>
<div class="delfile"><h4>Deleted: trunk/Tools/WebKitTestRunner/wpe/HeadlessViewBackend.cpp (225044 => 225045)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/wpe/HeadlessViewBackend.cpp 2017-11-20 08:16:26 UTC (rev 225044)
+++ trunk/Tools/WebKitTestRunner/wpe/HeadlessViewBackend.cpp    2017-11-20 09:47:56 UTC (rev 225045)
</span><span class="lines">@@ -1,258 +0,0 @@
</span><del>-/*
- * Copyright (C) 2016 Igalia S.L.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "HeadlessViewBackend.h"
-
-#include <cassert>
-#include <fcntl.h>
-#include <unistd.h>
-#include <wtf/glib/RunLoopSourcePriority.h>
-
-// Manually provide the EGL_CAST C++ definition in case eglplatform.h doesn't provide it.
-#ifndef EGL_CAST
-#define EGL_CAST(type, value) (static_cast<type>(value))
-#endif
-
-// FIXME: Deploy good practices and clean up GBM resources at process exit.
-static EGLDisplay getEGLDisplay()
-{
-    static EGLDisplay s_display = EGL_NO_DISPLAY;
-    if (s_display == EGL_NO_DISPLAY) {
-        int fd = open("/dev/dri/renderD128", O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK);
-        if (fd < 0)
-            return EGL_NO_DISPLAY;
-
-        struct gbm_device* device = gbm_create_device(fd);
-        if (!device)
-            return EGL_NO_DISPLAY;
-
-        EGLDisplay display = eglGetDisplay(device);
-        if (display == EGL_NO_DISPLAY)
-            return EGL_NO_DISPLAY;
-
-        if (!eglInitialize(display, nullptr, nullptr))
-            return EGL_NO_DISPLAY;
-
-        if (!eglBindAPI(EGL_OPENGL_ES_API))
-            return EGL_NO_DISPLAY;
-
-        s_display = display;
-    }
-
-    return s_display;
-}
-
-HeadlessViewBackend::HeadlessViewBackend()
-{
-    m_egl.display = getEGLDisplay();
-
-    static const EGLint configAttributes[13] = {
-        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
-        EGL_RED_SIZE, 1,
-        EGL_GREEN_SIZE, 1,
-        EGL_BLUE_SIZE, 1,
-        EGL_ALPHA_SIZE, 1,
-        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-        EGL_NONE
-    };
-
-    EGLint numConfigs;
-    EGLBoolean ret = eglChooseConfig(m_egl.display, configAttributes, &m_egl.config, 1, &numConfigs);
-    if (!ret || !numConfigs)
-        return;
-
-    static const EGLint contextAttributes[3] = {
-        EGL_CONTEXT_CLIENT_VERSION, 2,
-        EGL_NONE
-    };
-
-    m_egl.context = eglCreateContext(m_egl.display, m_egl.config, EGL_NO_CONTEXT, contextAttributes);
-    if (m_egl.context == EGL_NO_CONTEXT)
-        return;
-
-    if (!eglMakeCurrent(m_egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, m_egl.context))
-        return;
-
-    m_egl.createImage = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress("eglCreateImageKHR"));
-    m_egl.destroyImage = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress("eglDestroyImageKHR"));
-    m_egl.imageTargetTexture2DOES = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES"));
-
-    m_exportable = wpe_mesa_view_backend_exportable_dma_buf_create(&s_exportableClient, this);
-
-    m_updateSource = g_timeout_source_new(m_frameRate / 1000);
-    g_source_set_callback(m_updateSource,
-        [](gpointer data) -> gboolean {
-            auto& backend = *static_cast<HeadlessViewBackend*>(data);
-            backend.performUpdate();
-            return TRUE;
-        }, this, nullptr);
-    g_source_set_priority(m_updateSource, RunLoopSourcePriority::RunLoopDispatcher);
-    g_source_attach(m_updateSource, g_main_context_default());
-}
-
-HeadlessViewBackend::~HeadlessViewBackend()
-{
-    if (m_updateSource)
-        g_source_destroy(m_updateSource);
-
-    if (auto image = std::get<0>(m_pendingImage.second))
-        m_egl.destroyImage(m_egl.display, image);
-    if (auto image = std::get<0>(m_lockedImage.second))
-        m_egl.destroyImage(m_egl.display, image);
-
-    for (auto it : m_exportMap) {
-        int fd = it.second;
-        if (fd >= 0)
-            close(fd);
-    }
-
-    if (m_egl.context)
-        eglDestroyContext(m_egl.display, m_egl.context);
-
-    wpe_mesa_view_backend_exportable_dma_buf_destroy(m_exportable);
-}
-
-struct wpe_view_backend* HeadlessViewBackend::backend() const
-{
-    return wpe_mesa_view_backend_exportable_dma_buf_get_view_backend(m_exportable);
-}
-
-cairo_surface_t* HeadlessViewBackend::createSnapshot()
-{
-    performUpdate();
-
-    EGLImageKHR image = std::get<0>(m_lockedImage.second);
-    if (!image)
-        return nullptr;
-
-    uint32_t width = std::get<1>(m_lockedImage.second);
-    uint32_t height = std::get<2>(m_lockedImage.second);
-
-    uint8_t* buffer = new uint8_t[4 * width * height];
-    bool successfulSnapshot = false;
-
-    makeCurrent();
-
-    GLuint imageTexture;
-    glGenTextures(1, &imageTexture);
-    glBindTexture(GL_TEXTURE_2D, imageTexture);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, width, height, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, nullptr);
-
-    m_egl.imageTargetTexture2DOES(GL_TEXTURE_2D, image);
-    glBindTexture(GL_TEXTURE_2D, 0);
-
-    GLuint imageFramebuffer;
-    glGenFramebuffers(1, &imageFramebuffer);
-    glBindFramebuffer(GL_FRAMEBUFFER, imageFramebuffer);
-    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, imageTexture, 0);
-
-    glFlush();
-    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) {
-        glReadPixels(0, 0, width, height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, buffer);
-        successfulSnapshot = true;
-    }
-
-    glBindFramebuffer(GL_FRAMEBUFFER, 0);
-    glDeleteFramebuffers(1, &imageFramebuffer);
-    glDeleteTextures(1, &imageTexture);
-
-    if (!successfulSnapshot) {
-        delete[] buffer;
-        return nullptr;
-    }
-
-    cairo_surface_t* imageSurface = cairo_image_surface_create_for_data(buffer,
-        CAIRO_FORMAT_ARGB32, width, height, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width));
-    cairo_surface_mark_dirty(imageSurface);
-
-    static cairo_user_data_key_t bufferKey;
-    cairo_surface_set_user_data(imageSurface, &bufferKey, buffer,
-        [](void* data) {
-            auto* buffer = static_cast<uint8_t*>(data);
-            delete[] buffer;
-        });
-
-    return imageSurface;
-}
-
-bool HeadlessViewBackend::makeCurrent()
-{
-    return eglMakeCurrent(m_egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, m_egl.context);
-}
-
-void HeadlessViewBackend::performUpdate()
-{
-    if (!m_pendingImage.first)
-        return;
-
-    wpe_mesa_view_backend_exportable_dma_buf_dispatch_frame_complete(m_exportable);
-    if (m_lockedImage.first) {
-        wpe_mesa_view_backend_exportable_dma_buf_dispatch_release_buffer(m_exportable, m_lockedImage.first);
-        m_egl.destroyImage(m_egl.display, std::get<0>(m_lockedImage.second));
-    }
-
-    m_lockedImage = m_pendingImage;
-    m_pendingImage = std::pair<uint32_t, std::tuple<EGLImageKHR, uint32_t, uint32_t>> { };
-}
-
-struct wpe_mesa_view_backend_exportable_dma_buf_client HeadlessViewBackend::s_exportableClient = {
-    // export_dma_buf
-    [](void* data, struct wpe_mesa_view_backend_exportable_dma_buf_data* imageData)
-    {
-        auto& backend = *static_cast<HeadlessViewBackend*>(data);
-
-        auto it = backend.m_exportMap.end();
-        if (imageData->fd >= 0) {
-            assert(backend.m_exportMap.find(imageData->handle) == backend.m_exportMap.end());
-
-            it = backend.m_exportMap.insert({ imageData->handle, imageData->fd }).first;
-        } else {
-            assert(backend.m_exportMap.find(imageData->handle) != backend.m_exportMap.end());
-            it = backend.m_exportMap.find(imageData->handle);
-        }
-
-        assert(it != backend.m_exportMap.end());
-        int32_t fd = it->second;
-
-        backend.makeCurrent();
-
-        EGLint attributes[] = {
-            EGL_WIDTH, static_cast<EGLint>(imageData->width),
-            EGL_HEIGHT, static_cast<EGLint>(imageData->height),
-            EGL_LINUX_DRM_FOURCC_EXT, static_cast<EGLint>(imageData->format),
-            EGL_DMA_BUF_PLANE0_FD_EXT, fd,
-            EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
-            EGL_DMA_BUF_PLANE0_PITCH_EXT, static_cast<EGLint>(imageData->stride),
-            EGL_NONE,
-        };
-        EGLImageKHR image = backend.m_egl.createImage(backend.m_egl.display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, attributes);
-        backend.m_pendingImage = { imageData->handle, std::make_tuple(image, imageData->width, imageData->height) };
-    },
-};
</del></span></pre></div>
<a id="trunkToolsWebKitTestRunnerwpeHeadlessViewBackendh"></a>
<div class="delfile"><h4>Deleted: trunk/Tools/WebKitTestRunner/wpe/HeadlessViewBackend.h (225044 => 225045)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/wpe/HeadlessViewBackend.h   2017-11-20 08:16:26 UTC (rev 225044)
+++ trunk/Tools/WebKitTestRunner/wpe/HeadlessViewBackend.h      2017-11-20 09:47:56 UTC (rev 225045)
</span><span class="lines">@@ -1,70 +0,0 @@
</span><del>-/*
- * Copyright (C) 2016 Igalia S.L.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-// This include order is necessary to enforce the GBM EGL platform.
-#include <gbm.h>
-#include <epoxy/egl.h>
-
-#include <cairo.h>
-#include <glib.h>
-#include <unordered_map>
-#include <wpe-mesa/view-backend-exportable-dma-buf.h>
-
-class HeadlessViewBackend {
-public:
-    HeadlessViewBackend();
-    ~HeadlessViewBackend();
-
-    struct wpe_view_backend* backend() const;
-
-    cairo_surface_t* createSnapshot();
-
-private:
-    bool makeCurrent();
-    void performUpdate();
-
-    static struct wpe_mesa_view_backend_exportable_dma_buf_client s_exportableClient;
-
-    struct {
-        EGLDisplay display;
-        EGLConfig config;
-        EGLContext context;
-
-        PFNEGLCREATEIMAGEKHRPROC createImage;
-        PFNEGLDESTROYIMAGEKHRPROC destroyImage;
-        PFNGLEGLIMAGETARGETTEXTURE2DOESPROC imageTargetTexture2DOES;
-    } m_egl;
-
-    struct wpe_mesa_view_backend_exportable_dma_buf* m_exportable;
-
-    std::unordered_map<uint32_t, int32_t> m_exportMap;
-    std::pair<uint32_t, std::tuple<EGLImageKHR, uint32_t, uint32_t>> m_pendingImage { };
-    std::pair<uint32_t, std::tuple<EGLImageKHR, uint32_t, uint32_t>> m_lockedImage { };
-
-    GSource* m_updateSource;
-    gint64 m_frameRate { G_USEC_PER_SEC / 60 };
-};
</del></span></pre></div>
<a id="trunkToolswpeHeadlessViewBackendCMakeListstxt"></a>
<div class="addfile"><h4>Added: trunk/Tools/wpe/HeadlessViewBackend/CMakeLists.txt (0 => 225045)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/wpe/HeadlessViewBackend/CMakeLists.txt                               (rev 0)
+++ trunk/Tools/wpe/HeadlessViewBackend/CMakeLists.txt  2017-11-20 09:47:56 UTC (rev 225045)
</span><span class="lines">@@ -0,0 +1,24 @@
</span><ins>+find_package(LibGBM REQUIRED)
+find_package(WPEBackend-mesa REQUIRED)
+
+set(WPEHeadlessViewBackend_SOURCES
+    ${TOOLS_DIR}/wpe/HeadlessViewBackend/HeadlessViewBackend.cpp
+)
+
+set(WPEHeadlessViewBackend_SYSTEM_INCLUDE_DIRECTORIES
+    ${CAIRO_INCLUDE_DIRS}
+    ${GLIB_INCLUDE_DIRS}
+    ${LIBGBM_INCLUDE_DIRS}
+    ${WPE_MESA_INCLUDE_DIRS}
+)
+
+set(WPEHeadlessViewBackend_LIBRARIES
+    ${CAIRO_LIBRARIES}
+    ${GLIB_LIBRARIES}
+    ${LIBGBM_LIBRARIES}
+    ${WPE_MESA_LIBRARIES}
+)
+
+add_library(WPEHeadlessViewBackend ${WPEHeadlessViewBackend_SOURCES})
+include_directories(SYSTEM ${WPEHeadlessViewBackend_SYSTEM_INCLUDE_DIRECTORIES})
+target_link_libraries(WPEHeadlessViewBackend ${WPEHeadlessViewBackend_LIBRARIES})
</ins></span></pre></div>
<a id="trunkToolswpeHeadlessViewBackendHeadlessViewBackendcppfromrev225044trunkToolsWebKitTestRunnerwpeHeadlessViewBackendcpp"></a>
<div class="copfile"><h4>Copied: trunk/Tools/wpe/HeadlessViewBackend/HeadlessViewBackend.cpp (from rev 225044, trunk/Tools/WebKitTestRunner/wpe/HeadlessViewBackend.cpp) (0 => 225045)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/wpe/HeadlessViewBackend/HeadlessViewBackend.cpp                              (rev 0)
+++ trunk/Tools/wpe/HeadlessViewBackend/HeadlessViewBackend.cpp 2017-11-20 09:47:56 UTC (rev 225045)
</span><span class="lines">@@ -0,0 +1,259 @@
</span><ins>+/*
+ * Copyright (C) 2016 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "HeadlessViewBackend.h"
+
+#include <cassert>
+#include <fcntl.h>
+#include <unistd.h>
+
+// Manually provide the EGL_CAST C++ definition in case eglplatform.h doesn't provide it.
+#ifndef EGL_CAST
+#define EGL_CAST(type, value) (static_cast<type>(value))
+#endif
+
+// Keep this in sync with wtf/glib/RunLoopSourcePriority.h.
+static int kRunLoopSourcePriorityDispatcher = -70;
+
+// FIXME: Deploy good practices and clean up GBM resources at process exit.
+static EGLDisplay getEGLDisplay()
+{
+    static EGLDisplay s_display = EGL_NO_DISPLAY;
+    if (s_display == EGL_NO_DISPLAY) {
+        int fd = open("/dev/dri/renderD128", O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK);
+        if (fd < 0)
+            return EGL_NO_DISPLAY;
+
+        struct gbm_device* device = gbm_create_device(fd);
+        if (!device)
+            return EGL_NO_DISPLAY;
+
+        EGLDisplay display = eglGetDisplay(device);
+        if (display == EGL_NO_DISPLAY)
+            return EGL_NO_DISPLAY;
+
+        if (!eglInitialize(display, nullptr, nullptr))
+            return EGL_NO_DISPLAY;
+
+        if (!eglBindAPI(EGL_OPENGL_ES_API))
+            return EGL_NO_DISPLAY;
+
+        s_display = display;
+    }
+
+    return s_display;
+}
+
+HeadlessViewBackend::HeadlessViewBackend()
+{
+    m_egl.display = getEGLDisplay();
+
+    static const EGLint configAttributes[13] = {
+        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+        EGL_RED_SIZE, 1,
+        EGL_GREEN_SIZE, 1,
+        EGL_BLUE_SIZE, 1,
+        EGL_ALPHA_SIZE, 1,
+        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+        EGL_NONE
+    };
+
+    EGLint numConfigs;
+    EGLBoolean ret = eglChooseConfig(m_egl.display, configAttributes, &m_egl.config, 1, &numConfigs);
+    if (!ret || !numConfigs)
+        return;
+
+    static const EGLint contextAttributes[3] = {
+        EGL_CONTEXT_CLIENT_VERSION, 2,
+        EGL_NONE
+    };
+
+    m_egl.context = eglCreateContext(m_egl.display, m_egl.config, EGL_NO_CONTEXT, contextAttributes);
+    if (m_egl.context == EGL_NO_CONTEXT)
+        return;
+
+    if (!eglMakeCurrent(m_egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, m_egl.context))
+        return;
+
+    m_egl.createImage = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress("eglCreateImageKHR"));
+    m_egl.destroyImage = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress("eglDestroyImageKHR"));
+    m_egl.imageTargetTexture2DOES = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES"));
+
+    m_exportable = wpe_mesa_view_backend_exportable_dma_buf_create(&s_exportableClient, this);
+
+    m_updateSource = g_timeout_source_new(m_frameRate / 1000);
+    g_source_set_callback(m_updateSource,
+        [](gpointer data) -> gboolean {
+            auto& backend = *static_cast<HeadlessViewBackend*>(data);
+            backend.performUpdate();
+            return TRUE;
+        }, this, nullptr);
+    g_source_set_priority(m_updateSource, kRunLoopSourcePriorityDispatcher);
+    g_source_attach(m_updateSource, g_main_context_default());
+}
+
+HeadlessViewBackend::~HeadlessViewBackend()
+{
+    if (m_updateSource)
+        g_source_destroy(m_updateSource);
+
+    if (auto image = std::get<0>(m_pendingImage.second))
+        m_egl.destroyImage(m_egl.display, image);
+    if (auto image = std::get<0>(m_lockedImage.second))
+        m_egl.destroyImage(m_egl.display, image);
+
+    for (auto it : m_exportMap) {
+        int fd = it.second;
+        if (fd >= 0)
+            close(fd);
+    }
+
+    if (m_egl.context)
+        eglDestroyContext(m_egl.display, m_egl.context);
+
+    wpe_mesa_view_backend_exportable_dma_buf_destroy(m_exportable);
+}
+
+struct wpe_view_backend* HeadlessViewBackend::backend() const
+{
+    return wpe_mesa_view_backend_exportable_dma_buf_get_view_backend(m_exportable);
+}
+
+cairo_surface_t* HeadlessViewBackend::createSnapshot()
+{
+    performUpdate();
+
+    EGLImageKHR image = std::get<0>(m_lockedImage.second);
+    if (!image)
+        return nullptr;
+
+    uint32_t width = std::get<1>(m_lockedImage.second);
+    uint32_t height = std::get<2>(m_lockedImage.second);
+
+    uint8_t* buffer = new uint8_t[4 * width * height];
+    bool successfulSnapshot = false;
+
+    makeCurrent();
+
+    GLuint imageTexture;
+    glGenTextures(1, &imageTexture);
+    glBindTexture(GL_TEXTURE_2D, imageTexture);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, width, height, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, nullptr);
+
+    m_egl.imageTargetTexture2DOES(GL_TEXTURE_2D, image);
+    glBindTexture(GL_TEXTURE_2D, 0);
+
+    GLuint imageFramebuffer;
+    glGenFramebuffers(1, &imageFramebuffer);
+    glBindFramebuffer(GL_FRAMEBUFFER, imageFramebuffer);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, imageTexture, 0);
+
+    glFlush();
+    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) {
+        glReadPixels(0, 0, width, height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, buffer);
+        successfulSnapshot = true;
+    }
+
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+    glDeleteFramebuffers(1, &imageFramebuffer);
+    glDeleteTextures(1, &imageTexture);
+
+    if (!successfulSnapshot) {
+        delete[] buffer;
+        return nullptr;
+    }
+
+    cairo_surface_t* imageSurface = cairo_image_surface_create_for_data(buffer,
+        CAIRO_FORMAT_ARGB32, width, height, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width));
+    cairo_surface_mark_dirty(imageSurface);
+
+    static cairo_user_data_key_t bufferKey;
+    cairo_surface_set_user_data(imageSurface, &bufferKey, buffer,
+        [](void* data) {
+            auto* buffer = static_cast<uint8_t*>(data);
+            delete[] buffer;
+        });
+
+    return imageSurface;
+}
+
+bool HeadlessViewBackend::makeCurrent()
+{
+    return eglMakeCurrent(m_egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, m_egl.context);
+}
+
+void HeadlessViewBackend::performUpdate()
+{
+    if (!m_pendingImage.first)
+        return;
+
+    wpe_mesa_view_backend_exportable_dma_buf_dispatch_frame_complete(m_exportable);
+    if (m_lockedImage.first) {
+        wpe_mesa_view_backend_exportable_dma_buf_dispatch_release_buffer(m_exportable, m_lockedImage.first);
+        m_egl.destroyImage(m_egl.display, std::get<0>(m_lockedImage.second));
+    }
+
+    m_lockedImage = m_pendingImage;
+    m_pendingImage = std::pair<uint32_t, std::tuple<EGLImageKHR, uint32_t, uint32_t>> { };
+}
+
+struct wpe_mesa_view_backend_exportable_dma_buf_client HeadlessViewBackend::s_exportableClient = {
+    // export_dma_buf
+    [](void* data, struct wpe_mesa_view_backend_exportable_dma_buf_data* imageData)
+    {
+        auto& backend = *static_cast<HeadlessViewBackend*>(data);
+
+        auto it = backend.m_exportMap.end();
+        if (imageData->fd >= 0) {
+            assert(backend.m_exportMap.find(imageData->handle) == backend.m_exportMap.end());
+
+            it = backend.m_exportMap.insert({ imageData->handle, imageData->fd }).first;
+        } else {
+            assert(backend.m_exportMap.find(imageData->handle) != backend.m_exportMap.end());
+            it = backend.m_exportMap.find(imageData->handle);
+        }
+
+        assert(it != backend.m_exportMap.end());
+        int32_t fd = it->second;
+
+        backend.makeCurrent();
+
+        EGLint attributes[] = {
+            EGL_WIDTH, static_cast<EGLint>(imageData->width),
+            EGL_HEIGHT, static_cast<EGLint>(imageData->height),
+            EGL_LINUX_DRM_FOURCC_EXT, static_cast<EGLint>(imageData->format),
+            EGL_DMA_BUF_PLANE0_FD_EXT, fd,
+            EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
+            EGL_DMA_BUF_PLANE0_PITCH_EXT, static_cast<EGLint>(imageData->stride),
+            EGL_NONE,
+        };
+        EGLImageKHR image = backend.m_egl.createImage(backend.m_egl.display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, attributes);
+        backend.m_pendingImage = { imageData->handle, std::make_tuple(image, imageData->width, imageData->height) };
+    },
+};
</ins></span></pre></div>
<a id="trunkToolswpeHeadlessViewBackendHeadlessViewBackendhfromrev225044trunkToolsWebKitTestRunnerwpeHeadlessViewBackendh"></a>
<div class="copfile"><h4>Copied: trunk/Tools/wpe/HeadlessViewBackend/HeadlessViewBackend.h (from rev 225044, trunk/Tools/WebKitTestRunner/wpe/HeadlessViewBackend.h) (0 => 225045)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/wpe/HeadlessViewBackend/HeadlessViewBackend.h                                (rev 0)
+++ trunk/Tools/wpe/HeadlessViewBackend/HeadlessViewBackend.h   2017-11-20 09:47:56 UTC (rev 225045)
</span><span class="lines">@@ -0,0 +1,70 @@
</span><ins>+/*
+ * Copyright (C) 2016 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+// This include order is necessary to enforce the GBM EGL platform.
+#include <gbm.h>
+#include <epoxy/egl.h>
+
+#include <cairo.h>
+#include <glib.h>
+#include <unordered_map>
+#include <wpe-mesa/view-backend-exportable-dma-buf.h>
+
+class HeadlessViewBackend {
+public:
+    HeadlessViewBackend();
+    ~HeadlessViewBackend();
+
+    struct wpe_view_backend* backend() const;
+
+    cairo_surface_t* createSnapshot();
+
+private:
+    bool makeCurrent();
+    void performUpdate();
+
+    static struct wpe_mesa_view_backend_exportable_dma_buf_client s_exportableClient;
+
+    struct {
+        EGLDisplay display;
+        EGLConfig config;
+        EGLContext context;
+
+        PFNEGLCREATEIMAGEKHRPROC createImage;
+        PFNEGLDESTROYIMAGEKHRPROC destroyImage;
+        PFNGLEGLIMAGETARGETTEXTURE2DOESPROC imageTargetTexture2DOES;
+    } m_egl;
+
+    struct wpe_mesa_view_backend_exportable_dma_buf* m_exportable;
+
+    std::unordered_map<uint32_t, int32_t> m_exportMap;
+    std::pair<uint32_t, std::tuple<EGLImageKHR, uint32_t, uint32_t>> m_pendingImage { };
+    std::pair<uint32_t, std::tuple<EGLImageKHR, uint32_t, uint32_t>> m_lockedImage { };
+
+    GSource* m_updateSource;
+    gint64 m_frameRate { G_USEC_PER_SEC / 60 };
+};
</ins></span></pre>
</div>
</div>

</body>
</html>