blob: 24e55fc76483521cb3b33f8be92dccf0d675d9ad [file] [log] [blame]
/*
* Copyright (C) 2019 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2,1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "WebKitProtocolHandler.h"
#include "WebKitError.h"
#include "WebKitVersion.h"
#include "WebKitWebView.h"
#include <WebCore/FloatRect.h>
#include <WebCore/GLContext.h>
#include <WebCore/IntRect.h>
#include <WebCore/PlatformDisplay.h>
#include <WebCore/PlatformScreen.h>
#include <cairo.h>
#include <gio/gio.h>
#include <wtf/URL.h>
#include <wtf/glib/GRefPtr.h>
#include <wtf/glib/GUniquePtr.h>
#if OS(UNIX)
#include <sys/utsname.h>
#endif
#if PLATFORM(GTK)
#include <gtk/gtk.h>
#if PLATFORM(WAYLAND) && USE(WPE_RENDERER)
#include <wpe/fdo.h>
#endif
#endif
#if PLATFORM(X11)
#include <WebCore/PlatformDisplayX11.h>
#endif
#if USE(LIBEPOXY)
#include <epoxy/gl.h>
#endif
#if USE(EGL)
#if USE(LIBEPOXY)
#include <epoxy/egl.h>
#else
#include <EGL/egl.h>
#endif
#endif
#if USE(GLX)
#include <GL/glx.h>
#include <WebCore/OpenGLShims.h>
#endif
#if USE(GSTREAMER)
#include <gst/gst.h>
#endif
namespace WebKit {
using namespace WebCore;
WebKitProtocolHandler::WebKitProtocolHandler(WebKitWebContext* context)
: m_context(context)
{
webkit_web_context_register_uri_scheme(context, "webkit", [](WebKitURISchemeRequest* request, gpointer userData) {
static_cast<WebKitProtocolHandler*>(userData)->handleRequest(request);
}, this, nullptr);
auto* manager = webkit_web_context_get_security_manager(context);
webkit_security_manager_register_uri_scheme_as_display_isolated(manager, "webkit");
webkit_security_manager_register_uri_scheme_as_local(manager, "webkit");
}
void WebKitProtocolHandler::handleRequest(WebKitURISchemeRequest* request)
{
URL requestURL = URL({ }, webkit_uri_scheme_request_get_uri(request));
if (requestURL.host() == "gpu") {
handleGPU(request);
return;
}
GUniquePtr<GError> error(g_error_new_literal(WEBKIT_POLICY_ERROR, WEBKIT_POLICY_ERROR_CANNOT_SHOW_URI, "Not found"));
webkit_uri_scheme_request_finish_error(request, error.get());
}
static inline const char* webkitPortName()
{
#if PLATFORM(GTK)
return "WebKitGTK";
#elif PLATFORM(WPE)
return "WPE WebKit";
#endif
RELEASE_ASSERT_NOT_REACHED();
}
static const char* hardwareAccelerationPolicy(WebKitURISchemeRequest* request)
{
#if PLATFORM(WPE)
return "always";
#elif PLATFORM(GTK)
auto* webView = webkit_uri_scheme_request_get_web_view(request);
ASSERT(webView);
switch (webkit_settings_get_hardware_acceleration_policy(webkit_web_view_get_settings(webView))) {
case WEBKIT_HARDWARE_ACCELERATION_POLICY_NEVER:
return "never";
case WEBKIT_HARDWARE_ACCELERATION_POLICY_ALWAYS:
return "always";
case WEBKIT_HARDWARE_ACCELERATION_POLICY_ON_DEMAND:
return "on demand";
}
#endif
RELEASE_ASSERT_NOT_REACHED();
}
static bool webGLEnabled(WebKitURISchemeRequest* request)
{
auto* webView = webkit_uri_scheme_request_get_web_view(request);
ASSERT(webView);
return webkit_settings_get_enable_webgl(webkit_web_view_get_settings(webView));
}
static const char* openGLAPI()
{
#if USE(LIBEPOXY)
if (epoxy_is_desktop_gl())
return "OpenGL (libepoxy)";
return "OpenGL ES 2 (libepoxy)";
#else
#if USE(GLX)
if (PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::X11)
return "OpenGL";
#endif
#if USE(EGL)
#if USE(OPENGL_ES)
return "OpenGL ES 2";
#else
return "OpenGL";
#endif
#endif
#endif
RELEASE_ASSERT_NOT_REACHED();
}
static const char* nativeInterface()
{
#if PLATFORM(GTK)
#if USE(GLX)
if (PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::X11)
return "GLX";
#endif
#endif
#if USE(EGL)
return "EGL";
#endif
RELEASE_ASSERT_NOT_REACHED();
}
void WebKitProtocolHandler::handleGPU(WebKitURISchemeRequest* request)
{
GString* html = g_string_new(
"<html><head><title>GPU information</title>"
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />"
"<style>"
" h1 { color: #babdb6; text-shadow: 0 1px 0 white; margin-bottom: 0; }"
" html { font-family: -webkit-system-font; font-size: 11pt; color: #2e3436; padding: 20px 20px 0 20px; background-color: #f6f6f4; "
" background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #eeeeec), color-stop(1, #f6f6f4));"
" background-size: 100% 5em; background-repeat: no-repeat; }"
" table { width: 100%; border-collapse: collapse; }"
" table, td { border: 1px solid #d3d7cf; border-left: none; border-right: none; }"
" p { margin-bottom: 30px; }"
" td { padding: 15px; }"
" td.data { width: 200px; }"
" .titlename { font-weight: bold; }"
"</style></head><body>");
g_string_append(html,
"<h1>Version Information</h1>"
"<table>");
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">WebKit version</div></td>"
" <td>%s %d.%d.%d (%s)</td>"
" </tbody></tr>",
webkitPortName(), WEBKIT_MAJOR_VERSION, WEBKIT_MINOR_VERSION, WEBKIT_MICRO_VERSION, SVN_REVISION);
#if OS(UNIX)
struct utsname osName;
uname(&osName);
g_string_append_printf(
html,
" <tbody><tr>"
" <td><div class=\"titlename\">Operating system</div></td>"
" <td>%s %s %s %s</td>"
" </tbody></tr>",
osName.sysname, osName.release, osName.version, osName.machine);
#endif
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">Desktop</div></td>"
" <td>%s</td>"
" </tbody></tr>",
g_getenv("XDG_CURRENT_DESKTOP"));
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">Cairo version</div></td>"
" <td>%s (build) %s (runtime)</td>"
" </tbody></tr>",
CAIRO_VERSION_STRING, cairo_version_string());
#if USE(GSTREAMER)
GUniquePtr<char> gstVersion(gst_version_string());
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">GStreamer version</div></td>"
" <td>%d.%d.%d (build) %s (runtime)</td>"
" </tbody></tr>",
GST_VERSION_MAJOR, GST_VERSION_MINOR, GST_VERSION_MICRO, gstVersion.get());
#endif
#if PLATFORM(GTK)
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">GTK version</div></td>"
" <td>%d.%d.%d (build) %d.%d.%d (runtime)</td>"
" </tbody></tr>",
GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION,
gtk_get_major_version(), gtk_get_minor_version(), gtk_get_micro_version());
#if PLATFORM(WAYLAND) && USE(WPE_RENDERER)
if (PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::Wayland) {
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">WPE version</div></td>"
" <td>%d.%d.%d (using fdo backend %d.%d.%d)</td>"
" </tbody></tr>",
WPE_FDO_MAJOR_VERSION, WPE_FDO_MINOR_VERSION, WPE_FDO_MICRO_VERSION,
WPE_MAJOR_VERSION, WPE_MINOR_VERSION, WPE_MICRO_VERSION);
}
#endif
#endif
#if PLATFORM(WPE)
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">WPE version</div></td>"
" <td>%d.%d.%d (build) %d.%d.%d (runtime)</td>"
" </tbody></tr>",
WPE_MAJOR_VERSION, WPE_MINOR_VERSION, WPE_MICRO_VERSION,
wpe_get_major_version(), wpe_get_minor_version(), wpe_get_micro_version());
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">WPE backend</div></td>"
" <td>%s</td>"
" </tbody></tr>",
wpe_loader_get_loaded_implementation_library_name());
#endif
g_string_append(html, "<table>");
g_string_append(html,
"<h1>Display Information</h1>"
"<table>");
#if PLATFORM(GTK)
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">Type</div></td>"
" <td>%s</td>"
" </tbody></tr>",
PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::Wayland ? "Wayland" : "X11");
#endif
auto rect = IntRect(screenRect(nullptr));
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">Screen geometry</div></td>"
" <td>%d,%d %dx%d</td>"
" </tbody></tr>",
rect.x(), rect.y(), rect.width(), rect.height());
rect = IntRect(screenAvailableRect(nullptr));
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">Screen work area</div></td>"
" <td>%d,%d %dx%d</td>"
" </tbody></tr>",
rect.x(), rect.y(), rect.width(), rect.height());
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">Depth</div></td>"
" <td>%d</td>"
" </tbody></tr>",
screenDepth(nullptr));
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">Bits per color component</div></td>"
" <td>%d</td>"
" </tbody></tr>",
screenDepthPerComponent(nullptr));
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">DPI</div></td>"
" <td>%.2f</td>"
" </tbody></tr>",
screenDPI());
g_string_append(html, "<table>");
g_string_append(html,
"<h1>Hardware Acceleration Information</h1>"
"<table>");
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">Policy</div></td>"
" <td>%s</td>"
" </tbody></tr>",
hardwareAccelerationPolicy(request));
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">WebGL enabled</div></td>"
" <td>%s</td>"
" </tbody></tr>",
webGLEnabled(request) ? "Yes" : "No");
auto glContext = GLContext::createOffscreenContext();
glContext->makeContextCurrent();
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">API</div></td>"
" <td>%s</td>"
" </tbody></tr>",
openGLAPI());
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">Native interface</div></td>"
" <td>%s</td>"
" </tbody></tr>",
nativeInterface());
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">GL_RENDERER</div></td>"
" <td>%s</td>"
" </tbody></tr>",
reinterpret_cast<const char*>(glGetString(GL_RENDERER)));
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">GL_VENDOR</div></td>"
" <td>%s</td>"
" </tbody></tr>",
reinterpret_cast<const char*>(glGetString(GL_VENDOR)));
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">GL_VERSION</div></td>"
" <td>%s</td>"
" </tbody></tr>",
reinterpret_cast<const char*>(glGetString(GL_VERSION)));
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">GL_SHADING_LANGUAGE_VERSION</div></td>"
" <td>%s</td>"
" </tbody></tr>",
reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION)));
#if USE(OPENGL_ES)
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">GL_EXTENSIONS</div></td>"
" <td>%s</td>"
" </tbody></tr>",
reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)));
#else
GString* extensions = g_string_new(nullptr);
GLint numExtensions = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
for (GLint i = 0; i < numExtensions; ++i) {
if (i)
g_string_append_c(extensions, ' ');
g_string_append(extensions, reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i)));
}
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">GL_EXTENSIONS</div></td>"
" <td>%s</td>"
" </tbody></tr>",
extensions->str);
g_string_free(extensions, TRUE);
#endif
bool isGLX = false;
#if USE(GLX)
if (PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::X11) {
isGLX = true;
auto* x11Display = downcast<PlatformDisplayX11>(PlatformDisplay::sharedDisplay()).native();
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">GLX_VERSION</div></td>"
" <td>%s</td>"
" </tbody></tr>",
glXGetClientString(x11Display, GLX_VERSION));
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">GLX_VENDOR</div></td>"
" <td>%s</td>"
" </tbody></tr>",
glXGetClientString(x11Display, GLX_VENDOR));
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">GLX_EXTENSIONS</div></td>"
" <td>%s</td>"
" </tbody></tr>",
glXGetClientString(x11Display, GLX_EXTENSIONS));
}
#endif
#if USE(EGL)
if (!isGLX) {
auto eglDisplay = PlatformDisplay::sharedDisplay().eglDisplay();
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">EGL_VERSION</div></td>"
" <td>%s</td>"
" </tbody></tr>",
eglQueryString(eglDisplay, EGL_VERSION));
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">EGL_VENDOR</div></td>"
" <td>%s</td>"
" </tbody></tr>",
eglQueryString(eglDisplay, EGL_VENDOR));
g_string_append_printf(html,
" <tbody><tr>"
" <td><div class=\"titlename\">EGL_EXTENSIONS</div></td>"
" <td>%s %s</td>"
" </tbody></tr>",
eglQueryString(nullptr, EGL_EXTENSIONS),
eglQueryString(eglDisplay, EGL_EXTENSIONS));
}
#endif
g_string_append(html, "<table>");
g_string_append(html, "</body></html>");
gsize streamLength = html->len;
GRefPtr<GInputStream> stream = adoptGRef(g_memory_input_stream_new_from_data(g_string_free(html, FALSE), streamLength, g_free));
webkit_uri_scheme_request_finish(request, stream.get(), streamLength, "text/html");
}
} // namespace WebKit