2020-08-05 17:41:45 +00:00
/* Copyright (C) <2018, 2019, 2020> Philippe Normand <philn@igalia.com>
2018-12-05 13:10:11 +00:00
* Copyright ( C ) < 2018 > Ž an Doberšek < zdobersek @ igalia . com >
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation ; either
* version 2 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 ; if not , write to the
* Free Software Foundation , Inc . , 51 Franklin St , Fifth Floor ,
* Boston , MA 02110 - 1301 , USA .
*/
2019-06-05 11:47:16 +00:00
# ifdef HAVE_CONFIG_H
# include <config.h>
# endif
2018-12-05 13:10:11 +00:00
# include "WPEThreadedView.h"
2019-06-05 11:47:16 +00:00
# include <gst/gl/gl.h>
# include <gst/gl/egl/gsteglimage.h>
# include <gst/gl/egl/gstgldisplay_egl.h>
2020-02-08 12:05:03 +00:00
# include <wayland-server.h>
2019-06-05 11:47:16 +00:00
2018-12-05 13:10:11 +00:00
# include <cstdio>
# include <mutex>
2020-04-03 14:45:02 +00:00
# if ENABLE_SHM_BUFFER_SUPPORT
# include <wpe/unstable/fdo-shm.h>
# endif
2019-06-05 11:47:16 +00:00
GST_DEBUG_CATEGORY_EXTERN ( wpe_src_debug ) ;
2019-06-12 10:12:37 +00:00
# define GST_CAT_DEFAULT wpe_src_debug
2018-12-05 13:10:11 +00:00
2019-06-12 10:12:37 +00:00
# if defined(WPE_FDO_CHECK_VERSION) && WPE_FDO_CHECK_VERSION(1, 3, 0)
# define USE_DEPRECATED_FDO_EGL_IMAGE 0
# define WPE_GLIB_SOURCE_PRIORITY G_PRIORITY_DEFAULT
# else
# define USE_DEPRECATED_FDO_EGL_IMAGE 1
2018-12-05 13:10:11 +00:00
# define WPE_GLIB_SOURCE_PRIORITY -70
2019-06-12 10:12:37 +00:00
# endif
2018-12-05 13:10:11 +00:00
class GMutexHolder {
public :
GMutexHolder ( GMutex & mutex )
: m ( mutex )
{
g_mutex_lock ( & m ) ;
}
~ GMutexHolder ( )
{
g_mutex_unlock ( & m ) ;
}
private :
GMutex & m ;
} ;
2020-08-05 17:41:45 +00:00
static WPEContextThread * s_view = NULL ;
WPEContextThread & WPEContextThread : : singleton ( )
{
if ( ! s_view )
s_view = new WPEContextThread ;
return * s_view ;
}
WPEContextThread : : WPEContextThread ( )
2018-12-05 13:10:11 +00:00
{
g_mutex_init ( & threading . mutex ) ;
g_cond_init ( & threading . cond ) ;
{
GMutexHolder lock ( threading . mutex ) ;
2020-08-05 17:41:45 +00:00
threading . thread = g_thread_new ( " WPEContextThread " , s_viewThread , this ) ;
2018-12-05 13:10:11 +00:00
g_cond_wait ( & threading . cond , & threading . mutex ) ;
GST_DEBUG ( " thread spawned " ) ;
}
}
2020-08-05 17:41:45 +00:00
WPEContextThread : : ~ WPEContextThread ( )
2018-12-05 13:10:11 +00:00
{
if ( threading . thread ) {
g_thread_unref ( threading . thread ) ;
threading . thread = nullptr ;
}
g_mutex_clear ( & threading . mutex ) ;
g_cond_clear ( & threading . cond ) ;
}
2020-08-05 17:41:45 +00:00
template < typename Function >
void WPEContextThread : : dispatch ( Function func )
2018-12-05 13:10:11 +00:00
{
2020-08-05 17:41:45 +00:00
struct Payload {
Function & func ;
} ;
struct Payload payload { func } ;
GSource * source = g_idle_source_new ( ) ;
g_source_set_callback ( source , [ ] ( gpointer data ) - > gboolean {
auto & view = WPEContextThread : : singleton ( ) ;
GMutexHolder lock ( view . threading . mutex ) ;
auto * payload = static_cast < struct Payload * > ( data ) ;
payload - > func ( ) ;
g_cond_signal ( & view . threading . cond ) ;
return G_SOURCE_REMOVE ;
} , & payload , nullptr ) ;
g_source_set_priority ( source , WPE_GLIB_SOURCE_PRIORITY ) ;
{
GMutexHolder lock ( threading . mutex ) ;
g_source_attach ( source , glib . context ) ;
g_cond_wait ( & threading . cond , & threading . mutex ) ;
}
g_source_unref ( source ) ;
}
gpointer WPEContextThread : : s_viewThread ( gpointer data )
{
auto & view = * static_cast < WPEContextThread * > ( data ) ;
2018-12-05 13:10:11 +00:00
view . glib . context = g_main_context_new ( ) ;
view . glib . loop = g_main_loop_new ( view . glib . context , FALSE ) ;
g_main_context_push_thread_default ( view . glib . context ) ;
{
GSource * source = g_idle_source_new ( ) ;
g_source_set_callback ( source ,
[ ] ( gpointer data ) - > gboolean {
2020-08-05 17:41:45 +00:00
auto & view = * static_cast < WPEContextThread * > ( data ) ;
2018-12-05 13:10:11 +00:00
GMutexHolder lock ( view . threading . mutex ) ;
g_cond_signal ( & view . threading . cond ) ;
return G_SOURCE_REMOVE ;
} ,
& view , nullptr ) ;
g_source_attach ( source , view . glib . context ) ;
g_source_unref ( source ) ;
}
g_main_loop_run ( view . glib . loop ) ;
g_main_loop_unref ( view . glib . loop ) ;
view . glib . loop = nullptr ;
g_main_context_pop_thread_default ( view . glib . context ) ;
g_main_context_unref ( view . glib . context ) ;
view . glib . context = nullptr ;
return nullptr ;
}
2020-08-05 17:41:45 +00:00
WPEView * WPEContextThread : : createWPEView ( GstWpeSrc * src , GstGLContext * context , GstGLDisplay * display , int width , int height )
2018-12-05 13:10:11 +00:00
{
GST_DEBUG ( " context %p display %p, size (%d,%d) " , context , display , width , height ) ;
static std : : once_flag s_loaderFlag ;
std : : call_once ( s_loaderFlag ,
[ ] {
2019-03-30 14:02:50 +00:00
# if defined(WPE_BACKEND_CHECK_VERSION) && WPE_BACKEND_CHECK_VERSION(1, 2, 0)
wpe_loader_init ( " libWPEBackend-fdo-1.0.so " ) ;
2018-12-05 13:10:11 +00:00
# endif
} ) ;
2020-08-05 17:41:45 +00:00
WPEView * view = nullptr ;
dispatch ( [ & ] ( ) mutable {
if ( ! glib . web_context ) {
auto * manager = webkit_website_data_manager_new_ephemeral ( ) ;
glib . web_context = webkit_web_context_new_with_website_data_manager ( manager ) ;
g_object_unref ( manager ) ;
}
view = new WPEView ( glib . web_context , src , context , display , width , height ) ;
} ) ;
if ( view & & view - > hasUri ( ) ) {
GST_DEBUG ( " waiting load to finish " ) ;
2020-09-10 13:39:58 +00:00
view - > waitLoadCompletion ( ) ;
2020-08-05 17:41:45 +00:00
GST_DEBUG ( " done " ) ;
}
return view ;
}
static gboolean s_loadFailed ( WebKitWebView * , WebKitLoadEvent , gchar * failing_uri , GError * error , gpointer data )
{
GstWpeSrc * src = GST_WPE_SRC ( data ) ;
2021-03-15 19:25:36 +00:00
if ( g_error_matches ( error , WEBKIT_NETWORK_ERROR , WEBKIT_NETWORK_ERROR_CANCELLED ) ) {
GST_INFO_OBJECT ( src , " Loading cancelled. " ) ;
return FALSE ;
}
2020-08-05 17:41:45 +00:00
GST_ELEMENT_ERROR ( GST_ELEMENT_CAST ( src ) , RESOURCE , FAILED , ( NULL ) , ( " Failed to load %s (%s) " , failing_uri , error - > message ) ) ;
return FALSE ;
}
2020-09-10 12:05:23 +00:00
static gboolean s_loadFailedWithTLSErrors ( WebKitWebView * , gchar * failing_uri , GTlsCertificate * , GTlsCertificateFlags , gpointer data )
{
// Defer to load-failed.
return FALSE ;
}
2020-10-19 13:56:43 +00:00
static void s_loadProgressChaned ( GObject * object , GParamSpec * , gpointer data )
{
GstElement * src = GST_ELEMENT_CAST ( data ) ;
// The src element is locked already so we can't call
// gst_element_post_message(). Instead retrieve the bus manually and use it
// directly.
GstBus * bus = GST_ELEMENT_BUS ( src ) ;
double estimatedProgress ;
g_object_get ( object , " estimated-load-progress " , & estimatedProgress , nullptr ) ;
gst_object_ref ( bus ) ;
gst_bus_post ( bus , gst_message_new_element ( GST_OBJECT_CAST ( src ) , gst_structure_new ( " wpe-stats " , " estimated-load-progress " , G_TYPE_DOUBLE , estimatedProgress * 100 , nullptr ) ) ) ;
gst_object_unref ( bus ) ;
}
2020-08-05 17:41:45 +00:00
WPEView : : WPEView ( WebKitWebContext * web_context , GstWpeSrc * src , GstGLContext * context , GstGLDisplay * display , int width , int height )
{
2020-09-10 13:39:58 +00:00
g_mutex_init ( & threading . ready_mutex ) ;
g_cond_init ( & threading . ready_cond ) ;
threading . ready = FALSE ;
2020-08-05 17:41:45 +00:00
g_mutex_init ( & images_mutex ) ;
if ( context )
gst . context = GST_GL_CONTEXT ( gst_object_ref ( context ) ) ;
2020-08-14 16:02:44 +00:00
if ( display ) {
2020-08-05 17:41:45 +00:00
gst . display = GST_GL_DISPLAY ( gst_object_ref ( display ) ) ;
2020-08-14 16:02:44 +00:00
}
2020-08-05 17:41:45 +00:00
wpe . width = width ;
wpe . height = height ;
2020-08-14 16:02:44 +00:00
if ( context & & display ) {
if ( gst_gl_context_get_gl_platform ( context ) = = GST_GL_PLATFORM_EGL ) {
gst . display_egl = gst_gl_display_egl_from_gl_display ( gst . display ) ;
} else {
GST_DEBUG ( " Available GStreamer GL Context is not EGL - not creating an EGL display from it " ) ;
}
}
if ( gst . display_egl ) {
EGLDisplay eglDisplay = ( EGLDisplay ) gst_gl_display_get_handle ( GST_GL_DISPLAY ( gst . display_egl ) ) ;
GST_DEBUG ( " eglDisplay %p " , eglDisplay ) ;
2019-08-07 16:07:21 +00:00
2020-08-05 17:41:45 +00:00
m_isValid = wpe_fdo_initialize_for_egl_display ( eglDisplay ) ;
GST_DEBUG ( " FDO EGL display initialisation result: %d " , m_isValid ) ;
} else {
2020-04-03 14:45:02 +00:00
# if ENABLE_SHM_BUFFER_SUPPORT
2020-08-05 17:41:45 +00:00
m_isValid = wpe_fdo_initialize_shm ( ) ;
GST_DEBUG ( " FDO SHM initialisation result: %d " , m_isValid ) ;
2020-04-03 14:45:02 +00:00
# else
2020-08-05 17:41:45 +00:00
GST_WARNING ( " FDO SHM support is available only in WPEBackend-FDO 1.7.0 " ) ;
2020-04-03 14:45:02 +00:00
# endif
2020-08-05 17:41:45 +00:00
}
if ( ! m_isValid )
return ;
2020-08-14 16:02:44 +00:00
if ( gst . display_egl ) {
2020-08-05 17:41:45 +00:00
wpe . exportable = wpe_view_backend_exportable_fdo_egl_create ( & s_exportableEGLClient , this , wpe . width , wpe . height ) ;
} else {
2020-04-03 14:45:02 +00:00
# if ENABLE_SHM_BUFFER_SUPPORT
2020-08-05 17:41:45 +00:00
wpe . exportable = wpe_view_backend_exportable_fdo_create ( & s_exportableClient , this , wpe . width , wpe . height ) ;
2020-04-03 14:45:02 +00:00
# endif
2020-08-05 17:41:45 +00:00
}
auto * wpeViewBackend = wpe_view_backend_exportable_fdo_get_view_backend ( wpe . exportable ) ;
auto * viewBackend = webkit_web_view_backend_new ( wpeViewBackend , ( GDestroyNotify ) wpe_view_backend_exportable_fdo_destroy , wpe . exportable ) ;
2019-01-31 16:31:04 +00:00
# if defined(WPE_BACKEND_CHECK_VERSION) && WPE_BACKEND_CHECK_VERSION(1, 1, 0)
2020-08-05 17:41:45 +00:00
wpe_view_backend_add_activity_state ( wpeViewBackend , wpe_view_activity_state_visible | wpe_view_activity_state_focused | wpe_view_activity_state_in_window ) ;
2019-01-31 16:31:04 +00:00
# endif
2018-12-05 13:10:11 +00:00
2020-08-05 17:41:45 +00:00
webkit . view = WEBKIT_WEB_VIEW ( g_object_new ( WEBKIT_TYPE_WEB_VIEW , " web-context " , web_context , " backend " , viewBackend , nullptr ) ) ;
2018-12-05 13:10:11 +00:00
2020-08-05 17:41:45 +00:00
g_signal_connect ( webkit . view , " load-failed " , G_CALLBACK ( s_loadFailed ) , src ) ;
2020-09-10 12:05:23 +00:00
g_signal_connect ( webkit . view , " load-failed-with-tls-errors " , G_CALLBACK ( s_loadFailedWithTLSErrors ) , src ) ;
2020-10-19 13:56:43 +00:00
g_signal_connect ( webkit . view , " notify::estimated-load-progress " , G_CALLBACK ( s_loadProgressChaned ) , src ) ;
2018-12-05 13:10:11 +00:00
2020-08-05 17:41:45 +00:00
gst_wpe_src_configure_web_view ( src , webkit . view ) ;
2018-12-05 13:10:11 +00:00
2020-08-05 17:41:45 +00:00
const gchar * location ;
gboolean drawBackground = TRUE ;
g_object_get ( src , " location " , & location , " draw-background " , & drawBackground , nullptr ) ;
setDrawBackground ( drawBackground ) ;
if ( location )
loadUriUnlocked ( location ) ;
}
2018-12-05 13:10:11 +00:00
2020-08-05 17:41:45 +00:00
WPEView : : ~ WPEView ( )
{
2020-11-27 05:18:29 +00:00
GstEGLImage * egl_pending = NULL ;
GstEGLImage * egl_committed = NULL ;
GstBuffer * shm_pending = NULL ;
GstBuffer * shm_committed = NULL ;
2020-10-07 10:13:09 +00:00
GST_TRACE ( " %p destroying " , this ) ;
2020-09-10 13:39:58 +00:00
g_mutex_clear ( & threading . ready_mutex ) ;
g_cond_clear ( & threading . ready_cond ) ;
2018-12-05 13:10:11 +00:00
{
2020-08-05 17:41:45 +00:00
GMutexHolder lock ( images_mutex ) ;
if ( egl . pending ) {
2020-11-27 05:18:29 +00:00
egl_pending = egl . pending ;
2020-08-05 17:41:45 +00:00
egl . pending = nullptr ;
}
if ( egl . committed ) {
2020-11-27 05:18:29 +00:00
egl_committed = egl . committed ;
2020-08-05 17:41:45 +00:00
egl . committed = nullptr ;
}
2020-09-11 11:51:56 +00:00
if ( shm . pending ) {
2020-10-07 10:13:09 +00:00
GST_TRACE ( " %p freeing shm pending % " GST_PTR_FORMAT , this , shm . pending ) ;
2020-11-27 05:18:29 +00:00
shm_pending = shm . pending ;
2020-09-11 11:51:56 +00:00
shm . pending = nullptr ;
}
if ( shm . committed ) {
2020-10-07 10:13:09 +00:00
GST_TRACE ( " %p freeing shm commited % " GST_PTR_FORMAT , this , shm . committed ) ;
2020-11-27 05:18:29 +00:00
shm_committed = shm . committed ;
2020-09-11 11:51:56 +00:00
shm . committed = nullptr ;
}
2018-12-05 13:10:11 +00:00
}
2020-11-27 05:18:29 +00:00
if ( egl_pending )
gst_egl_image_unref ( egl_pending ) ;
if ( egl_committed )
gst_egl_image_unref ( egl_committed ) ;
if ( shm_pending )
gst_buffer_unref ( shm_pending ) ;
if ( shm_committed )
gst_buffer_unref ( shm_committed ) ;
2020-08-05 17:41:45 +00:00
WPEContextThread : : singleton ( ) . dispatch ( [ & ] ( ) {
if ( webkit . view ) {
g_object_unref ( webkit . view ) ;
webkit . view = nullptr ;
}
} ) ;
2018-12-05 13:10:11 +00:00
2020-08-14 16:02:44 +00:00
if ( gst . display_egl ) {
gst_object_unref ( gst . display_egl ) ;
gst . display_egl = nullptr ;
}
2020-08-05 17:41:45 +00:00
if ( gst . display ) {
gst_object_unref ( gst . display ) ;
gst . display = nullptr ;
2018-12-05 13:10:11 +00:00
}
2020-07-28 21:28:12 +00:00
2020-08-05 17:41:45 +00:00
if ( gst . context ) {
gst_object_unref ( gst . context ) ;
gst . context = nullptr ;
}
if ( webkit . uri ) {
g_free ( webkit . uri ) ;
webkit . uri = nullptr ;
}
2020-07-28 21:28:12 +00:00
2020-08-05 17:41:45 +00:00
g_mutex_clear ( & images_mutex ) ;
2020-10-07 10:13:09 +00:00
GST_TRACE ( " %p destroyed " , this ) ;
2018-12-05 13:10:11 +00:00
}
2020-09-10 13:39:58 +00:00
void WPEView : : notifyLoadFinished ( )
{
GMutexHolder lock ( threading . ready_mutex ) ;
if ( ! threading . ready ) {
threading . ready = TRUE ;
g_cond_signal ( & threading . ready_cond ) ;
}
}
void WPEView : : waitLoadCompletion ( )
{
GMutexHolder lock ( threading . ready_mutex ) ;
while ( ! threading . ready )
g_cond_wait ( & threading . ready_cond , & threading . ready_mutex ) ;
}
2020-08-05 17:41:45 +00:00
GstEGLImage * WPEView : : image ( )
2018-12-05 13:10:11 +00:00
{
GstEGLImage * ret = nullptr ;
2019-10-22 17:33:18 +00:00
bool dispatchFrameComplete = false ;
2020-11-27 05:18:29 +00:00
GstEGLImage * prev_image = NULL ;
2018-12-05 13:10:11 +00:00
2019-10-19 11:48:55 +00:00
{
2020-02-08 12:05:03 +00:00
GMutexHolder lock ( images_mutex ) ;
2019-10-19 11:48:55 +00:00
2020-02-08 12:05:03 +00:00
GST_TRACE ( " pending % " GST_PTR_FORMAT " (%d) committed % " GST_PTR_FORMAT " (%d) " , egl . pending ,
GST_IS_EGL_IMAGE ( egl . pending ) ? GST_MINI_OBJECT_REFCOUNT_VALUE ( GST_MINI_OBJECT_CAST ( egl . pending ) ) : 0 ,
egl . committed ,
GST_IS_EGL_IMAGE ( egl . committed ) ? GST_MINI_OBJECT_REFCOUNT_VALUE ( GST_MINI_OBJECT_CAST ( egl . committed ) ) : 0 ) ;
2019-10-19 11:48:55 +00:00
2020-02-08 12:05:03 +00:00
if ( egl . pending ) {
2020-11-27 05:18:29 +00:00
prev_image = egl . committed ;
2020-02-08 12:05:03 +00:00
egl . committed = egl . pending ;
egl . pending = nullptr ;
2018-12-05 13:10:11 +00:00
2019-10-22 17:33:18 +00:00
dispatchFrameComplete = true ;
2019-10-19 11:48:55 +00:00
}
2018-12-05 13:10:11 +00:00
2020-02-08 12:05:03 +00:00
if ( egl . committed )
ret = egl . committed ;
}
2020-11-27 05:18:29 +00:00
if ( prev_image )
gst_egl_image_unref ( prev_image ) ;
2020-02-08 12:05:03 +00:00
if ( dispatchFrameComplete )
frameComplete ( ) ;
return ret ;
}
2020-08-05 17:41:45 +00:00
GstBuffer * WPEView : : buffer ( )
2020-02-08 12:05:03 +00:00
{
GstBuffer * ret = nullptr ;
bool dispatchFrameComplete = false ;
2020-11-27 05:18:29 +00:00
GstBuffer * prev_image = NULL ;
2020-02-08 12:05:03 +00:00
{
GMutexHolder lock ( images_mutex ) ;
GST_TRACE ( " pending % " GST_PTR_FORMAT " (%d) committed % " GST_PTR_FORMAT " (%d) " , shm . pending ,
GST_IS_BUFFER ( shm . pending ) ? GST_MINI_OBJECT_REFCOUNT_VALUE ( GST_MINI_OBJECT_CAST ( shm . pending ) ) : 0 ,
shm . committed ,
GST_IS_BUFFER ( shm . committed ) ? GST_MINI_OBJECT_REFCOUNT_VALUE ( GST_MINI_OBJECT_CAST ( shm . committed ) ) : 0 ) ;
if ( shm . pending ) {
2020-11-27 05:18:29 +00:00
prev_image = shm . committed ;
2020-02-08 12:05:03 +00:00
shm . committed = shm . pending ;
shm . pending = nullptr ;
dispatchFrameComplete = true ;
}
if ( shm . committed )
ret = shm . committed ;
2018-12-05 13:10:11 +00:00
}
2020-11-27 05:18:29 +00:00
if ( prev_image )
gst_buffer_unref ( prev_image ) ;
2019-10-22 17:33:18 +00:00
if ( dispatchFrameComplete )
2019-08-07 16:07:21 +00:00
frameComplete ( ) ;
2018-12-05 13:10:11 +00:00
return ret ;
}
2020-08-05 17:41:45 +00:00
void WPEView : : resize ( int width , int height )
2018-12-05 13:10:11 +00:00
{
2019-08-07 16:07:21 +00:00
GST_DEBUG ( " resize to %dx%d " , width , height ) ;
wpe . width = width ;
wpe . height = height ;
2018-12-05 13:10:11 +00:00
2020-08-05 17:41:45 +00:00
s_view - > dispatch ( [ & ] ( ) {
if ( wpe . exportable & & wpe_view_backend_exportable_fdo_get_view_backend ( wpe . exportable ) )
wpe_view_backend_dispatch_set_size ( wpe_view_backend_exportable_fdo_get_view_backend ( wpe . exportable ) , wpe . width , wpe . height ) ;
} ) ;
2018-12-05 13:10:11 +00:00
}
2020-08-05 17:41:45 +00:00
void WPEView : : frameComplete ( )
2018-12-05 13:10:11 +00:00
{
2019-08-07 16:07:21 +00:00
GST_TRACE ( " frame complete " ) ;
2020-08-05 17:41:45 +00:00
s_view - > dispatch ( [ & ] ( ) {
GST_TRACE ( " dispatching " ) ;
wpe_view_backend_exportable_fdo_dispatch_frame_complete ( wpe . exportable ) ;
} ) ;
2018-12-05 13:10:11 +00:00
}
2020-08-05 17:41:45 +00:00
void WPEView : : loadUriUnlocked ( const gchar * uri )
2018-12-05 13:10:11 +00:00
{
if ( webkit . uri )
g_free ( webkit . uri ) ;
2019-01-31 16:30:18 +00:00
GST_DEBUG ( " loading %s " , uri ) ;
2018-12-05 13:10:11 +00:00
webkit . uri = g_strdup ( uri ) ;
webkit_web_view_load_uri ( webkit . view , webkit . uri ) ;
}
2020-08-05 17:41:45 +00:00
void WPEView : : loadUri ( const gchar * uri )
2018-12-05 13:10:11 +00:00
{
2020-08-05 17:41:45 +00:00
s_view - > dispatch ( [ & ] ( ) {
loadUriUnlocked ( uri ) ;
} ) ;
2018-12-05 13:10:11 +00:00
}
2020-08-05 17:41:45 +00:00
void WPEView : : loadData ( GBytes * bytes )
2019-09-24 23:57:54 +00:00
{
2020-08-05 17:41:45 +00:00
s_view - > dispatch ( [ this , bytes = g_bytes_ref ( bytes ) ] ( ) {
webkit_web_view_load_bytes ( webkit . view , bytes , nullptr , nullptr , nullptr ) ;
g_bytes_unref ( bytes ) ;
} ) ;
2019-09-24 23:57:54 +00:00
}
2020-08-05 17:41:45 +00:00
void WPEView : : setDrawBackground ( gboolean drawsBackground )
2018-12-05 13:10:11 +00:00
{
2019-06-12 10:12:37 +00:00
# if WEBKIT_CHECK_VERSION(2, 24, 0)
2019-01-18 13:28:45 +00:00
GST_DEBUG ( " %s background rendering " , drawsBackground ? " Enabling " : " Disabling " ) ;
WebKitColor color ;
webkit_color_parse ( & color , drawsBackground ? " white " : " transparent " ) ;
webkit_web_view_set_background_color ( webkit . view , & color ) ;
2018-12-05 13:10:11 +00:00
# else
2019-01-18 13:28:45 +00:00
GST_FIXME ( " webkit_web_view_set_background_color is not implemented in WPE %u.%u. Please upgrade to 2.24 " , webkit_get_major_version ( ) , webkit_get_minor_version ( ) ) ;
2018-12-05 13:10:11 +00:00
# endif
}
2020-08-05 17:41:45 +00:00
void WPEView : : releaseImage ( gpointer imagePointer )
2018-12-05 13:10:11 +00:00
{
2020-08-05 17:41:45 +00:00
s_view - > dispatch ( [ & ] ( ) {
GST_TRACE ( " Dispatch release exported image %p " , imagePointer ) ;
2019-06-12 10:12:37 +00:00
# if USE_DEPRECATED_FDO_EGL_IMAGE
2020-08-05 17:41:45 +00:00
wpe_view_backend_exportable_fdo_egl_dispatch_release_image ( wpe . exportable ,
static_cast < EGLImageKHR > ( imagePointer ) ) ;
2019-06-12 10:12:37 +00:00
# else
2020-08-05 17:41:45 +00:00
wpe_view_backend_exportable_fdo_egl_dispatch_release_exported_image ( wpe . exportable ,
static_cast < struct wpe_fdo_egl_exported_image * > ( imagePointer ) ) ;
2019-06-12 10:12:37 +00:00
# endif
2020-08-05 17:41:45 +00:00
} ) ;
2018-12-05 13:10:11 +00:00
}
2019-06-12 10:12:37 +00:00
struct ImageContext {
2020-08-05 17:41:45 +00:00
WPEView * view ;
2019-06-12 10:12:37 +00:00
gpointer image ;
} ;
2020-08-05 17:41:45 +00:00
void WPEView : : handleExportedImage ( gpointer image )
2019-06-12 10:12:37 +00:00
{
ImageContext * imageContext = g_slice_new ( ImageContext ) ;
imageContext - > view = this ;
imageContext - > image = static_cast < gpointer > ( image ) ;
EGLImageKHR eglImage ;
# if USE_DEPRECATED_FDO_EGL_IMAGE
eglImage = static_cast < EGLImageKHR > ( image ) ;
# else
eglImage = wpe_fdo_egl_exported_image_get_egl_image ( static_cast < struct wpe_fdo_egl_exported_image * > ( image ) ) ;
# endif
auto * gstImage = gst_egl_image_new_wrapped ( gst . context , eglImage , GST_GL_RGBA , imageContext , s_releaseImage ) ;
2019-08-07 16:07:21 +00:00
{
2020-02-08 12:05:03 +00:00
GMutexHolder lock ( images_mutex ) ;
2019-08-07 16:07:21 +00:00
GST_TRACE ( " EGLImage %p wrapped in GstEGLImage % " GST_PTR_FORMAT , eglImage , gstImage ) ;
2020-10-02 02:06:59 +00:00
gst_clear_mini_object ( ( GstMiniObject * * ) & egl . pending ) ;
2020-02-08 12:05:03 +00:00
egl . pending = gstImage ;
2020-07-28 21:28:12 +00:00
2020-09-10 13:39:58 +00:00
notifyLoadFinished ( ) ;
2019-08-07 16:07:21 +00:00
}
2019-06-12 10:12:37 +00:00
}
2020-02-08 12:05:03 +00:00
# if ENABLE_SHM_BUFFER_SUPPORT
struct SHMBufferContext {
2020-08-05 17:41:45 +00:00
WPEView * view ;
struct wpe_fdo_shm_exported_buffer * buffer ;
2020-02-08 12:05:03 +00:00
} ;
2020-08-05 17:41:45 +00:00
void WPEView : : releaseSHMBuffer ( gpointer data )
2020-02-08 12:05:03 +00:00
{
SHMBufferContext * context = static_cast < SHMBufferContext * > ( data ) ;
2020-08-05 17:41:45 +00:00
s_view - > dispatch ( [ & ] ( ) {
auto * buffer = static_cast < struct wpe_fdo_shm_exported_buffer * > ( context - > buffer ) ;
GST_TRACE ( " Dispatch release exported buffer %p " , buffer ) ;
wpe_view_backend_exportable_fdo_dispatch_release_shm_exported_buffer ( wpe . exportable , buffer ) ;
} ) ;
2020-02-08 12:05:03 +00:00
}
2020-08-05 17:41:45 +00:00
void WPEView : : s_releaseSHMBuffer ( gpointer data )
2020-02-08 12:05:03 +00:00
{
SHMBufferContext * context = static_cast < SHMBufferContext * > ( data ) ;
context - > view - > releaseSHMBuffer ( data ) ;
g_slice_free ( SHMBufferContext , context ) ;
}
2020-08-05 17:41:45 +00:00
void WPEView : : handleExportedBuffer ( struct wpe_fdo_shm_exported_buffer * buffer )
2020-02-08 12:05:03 +00:00
{
struct wl_shm_buffer * shmBuffer = wpe_fdo_shm_exported_buffer_get_shm_buffer ( buffer ) ;
auto format = wl_shm_buffer_get_format ( shmBuffer ) ;
if ( format ! = WL_SHM_FORMAT_ARGB8888 & & format ! = WL_SHM_FORMAT_XRGB8888 ) {
GST_ERROR ( " Unsupported pixel format: %d " , format ) ;
return ;
}
int32_t width = wl_shm_buffer_get_width ( shmBuffer ) ;
int32_t height = wl_shm_buffer_get_height ( shmBuffer ) ;
gint stride = wl_shm_buffer_get_stride ( shmBuffer ) ;
gsize size = width * height * 4 ;
auto * data = static_cast < uint8_t * > ( wl_shm_buffer_get_data ( shmBuffer ) ) ;
SHMBufferContext * bufferContext = g_slice_new ( SHMBufferContext ) ;
bufferContext - > view = this ;
bufferContext - > buffer = buffer ;
auto * gstBuffer = gst_buffer_new_wrapped_full ( GST_MEMORY_FLAG_READONLY , data , size , 0 , size , bufferContext , s_releaseSHMBuffer ) ;
gsize offsets [ 1 ] ;
gint strides [ 1 ] ;
offsets [ 0 ] = 0 ;
strides [ 0 ] = stride ;
gst_buffer_add_video_meta_full ( gstBuffer , GST_VIDEO_FRAME_FLAG_NONE , GST_VIDEO_FORMAT_BGRA , width , height , 1 , offsets , strides ) ;
{
GMutexHolder lock ( images_mutex ) ;
GST_TRACE ( " SHM buffer %p wrapped in buffer % " GST_PTR_FORMAT , buffer , gstBuffer ) ;
2020-10-02 02:06:59 +00:00
gst_clear_buffer ( & shm . pending ) ;
2020-02-08 12:05:03 +00:00
shm . pending = gstBuffer ;
2020-09-10 13:39:58 +00:00
notifyLoadFinished ( ) ;
2020-02-08 12:05:03 +00:00
}
}
# endif
2020-08-05 17:41:45 +00:00
struct wpe_view_backend_exportable_fdo_egl_client WPEView : : s_exportableEGLClient = {
2019-06-12 10:12:37 +00:00
# if USE_DEPRECATED_FDO_EGL_IMAGE
// export_egl_image
2018-12-05 13:10:11 +00:00
[ ] ( void * data , EGLImageKHR image ) {
2020-08-05 17:41:45 +00:00
auto & view = * static_cast < WPEView * > ( data ) ;
2019-06-12 10:12:37 +00:00
view . handleExportedImage ( static_cast < gpointer > ( image ) ) ;
2018-12-05 13:10:11 +00:00
} ,
2020-02-08 12:05:03 +00:00
nullptr , nullptr ,
2019-06-12 10:12:37 +00:00
# else
// export_egl_image
nullptr ,
[ ] ( void * data , struct wpe_fdo_egl_exported_image * image ) {
2020-08-05 17:41:45 +00:00
auto & view = * static_cast < WPEView * > ( data ) ;
2019-06-12 10:12:37 +00:00
view . handleExportedImage ( static_cast < gpointer > ( image ) ) ;
} ,
2020-04-03 14:45:02 +00:00
nullptr ,
# endif // USE_DEPRECATED_FDO_EGL_IMAGE
// padding
nullptr , nullptr
} ;
2020-02-08 12:05:03 +00:00
# if ENABLE_SHM_BUFFER_SUPPORT
2020-08-05 17:41:45 +00:00
struct wpe_view_backend_exportable_fdo_client WPEView : : s_exportableClient = {
2020-04-03 14:45:02 +00:00
nullptr ,
nullptr ,
2020-02-08 12:05:03 +00:00
// export_shm_buffer
[ ] ( void * data , struct wpe_fdo_shm_exported_buffer * buffer ) {
2020-08-05 17:41:45 +00:00
auto & view = * static_cast < WPEView * > ( data ) ;
2020-02-08 12:05:03 +00:00
view . handleExportedBuffer ( buffer ) ;
} ,
nullptr ,
2020-04-03 14:45:02 +00:00
nullptr ,
2018-12-05 13:10:11 +00:00
} ;
2020-04-03 14:45:02 +00:00
# endif
2018-12-05 13:10:11 +00:00
2020-08-05 17:41:45 +00:00
void WPEView : : s_releaseImage ( GstEGLImage * image , gpointer data )
2018-12-05 13:10:11 +00:00
{
2019-06-12 10:12:37 +00:00
ImageContext * context = static_cast < ImageContext * > ( data ) ;
context - > view - > releaseImage ( context - > image ) ;
g_slice_free ( ImageContext , context ) ;
2018-12-05 13:10:11 +00:00
}
2020-08-05 17:41:45 +00:00
struct wpe_view_backend * WPEView : : backend ( ) const
{
return wpe . exportable ? wpe_view_backend_exportable_fdo_get_view_backend ( wpe . exportable ) : nullptr ;
}
void WPEView : : dispatchKeyboardEvent ( struct wpe_input_keyboard_event & wpe_event )
{
s_view - > dispatch ( [ & ] ( ) {
wpe_view_backend_dispatch_keyboard_event ( backend ( ) , & wpe_event ) ;
} ) ;
}
void WPEView : : dispatchPointerEvent ( struct wpe_input_pointer_event & wpe_event )
{
s_view - > dispatch ( [ & ] ( ) {
wpe_view_backend_dispatch_pointer_event ( backend ( ) , & wpe_event ) ;
} ) ;
}
void WPEView : : dispatchAxisEvent ( struct wpe_input_axis_event & wpe_event )
{
s_view - > dispatch ( [ & ] ( ) {
wpe_view_backend_dispatch_axis_event ( backend ( ) , & wpe_event ) ;
} ) ;
}