| /* |
| * 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 "BuildRevision.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 <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 USE(CAIRO) |
| #include <cairo.h> |
| #endif |
| |
| #if PLATFORM(GTK) |
| #include <gtk/gtk.h> |
| |
| #if PLATFORM(WAYLAND) && USE(WPE_RENDERER) |
| #include <wpe/wpe.h> |
| #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) |
| { |
| 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, BUILD_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")); |
| |
| #if USE(CAIRO) |
| 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()); |
| #endif |
| |
| #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 (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\">WPEBackend-fdo version</div></td>" |
| " <td>%d.%d.%d (build) %d.%d.%d (runtime)</td>" |
| " </tbody></tr>", |
| WPE_FDO_MAJOR_VERSION, WPE_FDO_MINOR_VERSION, WPE_FDO_MICRO_VERSION, |
| wpe_fdo_get_major_version(), wpe_fdo_get_minor_version(), wpe_fdo_get_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>", |
| #if PLATFORM(WAYLAND) |
| PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::Wayland ? "Wayland" : |
| #endif |
| #if PLATFORM(X11) |
| PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::X11 ? "X11" : |
| #endif |
| "Unknown" |
| ); |
| #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)); |
| |
| #if ENABLE(WEBGL) |
| 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 |
| #endif // ENABLE(WEBGL) |
| |
| 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 |