2016-07-12 00:40:13 +00:00
//fte defs
# include "../plugin.h"
# include "../engine.h"
2020-05-14 15:50:26 +00:00
static plugfsfuncs_t * fsfuncs ;
static plugsubconsolefuncs_t * confuncs ;
static plugclientfuncs_t * clientfuncs ;
# pragma GCC diagnostic ignored "-Wstrict-prototypes" //not my bug.
2016-07-12 00:40:13 +00:00
//libcef defs
# include "include/cef_version.h"
# include "include/capi/cef_app_capi.h"
# include "include/capi/cef_client_capi.h"
2020-05-14 15:50:26 +00:00
# include "include/capi/cef_parser_capi.h"
# include "include/capi/cef_request_context_handler_capi.h"
2016-07-12 00:40:13 +00:00
//#include "include/capi/cef_url_capi.h"
# include "assert.h"
# if defined(_DEBUG) && defined(_MSC_VER)
# include <crtdbg.h>
# endif
2020-05-14 15:50:26 +00:00
# ifndef _WIN32
# include <unistd.h>
# endif
2021-11-03 20:30:48 +00:00
# include <sys/types.h>
# include <sys/stat.h>
2020-05-14 15:50:26 +00:00
# define EXPECTED_COMMIT_NUMBER 2179 //last version of libcef we tried building against...
# if EXPECTED_COMMIT_NUMBER != EXPECTED_COMMIT_NUMBER
# warning "libcef version different from expected. expect problems with libcef's unstable API."
# endif
# define cef_addref(ptr) (ptr)->base.add_ref(&(ptr)->base)
# define cef_release(ptr) (((ptr)->base.release)(&(ptr)->base))
2016-07-12 00:40:13 +00:00
2021-10-05 05:05:15 +00:00
# if !defined(LIBCEF_STATIC) && !defined(LIBCEF_DYNAMIC)
2020-05-14 15:50:26 +00:00
# define LIBCEF_DYNAMIC
# endif
# ifdef LIBCEF_DYNAMIC
2016-07-12 00:40:13 +00:00
//avoid conflicts with cef headers
# define cef_version_info pcef_version_info
# define cef_initialize pcef_initialize
# define cef_do_message_loop_work pcef_do_message_loop_work
# define cef_shutdown pcef_shutdown
# define cef_execute_process pcef_execute_process
# define cef_browser_host_create_browser_sync pcef_browser_host_create_browser_sync
# define cef_string_utf8_to_utf16 pcef_string_utf8_to_utf16
# define cef_string_utf16_to_utf8 pcef_string_utf16_to_utf8
# define cef_string_utf16_clear pcef_string_utf16_clear
# define cef_string_utf16_set pcef_string_utf16_set
# define cef_string_utf8_clear pcef_string_utf8_clear
# define cef_string_utf8_set pcef_string_utf8_set
# define cef_string_userfree_utf16_free pcef_string_userfree_utf16_free
# define cef_register_scheme_handler_factory pcef_register_scheme_handler_factory
# define cef_get_mime_type pcef_get_mime_type
# define cef_v8value_create_function pcef_v8value_create_function
# define cef_v8value_create_string pcef_v8value_create_string
# define cef_process_message_create pcef_process_message_create
# define cef_v8context_get_current_context pcef_v8context_get_current_context
# define cef_post_task pcef_post_task
# define cef_request_context_create_context pcef_request_context_create_context
2017-09-20 11:27:13 +00:00
# define cef_string_multimap_alloc pcef_string_multimap_alloc
# define cef_string_multimap_append pcef_string_multimap_append
# define cef_string_multimap_size pcef_string_multimap_size
# define cef_string_multimap_key pcef_string_multimap_key
# define cef_string_multimap_value pcef_string_multimap_value
# define cef_string_multimap_free pcef_string_multimap_free
# define cef_string_list_size pcef_string_list_size
# define cef_string_list_value pcef_string_list_value
2016-07-12 00:40:13 +00:00
static int ( * cef_version_info ) ( int entry ) ;
static int ( * cef_initialize ) ( const struct _cef_main_args_t * args , const cef_settings_t * settings , cef_app_t * application , void * windows_sandbox_info ) ;
static void ( * cef_do_message_loop_work ) ( void ) ;
static void ( * cef_shutdown ) ( void ) ;
static int ( * cef_execute_process ) ( const cef_main_args_t * args , cef_app_t * application , void * windows_sandbox_info ) ;
2020-05-14 15:50:26 +00:00
static cef_browser_t * ( * cef_browser_host_create_browser_sync ) ( const cef_window_info_t * windowInfo , cef_client_t * client , const cef_string_t * url , const cef_browser_settings_t * settings , cef_dictionary_value_t * extra_info , cef_request_context_t * request_context ) ;
2016-07-12 00:40:13 +00:00
static int ( * cef_string_utf8_to_utf16 ) ( const char * src , size_t src_len , cef_string_utf16_t * output ) ;
static int ( * cef_string_utf16_to_utf8 ) ( const char16 * src , size_t src_len , cef_string_utf8_t * output ) ;
static void ( * cef_string_utf16_clear ) ( cef_string_utf16_t * str ) ;
static int ( * cef_string_utf16_set ) ( const char16 * src , size_t src_len , cef_string_utf16_t * output , int copy ) ;
static void ( * cef_string_utf8_clear ) ( cef_string_utf8_t * str ) ;
static int ( * cef_string_utf8_set ) ( const char * src , size_t src_len , cef_string_utf8_t * output , int copy ) ;
static void ( * cef_string_userfree_utf16_free ) ( cef_string_userfree_utf16_t str ) ;
static int ( * cef_register_scheme_handler_factory ) ( const cef_string_t * scheme_name , const cef_string_t * domain_name , cef_scheme_handler_factory_t * factory ) ;
static cef_string_userfree_t ( * cef_get_mime_type ) ( const cef_string_t * extension ) ;
static cef_v8value_t * ( * cef_v8value_create_function ) ( const cef_string_t * name , cef_v8handler_t * handler ) ;
static cef_v8value_t * ( * cef_v8value_create_string ) ( const cef_string_t * value ) ;
static cef_process_message_t * ( * cef_process_message_create ) ( const cef_string_t * name ) ;
static cef_v8context_t * ( * cef_v8context_get_current_context ) ( void ) ; //typical C++ programmers omitted the void.
static int ( * cef_post_task ) ( cef_thread_id_t threadId , cef_task_t * task ) ;
static cef_request_context_t * ( * cef_request_context_create_context ) ( const cef_request_context_settings_t * settings , cef_request_context_handler_t * handler ) ;
2017-09-20 11:27:13 +00:00
static cef_string_multimap_t ( * cef_string_multimap_alloc ) ( void ) ;
static int ( * cef_string_multimap_append ) ( cef_string_multimap_t map , const cef_string_t * key , const cef_string_t * value ) ;
static size_t ( * cef_string_multimap_size ) ( cef_string_multimap_t map ) ;
static int ( * cef_string_multimap_key ) ( cef_string_multimap_t map , size_t index , cef_string_t * key ) ;
static int ( * cef_string_multimap_value ) ( cef_string_multimap_t map , size_t index , cef_string_t * value ) ;
static void ( * cef_string_multimap_free ) ( cef_string_multimap_t map ) ;
static size_t ( * cef_string_list_size ) ( cef_string_list_t list ) ;
static int ( * cef_string_list_value ) ( cef_string_list_t list , size_t index , cef_string_t * value ) ;
2016-07-12 00:40:13 +00:00
# endif
2020-05-14 15:50:26 +00:00
static cvar_t * cef_incognito ;
static cvar_t * cef_allowplugins ;
static cvar_t * cef_allowcvars ;
static cvar_t * cef_devtools ;
2016-07-12 00:40:13 +00:00
static char plugname [ MAX_OSPATH ] ;
static char * newconsole ;
2017-09-20 11:27:13 +00:00
/*static void setcefstring(char *str, cef_string_t *r)
2016-07-12 00:40:13 +00:00
{
cef_string_from_utf8 ( str , strlen ( str ) , r ) ;
2017-09-20 11:27:13 +00:00
} */
2016-07-12 00:40:13 +00:00
static cef_string_t makecefstring ( char * str )
{
cef_string_t r = { NULL } ;
cef_string_from_utf8 ( str , strlen ( str ) , & r ) ;
return r ;
}
2017-09-20 11:27:13 +00:00
static cef_string_t * makecefstringptr ( char * str , cef_string_t * ptr )
{
cef_string_from_utf8 ( str , strlen ( str ) , ptr ) ;
return ptr ;
}
2016-07-12 00:40:13 +00:00
static char * Info_JSONify ( char * s , char * o , size_t outlen )
{
outlen - - ; //so we don't have to consider nulls
if ( * s = = ' \\ ' )
s + + ;
while ( * s )
{
//min overhead
if ( outlen < 6 )
break ;
outlen - = 6 ;
* o + + = ' , ' ;
* o + + = ' \" ' ;
for ( ; * s & & * s ! = ' \\ ' ; s + + )
{
if ( * s ! = ' \" ' & & outlen )
{
outlen - - ;
* o + + = * s ;
}
}
* o + + = ' \" ' ;
* o + + = ' : ' ;
* o + + = ' \" ' ;
if ( ! * s + + )
{
//should never happen.
* o + + = ' \" ' ;
* o = 0 ;
return o ;
}
for ( ; * s & & * s ! = ' \\ ' ; s + + )
{
if ( * s ! = ' \" ' & & outlen )
{
outlen - - ;
* o + + = * s ;
}
}
* o + + = ' \" ' ;
if ( * s )
s + + ;
}
* o = 0 ;
return o ;
}
# ifdef _MSC_VER
# define atomic_fetch_add(p,v) (InterlockedIncrement(p)-1)
# define atomic_fetch_sub(p,v) (InterlockedDecrement(p)+1)
# define atomic_uint32_t LONG
# else
# define atomic_fetch_add __sync_fetch_and_add
# define atomic_fetch_sub __sync_fetch_and_sub
# define atomic_uint32_t unsigned int
# endif
typedef struct
{
atomic_uint32_t refcount ; //this needs to be atomic to avoid multiple threads adding at the same time
//cef interface objects
cef_client_t client ;
cef_render_handler_t render_handler ;
cef_display_handler_t display_handler ;
cef_request_handler_t request_handler ;
cef_life_span_handler_t life_span_handler ;
2017-09-20 11:27:13 +00:00
cef_context_menu_handler_t context_menu_handler ;
2016-07-12 00:40:13 +00:00
cef_browser_t * thebrowser ;
void * videodata ;
int videowidth ;
int videoheight ;
qboolean updated ;
int desiredwidth ;
int desiredheight ;
char * consolename ; //for internal plugin use.
2017-09-20 11:27:13 +00:00
qboolean fullscreen ;
2016-07-12 00:40:13 +00:00
cef_string_utf8_t currenturl ;
2017-09-20 11:27:13 +00:00
cef_string_utf8_t currenticon ;
2016-07-12 00:40:13 +00:00
cef_string_utf8_t currenttitle ;
cef_string_utf8_t currentstatus ;
cef_mouse_event_t mousepos ;
unsigned char keystate [ K_MAX ] ;
} browser_t ;
unsigned int numbrowsers ;
static void browser_addref ( browser_t * br )
{
atomic_fetch_add ( & br - > refcount , 1 ) ;
}
static int browser_release ( browser_t * br )
{
if ( atomic_fetch_sub ( & br - > refcount , 1 ) = = 1 )
{
if ( br - > consolename )
free ( br - > consolename ) ;
if ( br - > videodata )
free ( br - > videodata ) ;
cef_string_utf8_clear ( & br - > currenturl ) ;
2017-09-20 11:27:13 +00:00
cef_string_utf8_clear ( & br - > currenticon ) ;
2016-07-12 00:40:13 +00:00
cef_string_utf8_clear ( & br - > currenttitle ) ;
cef_string_utf8_clear ( & br - > currentstatus ) ;
numbrowsers - - ;
free ( br ) ;
return true ;
}
return false ;
}
# define browser_subs(sub) \
2020-05-14 15:50:26 +00:00
static void CEF_CALLBACK browser_ # # sub # # _addref ( cef_base_ref_counted_t * self ) { browser_t * br = ( browser_t * ) ( ( char * ) self - offsetof ( browser_t , sub . base ) ) ; browser_addref ( br ) ; } ; \
static int CEF_CALLBACK browser_ # # sub # # _release ( cef_base_ref_counted_t * self ) { browser_t * br = ( browser_t * ) ( ( char * ) self - offsetof ( browser_t , sub . base ) ) ; return browser_release ( br ) ; } ; \
static int CEF_CALLBACK browser_ # # sub # # _hasoneref ( cef_base_ref_counted_t * self ) { browser_t * br = ( browser_t * ) ( ( char * ) self - offsetof ( browser_t , sub . base ) ) ; return br - > refcount = = 1 ; } ;
2016-07-12 00:40:13 +00:00
browser_subs ( client ) ;
browser_subs ( render_handler ) ;
browser_subs ( display_handler ) ;
browser_subs ( request_handler ) ;
browser_subs ( life_span_handler ) ;
2017-09-20 11:27:13 +00:00
browser_subs ( context_menu_handler ) ;
2016-07-12 00:40:13 +00:00
# undef browser_subs
//client methods
static cef_render_handler_t * CEF_CALLBACK browser_get_render_handler ( cef_client_t * self )
{
browser_t * br = ( browser_t * ) ( ( char * ) self - offsetof ( browser_t , client ) ) ;
cef_addref ( & br - > render_handler ) ;
return & br - > render_handler ;
}
static cef_life_span_handler_t * CEF_CALLBACK browser_get_life_span_handler ( cef_client_t * self )
{
browser_t * br = ( browser_t * ) ( ( char * ) self - offsetof ( browser_t , client ) ) ;
cef_addref ( & br - > life_span_handler ) ;
return & br - > life_span_handler ;
}
2017-09-20 11:27:13 +00:00
static cef_context_menu_handler_t * CEF_CALLBACK browser_get_context_menu_handler ( cef_client_t * self )
{
browser_t * br = ( browser_t * ) ( ( char * ) self - offsetof ( browser_t , client ) ) ;
cef_addref ( & br - > context_menu_handler ) ;
return & br - > context_menu_handler ;
}
2016-07-12 00:40:13 +00:00
static cef_display_handler_t * CEF_CALLBACK browser_get_display_handler ( cef_client_t * self )
{
browser_t * br = ( browser_t * ) ( ( char * ) self - offsetof ( browser_t , client ) ) ;
cef_addref ( & br - > display_handler ) ;
return & br - > display_handler ;
}
static cef_request_handler_t * CEF_CALLBACK browser_get_request_handler ( cef_client_t * self )
{
browser_t * br = ( browser_t * ) ( ( char * ) self - offsetof ( browser_t , client ) ) ;
cef_addref ( & br - > request_handler ) ;
return & br - > request_handler ;
}
static qboolean browser_handle_query ( const char * req , char * buffer , size_t buffersize )
{
2017-09-20 11:27:13 +00:00
if ( ! req )
return false ;
else if ( ! strncmp ( req , " getcvar_ " , 8 ) )
2016-07-12 00:40:13 +00:00
{
2020-05-14 15:50:26 +00:00
if ( cef_allowcvars - > value & & cvarfuncs - > GetString ( req + 8 , buffer , buffersize ) )
2016-07-12 00:40:13 +00:00
return true ;
}
else if ( ! strncmp ( req , " setcvar_ " , 8 ) )
{
const char * eq = strchr ( req + 8 , ' = ' ) ;
if ( eq )
* ( char * ) eq + + = 0 ;
else
eq = req + strlen ( req ) ;
2020-05-14 15:50:26 +00:00
if ( cef_allowcvars - > value )
2016-07-12 00:40:13 +00:00
{
2020-05-14 15:50:26 +00:00
cvarfuncs - > SetString ( req + 8 , eq ) ;
2016-07-12 00:40:13 +00:00
* buffer = 0 ;
return true ;
}
}
else if ( ! strcmp ( req , " getstats " ) )
{ //1 [, one sign, 10 chars, one ], one comma
//FIXME: should be more than just a one-off.
unsigned int stats [ 256 ] , i , m ;
char * e = buffer ;
2020-05-14 15:50:26 +00:00
m = clientfuncs - > GetStats ( 0 , stats , countof ( stats ) ) ;
2016-07-12 00:40:13 +00:00
if ( ! m )
{
m = 0 ;
stats [ m + + ] = 0 ;
}
* e + + = ' [ ' ;
for ( i = 0 ; i < m ; i + + )
{
if ( i )
* e + + = ' , ' ;
sprintf ( e , " %i " , ( int ) stats [ i ] ) ;
e + = strlen ( e ) ;
}
* e + + = ' ] ' ;
* e = 0 ;
assert ( e < = buffer + buffersize ) ;
return true ;
}
else if ( ! strcmp ( req , " getseats " ) )
{
int i ;
char * e = buffer ;
int players [ MAX_SPLITS ] ;
int tracks [ MAX_SPLITS ] ;
2020-05-14 15:50:26 +00:00
int seats = clientfuncs - > GetLocalPlayerNumbers ( 0 , MAX_SPLITS , players , tracks ) ;
2016-07-12 00:40:13 +00:00
* e + + = ' [ ' ;
for ( i = 0 ; i < seats ; i + + )
{
if ( i )
* e + + = ' , ' ;
sprintf ( e , " { \" player \" :%i, \" track \" :%i} " , players [ i ] , tracks [ i ] ) ; e + = strlen ( e ) ;
}
* e + + = ' ] ' ;
* e = 0 ;
assert ( e < = buffer + buffersize ) ;
return true ;
}
else if ( ! strcmp ( req , " getserverinfo " ) )
{
char serverinfo [ 4096 ] ;
char * e = buffer ;
2022-06-19 15:18:23 +00:00
clientfuncs - > GetServerInfoRaw ( serverinfo , sizeof ( serverinfo ) ) ;
2016-07-12 00:40:13 +00:00
e = Info_JSONify ( serverinfo , e , buffer + buffersize - e - 1 ) ;
if ( e = = buffer ) e + + ;
* buffer = ' { ' ;
* e + + = ' } ' ;
* e = 0 ;
assert ( e < = buffer + buffersize ) ;
return true ;
}
else if ( ! strcmp ( req , " getplayers " ) )
{
unsigned int i ;
char * e = buffer ;
plugclientinfo_t info ;
* e + + = ' [ ' ;
for ( i = 0 ; ; i + + )
{
2020-05-14 15:50:26 +00:00
clientfuncs - > GetPlayerInfo ( i , & info ) ;
2016-07-12 00:40:13 +00:00
if ( buffer + buffersize - e - 1 < 100 )
break ;
if ( i )
* e + + = ' , ' ;
* e + + = ' { ' ;
//splurge the specific info
2020-05-14 15:50:26 +00:00
sprintf ( e , " \" frags \" :%i, \" ping \" :%i, \" pl \" :%i, \" active \" :%i, \" userid \" :%i " , info . frags , info . ping , info . pl , info . activetime , info . userid ) ;
2016-07-12 00:40:13 +00:00
e + = strlen ( e ) ;
//splurge the generic info (colours, name, team)
e = Info_JSONify ( info . userinfo , e , buffer + buffersize - e - 1 ) ;
* e + + = ' } ' ;
}
* e + + = ' ] ' ;
* e = 0 ;
assert ( e < = buffer + buffersize ) ;
return true ;
}
return false ;
}
2020-05-14 15:50:26 +00:00
static int CEF_CALLBACK browser_on_process_message_received ( cef_client_t * self , cef_browser_t * browser , cef_frame_t * frame , cef_process_id_t source_process , cef_process_message_t * message )
2016-07-12 00:40:13 +00:00
{
int handled = false ;
2016-07-15 12:26:24 +00:00
// browser_t *br = (browser_t*)((char*)self - offsetof(browser_t, request_handler));
2016-07-12 00:40:13 +00:00
cef_string_userfree_t msgnameunusable = message - > get_name ( message ) ;
cef_string_utf8_t name = { NULL } ;
cef_string_to_utf8 ( msgnameunusable - > str , msgnameunusable - > length , & name ) ;
if ( ! strcmp ( name . str , " fte_query " ) )
{
char buffer [ 8192 ] ;
int id1 , id2 ;
cef_process_message_t * reply ;
cef_string_utf8_t queryname = { NULL } ;
cef_string_t str = { NULL } ;
cef_list_value_t * args = message - > get_argument_list ( message ) ;
cef_string_userfree_t cmdunusable = args - > get_string ( args , 0 ) ;
2017-09-20 11:27:13 +00:00
cef_string_to_utf8 ( cmdunusable ? cmdunusable - > str : NULL , cmdunusable ? cmdunusable - > length : 0 , & queryname ) ;
2016-07-12 00:40:13 +00:00
id1 = args - > get_int ( args , 2 ) ;
id2 = args - > get_int ( args , 3 ) ;
cef_release ( args ) ;
reply = cef_process_message_create ( msgnameunusable ) ;
args = reply - > get_argument_list ( reply ) ;
args - > set_string ( args , 0 , cmdunusable ) ;
args - > set_int ( args , 2 , id1 ) ;
args - > set_int ( args , 3 , id2 ) ;
if ( browser_handle_query ( queryname . str , buffer , sizeof ( buffer ) ) )
{
str = makecefstring ( buffer ) ;
args - > set_string ( args , 1 , & str ) ;
2017-09-20 11:27:13 +00:00
cef_string_clear ( & str ) ;
2016-07-12 00:40:13 +00:00
}
else
args - > set_null ( args , 1 ) ;
cef_release ( args ) ;
cef_string_utf8_clear ( & queryname ) ;
2017-09-20 11:27:13 +00:00
if ( cmdunusable )
cef_string_userfree_free ( cmdunusable ) ;
2020-05-14 15:50:26 +00:00
frame - > send_process_message ( frame , source_process , reply ) ;
2016-07-12 00:40:13 +00:00
handled = true ;
}
cef_release ( message ) ;
cef_release ( browser ) ;
cef_string_utf8_clear ( & name ) ;
cef_string_userfree_free ( msgnameunusable ) ;
// if (messagerouter->OnProcessMessageReceived(browser, source_process, message))
// return true;
return handled ;
}
//render_handler methods
2020-05-14 15:50:26 +00:00
static void CEF_CALLBACK browser_get_view_rect ( cef_render_handler_t * self , cef_browser_t * browser , cef_rect_t * rect )
2016-07-12 00:40:13 +00:00
{
browser_t * br = ( browser_t * ) ( ( char * ) self - offsetof ( browser_t , render_handler ) ) ;
rect - > x = 0 ;
rect - > y = 0 ;
rect - > width = br - > desiredwidth ;
rect - > height = br - > desiredheight ;
cef_release ( browser ) ;
}
static void CEF_CALLBACK browser_on_paint ( cef_render_handler_t * self , cef_browser_t * browser , cef_paint_element_type_t type , size_t dirtyRectsCount , cef_rect_t const * dirtyRects , const void * buffer , int width , int height )
{
browser_t * br = ( browser_t * ) ( ( char * ) self - offsetof ( browser_t , render_handler ) ) ;
cef_release ( browser ) ;
//popups are gonna be so awkward...
if ( type ! = PET_VIEW )
return ;
2017-09-20 11:27:13 +00:00
/*
if ( pbocontext )
2016-07-12 00:40:13 +00:00
{
2017-09-20 11:27:13 +00:00
if ( ! PBO_Lock ( pbocontext , width , height , & lost , rgba ) )
return ;
if ( lost )
PBO_Update ( pbocontext , buffer , width , height , stride ) ;
else while ( dirtyRectsCount - - > 0 )
PBO_Update ( pbocontext , ( char * ) buffer + ( width * dirtyRects - > y + dirtyRects - > x ) * 4 ) , dirtyRects - > width , dirtyRects - > height , width * 4 ) ;
PBO_Unlock ( pbocontext ) ;
}
else
*/
if ( br - > videowidth ! = width | | br - > videoheight ! = height )
{ //copy the entire thing.
2016-07-12 00:40:13 +00:00
if ( br - > videodata )
free ( br - > videodata ) ;
br - > videowidth = width ;
br - > videoheight = height ;
br - > videodata = malloc ( width * height * 4 ) ;
memcpy ( br - > videodata , buffer , width * height * 4 ) ;
}
else
2017-09-20 11:27:13 +00:00
{ //try to save cpu time by copying only the dirty parts
2016-07-12 00:40:13 +00:00
while ( dirtyRectsCount - - > 0 )
{
if ( width = = dirtyRects - > width & & height = = dirtyRects - > height )
memcpy ( br - > videodata , buffer , width * height * 4 ) ;
else
{
int y ;
const unsigned int * src ;
unsigned int * dst ;
src = buffer ;
src + = width * dirtyRects - > y + dirtyRects - > x ;
dst = br - > videodata ;
dst + = width * dirtyRects - > y + dirtyRects - > x ;
for ( y = 0 ; y < dirtyRects - > height ; y + + )
{
memcpy ( dst , src , dirtyRects - > width * 4 ) ;
src + = width ;
dst + = width ;
}
}
dirtyRects + + ;
}
}
br - > updated = true ;
}
static void CEF_CALLBACK browser_on_before_close ( cef_life_span_handler_t * self , cef_browser_t * browser )
{
browser_t * br = ( browser_t * ) ( ( char * ) self - offsetof ( browser_t , life_span_handler ) ) ;
if ( br - > thebrowser )
{ //we may have already released our reference to this, if something else was blocking for some reason.
cef_release ( br - > thebrowser ) ;
br - > thebrowser = NULL ;
}
cef_release ( browser ) ;
}
2017-09-20 11:27:13 +00:00
//context_menu_handler methods
static void CEF_CALLBACK browser_on_before_context_menu ( struct _cef_context_menu_handler_t * self , struct _cef_browser_t * browser , struct _cef_frame_t * frame , struct _cef_context_menu_params_t * params , struct _cef_menu_model_t * model )
{
// browser_t *br = (browser_t*)((char*)self - offsetof(browser_t, context_menu_handler));
//wipe whatever elements libcef thinks it should add
model - > clear ( model ) ;
//don't bother adding any new ones.
cef_release ( browser ) ;
cef_release ( frame ) ;
cef_release ( params ) ;
cef_release ( model ) ;
}
2016-07-12 00:40:13 +00:00
//display_handler methods
//redirect console.log messages to quake's console, but only display them if we've got developer set.
2020-05-14 15:50:26 +00:00
static int CEF_CALLBACK browser_on_console_message ( cef_display_handler_t * self , cef_browser_t * browser , cef_log_severity_t level , const cef_string_t * message , const cef_string_t * source , int line )
2016-07-12 00:40:13 +00:00
{
cef_string_utf8_t u8_source = { NULL } ;
cef_string_utf8_t u8_message = { NULL } ;
if ( source )
cef_string_to_utf8 ( source - > str , source - > length , & u8_source ) ;
if ( message )
cef_string_to_utf8 ( message - > str , message - > length , & u8_message ) ;
Con_DPrintf ( " %s:%i: %s \n " , u8_source . str , line , u8_message . str ) ;
cef_string_utf8_clear ( & u8_source ) ;
cef_string_utf8_clear ( & u8_message ) ;
cef_release ( browser ) ;
return true ;
}
static void CEF_CALLBACK browser_on_title_change ( cef_display_handler_t * self , cef_browser_t * browser , const cef_string_t * title )
{
browser_t * br = ( browser_t * ) ( ( char * ) self - offsetof ( browser_t , display_handler ) ) ;
if ( title )
cef_string_to_utf8 ( title - > str , title - > length , & br - > currenttitle ) ;
else
cef_string_utf8_copy ( br - > currenturl . str , br - > currenturl . length , & br - > currenttitle ) ;
if ( br - > consolename )
2020-05-14 15:50:26 +00:00
confuncs - > SetConsoleString ( br - > consolename , " title " , br - > currenttitle . str ? br - > currenttitle . str : " " ) ;
2016-07-12 00:40:13 +00:00
cef_release ( browser ) ;
}
2017-09-20 11:27:13 +00:00
static void CEF_CALLBACK browser_on_favicon_urlchange ( cef_display_handler_t * self , cef_browser_t * browser , cef_string_list_t favicon )
{
browser_t * br = ( browser_t * ) ( ( char * ) self - offsetof ( browser_t , display_handler ) ) ;
cef_string_t str = { NULL } ;
if ( favicon )
{
//size_t opts = cef_string_list_size(favicon);
cef_string_list_value ( favicon , 0 , & str ) ;
}
cef_string_to_utf8 ( str . str , str . length , & br - > currenticon ) ;
cef_string_clear ( & str ) ;
if ( br - > consolename )
2020-05-14 15:50:26 +00:00
confuncs - > SetConsoleString ( br - > consolename , " icon " , br - > currenticon . str ? br - > currenticon . str : " " ) ;
2017-09-20 11:27:13 +00:00
cef_release ( browser ) ;
}
static void CEF_CALLBACK browser_on_fullscreenmode_change ( cef_display_handler_t * self , cef_browser_t * browser , int fullscreen )
{
browser_t * br = ( browser_t * ) ( ( char * ) self - offsetof ( browser_t , display_handler ) ) ;
br - > fullscreen = fullscreen ;
if ( br - > consolename )
2020-05-14 15:50:26 +00:00
confuncs - > SetConsoleFloat ( br - > consolename , " fullscreen " , br - > fullscreen ) ;
2017-09-20 11:27:13 +00:00
cef_release ( browser ) ;
}
2016-07-12 00:40:13 +00:00
static void CEF_CALLBACK browser_on_address_change ( cef_display_handler_t * self , cef_browser_t * browser , cef_frame_t * frame , const cef_string_t * url )
{
browser_t * br = ( browser_t * ) ( ( char * ) self - offsetof ( browser_t , display_handler ) ) ;
cef_string_to_utf8 ( url - > str , url - > length , & br - > currenturl ) ;
2017-09-20 11:27:13 +00:00
if ( br - > currenticon . length )
{
cef_string_utf8_clear ( & br - > currenticon ) ;
if ( br - > consolename )
2020-05-14 15:50:26 +00:00
confuncs - > SetConsoleString ( br - > consolename , " icon " , br - > currenticon . str ? br - > currenticon . str : " " ) ;
2017-09-20 11:27:13 +00:00
}
2016-07-12 00:40:13 +00:00
//FIXME: should probably make sure its the root frame
// Con_Printf("new url: %s\n", url.ToString().c_str());
cef_release ( browser ) ;
cef_release ( frame ) ;
}
static int CEF_CALLBACK browser_on_tooltip ( cef_display_handler_t * self , cef_browser_t * browser , cef_string_t * text )
{
browser_t * br = ( browser_t * ) ( ( char * ) self - offsetof ( browser_t , display_handler ) ) ;
if ( br - > consolename )
{
cef_string_utf8_t u8_text = { NULL } ;
cef_string_to_utf8 ( text - > str , text - > length , & u8_text ) ;
2020-05-14 15:50:26 +00:00
confuncs - > SetConsoleString ( br - > consolename , " tooltip " , u8_text . str ? u8_text . str : " " ) ;
2016-07-12 00:40:13 +00:00
cef_string_utf8_clear ( & u8_text ) ;
}
cef_release ( browser ) ;
return true ; //cef won't draw tooltips when running like this
}
static void CEF_CALLBACK browser_on_status_message ( cef_display_handler_t * self , cef_browser_t * browser , const cef_string_t * value )
{
browser_t * br = ( browser_t * ) ( ( char * ) self - offsetof ( browser_t , display_handler ) ) ;
if ( br - > consolename )
{
cef_string_utf8_t u8_value = { NULL } ;
if ( value )
cef_string_to_utf8 ( value - > str , value - > length , & u8_value ) ;
2020-05-14 15:50:26 +00:00
confuncs - > SetConsoleString ( br - > consolename , " footer " , u8_value . str ? u8_value . str : " " ) ;
2016-07-12 00:40:13 +00:00
cef_string_utf8_clear ( & u8_value ) ;
}
cef_release ( browser ) ;
}
//request_handler methods
2020-05-14 15:50:26 +00:00
static int CEF_CALLBACK browser_on_before_browse ( cef_request_handler_t * self , cef_browser_t * browser , cef_frame_t * frame , cef_request_t * request , int user_gesture , int is_redirect )
2016-07-12 00:40:13 +00:00
{
2016-07-15 12:26:24 +00:00
// browser_t *br = (browser_t*)((char*)self - offsetof(browser_t, request_handler));
2016-07-12 00:40:13 +00:00
cef_release ( browser ) ;
cef_release ( frame ) ;
cef_release ( request ) ;
2020-05-14 15:50:26 +00:00
return false ; //false = allow navigation, true = block
2016-07-12 00:40:13 +00:00
}
static void CEF_CALLBACK browser_on_render_process_terminated ( cef_request_handler_t * self , cef_browser_t * browser , cef_termination_status_t status )
{
browser_t * br = ( browser_t * ) ( ( char * ) self - offsetof ( browser_t , request_handler ) ) ;
if ( br - > videodata )
free ( br - > videodata ) ;
br - > videowidth = 1 ;
br - > videoheight = 1 ;
br - > videodata = malloc ( br - > videowidth * br - > videoheight * 4 ) ;
memset ( br - > videodata , 0 , br - > videowidth * br - > videoheight * 4 ) ;
br - > updated = true ;
cef_release ( browser ) ;
}
static browser_t * browser_create ( void )
{
browser_t * nb = malloc ( sizeof ( * nb ) ) ;
memset ( nb , 0 , sizeof ( * nb ) ) ;
nb - > refcount = 1 ;
# define browser_subs(sub) \
nb - > sub . base . add_ref = browser_ # # sub # # _addref ; \
2017-09-03 14:59:13 +00:00
nb - > sub . base . release = browser_ # # sub # # _release ; \
nb - > sub . base . has_one_ref = browser_ # # sub # # _hasoneref ; \
2016-07-12 00:40:13 +00:00
nb - > sub . base . size = sizeof ( nb - > sub ) ;
browser_subs ( client ) ;
browser_subs ( render_handler ) ;
browser_subs ( display_handler ) ;
browser_subs ( request_handler ) ;
browser_subs ( life_span_handler ) ;
2017-09-20 11:27:13 +00:00
browser_subs ( context_menu_handler ) ;
2016-07-12 00:40:13 +00:00
# undef browser_subs
2017-09-20 11:27:13 +00:00
nb - > client . get_context_menu_handler = browser_get_context_menu_handler ;
nb - > client . get_dialog_handler = NULL ;
nb - > client . get_display_handler = browser_get_display_handler ;
nb - > client . get_download_handler = NULL ;
nb - > client . get_drag_handler = NULL ;
nb - > client . get_find_handler = NULL ;
nb - > client . get_focus_handler = NULL ;
nb - > client . get_jsdialog_handler = NULL ;
nb - > client . get_keyboard_handler = NULL ;
2016-07-12 00:40:13 +00:00
nb - > client . get_life_span_handler = browser_get_life_span_handler ;
2017-09-20 11:27:13 +00:00
nb - > client . get_load_handler = NULL ;
2016-07-12 00:40:13 +00:00
nb - > client . get_render_handler = browser_get_render_handler ;
nb - > client . get_request_handler = browser_get_request_handler ;
nb - > client . on_process_message_received = browser_on_process_message_received ;
2017-09-20 11:27:13 +00:00
// nb->render_handler.get_accessibility_handler = NULL;
nb - > render_handler . get_root_screen_rect = NULL ;
2016-07-12 00:40:13 +00:00
nb - > render_handler . get_view_rect = browser_get_view_rect ;
2017-09-20 11:27:13 +00:00
nb - > render_handler . get_screen_point = NULL ;
nb - > render_handler . get_screen_info = NULL ;
nb - > render_handler . on_popup_show = NULL ;
nb - > render_handler . on_popup_size = NULL ;
2016-07-12 00:40:13 +00:00
nb - > render_handler . on_paint = browser_on_paint ;
2021-10-05 05:05:15 +00:00
// nb->render_handler.on_cursor_change = NULL;
2017-09-20 11:27:13 +00:00
nb - > render_handler . start_dragging = NULL ;
nb - > render_handler . update_drag_cursor = NULL ;
nb - > render_handler . on_scroll_offset_changed = NULL ;
// nb->render_handler.on_ime_composition_range_changed = NULL;
2016-07-12 00:40:13 +00:00
nb - > display_handler . on_address_change = browser_on_address_change ;
2017-09-20 11:27:13 +00:00
nb - > display_handler . on_title_change = browser_on_title_change ;
nb - > display_handler . on_favicon_urlchange = browser_on_favicon_urlchange ;
nb - > display_handler . on_fullscreen_mode_change = browser_on_fullscreenmode_change ;
2016-07-12 00:40:13 +00:00
nb - > display_handler . on_tooltip = browser_on_tooltip ;
nb - > display_handler . on_status_message = browser_on_status_message ;
2017-09-20 11:27:13 +00:00
nb - > display_handler . on_console_message = browser_on_console_message ;
2016-07-12 00:40:13 +00:00
nb - > request_handler . on_before_browse = browser_on_before_browse ;
2017-09-20 11:27:13 +00:00
nb - > request_handler . on_open_urlfrom_tab = NULL ;
2020-05-14 15:50:26 +00:00
// nb->request_handler.on_before_resource_load = NULL;
// nb->request_handler.get_resource_handler = NULL;
// nb->request_handler.on_resource_redirect = NULL;
// nb->request_handler.on_resource_response = NULL;
// nb->request_handler.get_resource_response_filter = NULL;
// nb->request_handler.on_resource_load_complete = NULL;
2017-09-20 11:27:13 +00:00
nb - > request_handler . get_auth_credentials = NULL ;
nb - > request_handler . on_quota_request = NULL ;
2020-05-14 15:50:26 +00:00
// nb->request_handler.on_protocol_execution = NULL; //FIXME: should implement.
2017-09-20 11:27:13 +00:00
nb - > request_handler . on_certificate_error = NULL ;
// nb->request_handler.on_select_client_certificate = NULL; //we have no such certs
nb - > request_handler . on_plugin_crashed = NULL ;
nb - > request_handler . on_render_view_ready = NULL ;
2016-07-12 00:40:13 +00:00
nb - > request_handler . on_render_process_terminated = browser_on_render_process_terminated ;
2017-09-20 11:27:13 +00:00
nb - > life_span_handler . on_before_popup = NULL ;
nb - > life_span_handler . on_after_created = NULL ;
nb - > life_span_handler . do_close = NULL ;
2016-07-12 00:40:13 +00:00
nb - > life_span_handler . on_before_close = browser_on_before_close ;
2017-09-20 11:27:13 +00:00
nb - > context_menu_handler . on_before_context_menu = browser_on_before_context_menu ;
nb - > context_menu_handler . run_context_menu = NULL ; //fixme: implement a working context menu somehow
nb - > context_menu_handler . on_context_menu_command = NULL ; //for custom context things, like opening in a new window...
nb - > context_menu_handler . on_context_menu_dismissed = NULL ; //
2016-07-12 00:40:13 +00:00
nb - > desiredwidth = 640 ;
nb - > desiredheight = 480 ;
if ( newconsole )
nb - > consolename = strdup ( newconsole ) ;
else
nb - > consolename = NULL ;
//make it white until there's actually something to draw
nb - > videowidth = 1 ;
nb - > videoheight = 1 ;
nb - > videodata = malloc ( nb - > videowidth * nb - > videoheight * 4 ) ;
* ( int * ) nb - > videodata = 0x00ffffff ;
memset ( nb - > videodata , 0xff , nb - > videowidth * nb - > videoheight * 4 ) ;
nb - > updated = true ;
numbrowsers + + ;
return nb ;
}
//request contexts are per-session things. eg, incognito tabs would have their own private instance
static cef_request_context_t * request_context ;
static cef_request_context_handler_t request_context_handler ;
//request_context_handler methods
2020-05-14 15:50:26 +00:00
static int CEF_CALLBACK request_context_handler_on_before_plugin_load ( cef_request_context_handler_t * self , const cef_string_t * mime_type , const cef_string_t * plugin_url , int is_main_frame , const cef_string_t * top_origin_url , cef_web_plugin_info_t * plugin_info , cef_plugin_policy_t * plugin_policy )
2016-07-12 00:40:13 +00:00
{
// Con_DPrintf("%s (%s), \"%s\" \"%s\" \"%s\" \"%s\"\n", policy_url.ToString().c_str(), url.ToString().c_str(),
// info->GetName().ToString().c_str(), info->GetPath().ToString().c_str(), info->GetVersion().ToString().c_str(), info->GetDescription().ToString().c_str());
* plugin_policy = PLUGIN_POLICY_BLOCK ; //block by default (user can manually override supposedly). most plugins are unlikely to cope well with our offscreen rendering stuff, and flash sucks.
cef_release ( plugin_info ) ;
2016-07-17 18:41:01 +00:00
2020-05-14 15:50:26 +00:00
if ( ! cef_allowplugins - > value )
2016-07-12 00:40:13 +00:00
{
* plugin_policy = PLUGIN_POLICY_DISABLE ;
// Con_Printf("Blocking plugin: %s (%s)\n", info->GetName().ToString().c_str(), url.ToString().c_str());
}
else
return false ; //false to use the 'recommended' policy
return true ;
}
//there's only one of these, so I'm not going to bother making separate objects for all of the interfaces, nor ref counting
static cef_app_t app ;
static cef_browser_process_handler_t browser_process_handler ;
static cef_render_process_handler_t render_process_handler ;
static cef_v8handler_t v8handler_query ; //window.fte_query
static cef_scheme_handler_factory_t scheme_handler_factory ;
static cef_browser_process_handler_t * CEF_CALLBACK app_get_browser_process_handler ( cef_app_t * self )
{
//cef_addref(&browser_process_handler);
return & browser_process_handler ;
}
static cef_render_process_handler_t * CEF_CALLBACK app_get_render_process_handler ( cef_app_t * self )
{
//cef_addref(&render_process_handler);
return & render_process_handler ;
}
static void CEF_CALLBACK app_on_register_custom_schemes ( struct _cef_app_t * self , cef_scheme_registrar_t * registrar )
{
cef_string_t fte = makecefstring ( " fte " ) ;
2020-05-14 15:50:26 +00:00
registrar - > add_custom_scheme ( registrar , & fte , CEF_SCHEME_OPTION_NONE
| CEF_SCHEME_OPTION_STANDARD
/*|CEF_SCHEME_OPTION_LOCAL*/
| CEF_SCHEME_OPTION_DISPLAY_ISOLATED
| CEF_SCHEME_OPTION_SECURE
| CEF_SCHEME_OPTION_CORS_ENABLED
/*|CEF_SCHEME_OPTION_CSP_BYPASSING*/
/*|CEF_SCHEME_OPTION_FETCH_ENABLED*/
2017-09-03 14:59:13 +00:00
) ;
2016-07-12 00:40:13 +00:00
cef_string_clear ( & fte ) ;
}
static void CEF_CALLBACK browser_process_handler_on_context_initialized ( cef_browser_process_handler_t * self )
{
cef_string_t fte = makecefstring ( " fte " ) ;
cef_register_scheme_handler_factory ( & fte , NULL , & scheme_handler_factory ) ;
cef_string_clear ( & fte ) ;
}
static void CEF_CALLBACK browser_process_handler_on_before_child_process_launch ( cef_browser_process_handler_t * self , cef_command_line_t * command_line )
{
2021-10-05 05:05:15 +00:00
char * arg = " --plugwrapper " ;
char * funcname = " CefSubprocessInit " ;
2016-07-12 00:40:13 +00:00
cef_string_t cefisannoying = { NULL } ;
cef_string_from_utf8 ( arg , strlen ( arg ) , & cefisannoying ) ;
command_line - > append_argument ( command_line , & cefisannoying ) ;
2021-10-05 05:05:15 +00:00
cef_string_from_utf8 ( plugname , strlen ( plugname ) , & cefisannoying ) ;
command_line - > append_argument ( command_line , & cefisannoying ) ;
cef_string_from_utf8 ( funcname , strlen ( funcname ) , & cefisannoying ) ;
command_line - > append_argument ( command_line , & cefisannoying ) ;
2016-07-12 00:40:13 +00:00
// MessageBoxW(NULL, command_line->GetCommandLineString().c_str(), L"CEF", 0);
2021-10-05 05:05:15 +00:00
cef_string_clear ( & cefisannoying ) ;
2016-07-12 00:40:13 +00:00
cef_release ( command_line ) ;
}
static void CEF_CALLBACK render_process_handler_on_context_created ( cef_render_process_handler_t * self , cef_browser_t * browser , cef_frame_t * frame , cef_v8context_t * context )
{
cef_v8value_t * jswindow = context - > get_global ( context ) ;
2021-10-05 05:05:15 +00:00
//eg: window.fte_query("getstats", function(req,res){console.log("health: "+JSON.parse(res)[0/*STAT_HEALTH*/]);});
cef_string_t key = makecefstring ( " fte_query " ) ;
2016-07-12 00:40:13 +00:00
jswindow - > set_value_bykey ( jswindow , & key , cef_v8value_create_function ( & key , & v8handler_query ) , V8_PROPERTY_ATTRIBUTE_READONLY | V8_PROPERTY_ATTRIBUTE_DONTENUM | V8_PROPERTY_ATTRIBUTE_DONTDELETE ) ;
cef_string_clear ( & key ) ;
cef_release ( browser ) ;
cef_release ( frame ) ;
cef_release ( context ) ;
}
//only use these in the 'renderer' thread / javascript thread.
typedef struct activequery_s
{
cef_v8value_t * callbackfunc ; //this is the js function to call when the result is available.
cef_v8context_t * context ;
cef_frame_t * frame ;
int64 queryid ;
struct activequery_s * next ;
} activequery_t ;
static activequery_t * queries ;
static int64 next_queryid ;
typedef struct
{
cef_task_t task ;
cef_string_userfree_t request ;
cef_string_userfree_t result ;
int64 queryid ;
atomic_uint32_t refcount ;
} queryresponse_t ;
2020-05-14 15:50:26 +00:00
static void CEF_CALLBACK queryresponse_addref ( cef_base_ref_counted_t * self )
2016-07-12 00:40:13 +00:00
{
queryresponse_t * qr = ( queryresponse_t * ) ( ( char * ) self - offsetof ( queryresponse_t , task . base ) ) ;
atomic_fetch_add ( & qr - > refcount , 1 ) ;
}
2020-05-14 15:50:26 +00:00
static int CEF_CALLBACK queryresponse_release ( cef_base_ref_counted_t * self )
2016-07-12 00:40:13 +00:00
{
queryresponse_t * qr = ( queryresponse_t * ) ( ( char * ) self - offsetof ( queryresponse_t , task . base ) ) ;
if ( atomic_fetch_sub ( & qr - > refcount , 1 ) = = 1 )
{
if ( qr - > request )
cef_string_userfree_free ( qr - > request ) ;
if ( qr - > result )
cef_string_userfree_free ( qr - > result ) ;
free ( qr ) ;
return true ;
}
return false ;
}
static void CEF_CALLBACK queryresponse_execute ( struct _cef_task_t * self )
{ //lethal injection.
queryresponse_t * qr = ( queryresponse_t * ) ( ( char * ) self - offsetof ( queryresponse_t , task . base ) ) ;
activequery_t * * link , * q ;
for ( link = & queries ; ( q = * link ) ; link = & ( * link ) - > next )
{
if ( q - > queryid = = qr - > queryid )
{
if ( q - > callbackfunc )
{
cef_v8value_t * args [ 2 ] = { cef_v8value_create_string ( qr - > request ) , cef_v8value_create_string ( qr - > result ) } ;
cef_v8value_t * r ;
cef_addref ( q - > context ) ;
r = q - > callbackfunc - > execute_function_with_context ( q - > callbackfunc , q - > context , NULL , 2 , args ) ;
cef_release ( r ) ;
}
//and clear up the request context too.
* link = q - > next ;
if ( q - > callbackfunc )
cef_release ( q - > callbackfunc ) ;
cef_release ( q - > frame ) ;
cef_release ( q - > context ) ;
free ( q ) ;
return ;
}
}
}
static void CEF_CALLBACK render_process_handler_on_context_released ( cef_render_process_handler_t * self , cef_browser_t * browser , cef_frame_t * frame , cef_v8context_t * context )
{
activequery_t * * link , * q ;
for ( link = & queries ; ( q = * link ) ; )
{
if ( q - > context = = context ) // && q->frame == frame)
{
* link = q - > next ;
if ( q - > callbackfunc )
cef_release ( q - > callbackfunc ) ;
cef_release ( q - > frame ) ;
cef_release ( q - > context ) ;
free ( q ) ;
continue ;
}
link = & ( * link ) - > next ;
}
cef_release ( browser ) ;
cef_release ( frame ) ;
cef_release ( context ) ;
}
/*javascript methods for the guest code to call*/
static cef_v8value_t * makev8string ( char * str )
{
cef_v8value_t * r ;
cef_string_t cs = makecefstring ( str ) ;
r = cef_v8value_create_string ( & cs ) ;
cef_string_clear ( & cs ) ;
return r ;
}
static int CEF_CALLBACK fsfunc_execute ( cef_v8handler_t * self , const cef_string_t * name , cef_v8value_t * object , size_t argumentsCount , cef_v8value_t * const * arguments , cef_v8value_t * * retval , cef_string_t * exception )
{
cef_process_message_t * msg ;
cef_list_value_t * args ;
cef_v8context_t * v8ctx = cef_v8context_get_current_context ( ) ;
cef_browser_t * browser = v8ctx - > get_browser ( v8ctx ) ;
cef_frame_t * frame = v8ctx - > get_frame ( v8ctx ) ;
2016-07-15 12:26:24 +00:00
// int64 frame_id = frame->get_identifier(frame);
2016-07-12 00:40:13 +00:00
// cef_string_t key = {L"omgwtfitkindaworks"};
// key.length = wcslen(key.str);
// *exception = makecefstring("SOME KIND OF EXCEPTION!");
2017-09-20 11:27:13 +00:00
* retval = makev8string ( " " ) ;
2016-07-12 00:40:13 +00:00
if ( argumentsCount )
{
cef_string_userfree_t setting = arguments [ 0 ] - > get_string_value ( arguments [ 0 ] ) ;
activequery_t * q = malloc ( sizeof ( * q ) ) ;
memset ( q , 0 , sizeof ( * q ) ) ;
q - > context = v8ctx ; //hold on to these
q - > frame = frame ;
q - > queryid = + + next_queryid ;
q - > next = queries ;
q - > callbackfunc = arguments [ 1 ] ;
queries = q ;
cef_addref ( q - > callbackfunc ) ;
msg = cef_process_message_create ( name ) ;
args = msg - > get_argument_list ( msg ) ;
args - > set_string ( args , 0 , setting ) ;
args - > set_null ( args , 1 ) ;
args - > set_int ( args , 2 , q - > queryid & 0xffffffff ) ;
args - > set_int ( args , 3 , ( q - > queryid > > 32 ) & 0xffffffff ) ;
cef_release ( args ) ;
2020-05-14 15:50:26 +00:00
frame - > send_process_message ( frame , PID_BROWSER , msg ) ;
2016-07-12 00:40:13 +00:00
2017-09-20 11:27:13 +00:00
if ( setting )
cef_string_userfree_free ( setting ) ;
2016-07-12 00:40:13 +00:00
}
else
{
cef_release ( frame ) ;
cef_release ( v8ctx ) ;
}
cef_release ( browser ) ;
return 1 ;
}
2020-05-14 15:50:26 +00:00
static int CEF_CALLBACK render_process_handler_on_process_message_received ( cef_render_process_handler_t * self , cef_browser_t * browser , cef_frame_t * frame , cef_process_id_t source_process , cef_process_message_t * message )
2016-07-12 00:40:13 +00:00
{
int handled = false ;
2016-07-15 12:26:24 +00:00
// browser_t *br = (browser_t*)((char*)self - offsetof(browser_t, request_handler));
2016-07-12 00:40:13 +00:00
cef_string_userfree_t msgnameunusable = message - > get_name ( message ) ;
cef_string_utf8_t name = { NULL } ;
cef_string_to_utf8 ( msgnameunusable - > str , msgnameunusable - > length , & name ) ;
if ( ! strcmp ( name . str , " fte_query " ) )
{
cef_list_value_t * args = message - > get_argument_list ( message ) ;
queryresponse_t * task = malloc ( sizeof ( * task ) ) ;
memset ( task , 0 , sizeof ( * task ) ) ;
task - > refcount = 1 ;
task - > task . base . size = sizeof ( task - > task ) ;
task - > task . base . add_ref = queryresponse_addref ;
task - > task . base . release = queryresponse_release ;
task - > task . execute = queryresponse_execute ;
task - > request = args - > get_string ( args , 0 ) ;
task - > result = args - > get_string ( args , 1 ) ;
task - > queryid = args - > get_int ( args , 2 ) | ( ( int64 ) args - > get_int ( args , 3 ) < < 32u ) ;
cef_release ( args ) ;
cef_post_task ( TID_RENDERER , & task - > task ) ;
handled = true ;
}
cef_string_utf8_clear ( & name ) ;
cef_string_userfree_free ( msgnameunusable ) ;
cef_release ( browser ) ;
cef_release ( message ) ;
return handled ;
}
/* fte://file/path scheme handler */
typedef struct
{
cef_resource_handler_t rh ;
atomic_uint32_t refcount ;
vfsfile_t * fh ;
char * data ;
size_t offset ;
size_t datasize ;
unsigned int resultcode ;
2017-09-20 11:27:13 +00:00
char * responseheaders ;
2016-07-12 00:40:13 +00:00
} fteresource_t ;
2020-05-14 15:50:26 +00:00
static void CEF_CALLBACK resource_handler_addref ( cef_base_ref_counted_t * self )
2016-07-12 00:40:13 +00:00
{
fteresource_t * rh = ( fteresource_t * ) ( ( char * ) self - offsetof ( fteresource_t , rh . base ) ) ;
atomic_fetch_add ( & rh - > refcount , 1 ) ;
}
2020-05-14 15:50:26 +00:00
static int CEF_CALLBACK resource_handler_release ( cef_base_ref_counted_t * self )
2016-07-12 00:40:13 +00:00
{
fteresource_t * rh = ( fteresource_t * ) ( ( char * ) self - offsetof ( fteresource_t , rh . base ) ) ;
if ( atomic_fetch_sub ( & rh - > refcount , 1 ) = = 1 )
{
if ( rh - > fh )
VFS_CLOSE ( rh - > fh ) ;
if ( rh - > data )
free ( rh - > data ) ;
2017-09-20 11:27:13 +00:00
free ( rh - > responseheaders ) ;
2016-07-12 00:40:13 +00:00
free ( rh ) ;
return true ;
}
return false ;
}
2017-09-20 11:27:13 +00:00
static void res_catfield_l ( char * * const orig , const char * key , int kl , const char * val , int vl )
{
size_t ol = * orig ? strlen ( * orig ) : 0 ;
char * n ;
if ( ol )
{
n = malloc ( ol + 1 + kl + 1 + vl + 1 ) ;
memcpy ( n , * orig , ol ) ;
n [ ol + + ] = ' \n ' ;
}
else
n = malloc ( kl + 1 + vl + 1 ) ;
memcpy ( n + ol , key , kl ) ;
ol + = kl ;
n [ ol + + ] = ' \n ' ;
memcpy ( n + ol , val , vl ) ;
ol + = vl ;
n [ ol + + ] = 0 ;
free ( * orig ) ;
* orig = n ;
}
static void res_catfield ( char * * const orig , const char * key , const char * val )
{
res_catfield_l ( orig , key , strlen ( key ) , val , strlen ( val ) ) ;
}
static void res_catfield_csuf ( char * * const orig , const char * key , cef_string_userfree_t cs )
{
cef_string_utf8_t u8 = { NULL } ;
cef_string_to_utf8 ( cs - > str , cs - > length , & u8 ) ;
res_catfield_l ( orig , key , strlen ( key ) , u8 . str , u8 . length ) ;
cef_string_utf8_clear ( & u8 ) ;
}
static void res_catfield_cs ( char * * const orig , cef_string_t * key , cef_string_t * val )
{
cef_string_utf8_t keyu8 = { NULL } ;
cef_string_utf8_t valu8 = { NULL } ;
cef_string_to_utf8 ( key - > str , key - > length , & keyu8 ) ;
cef_string_to_utf8 ( val - > str , val - > length , & valu8 ) ;
res_catfield_l ( orig , keyu8 . str , keyu8 . length , valu8 . str , valu8 . length ) ;
cef_string_utf8_clear ( & keyu8 ) ;
cef_string_utf8_clear ( & valu8 ) ;
}
2016-07-12 00:40:13 +00:00
static int CEF_CALLBACK resource_handler_process_request ( cef_resource_handler_t * self , cef_request_t * request , cef_callback_t * callback )
{
fteresource_t * rh = ( fteresource_t * ) ( ( char * ) self - offsetof ( fteresource_t , rh ) ) ;
2017-09-20 11:27:13 +00:00
cef_string_userfree_t url = request - > get_url ( request ) , method ;
cef_post_data_t * postdata ;
size_t numelements ;
cef_post_data_element_t * elements [ 1 ] ;
size_t postsize ;
char * postbytes ;
char * q ;
char * e ;
cef_string_utf8_t u8_url = { NULL } , u8 = { NULL } ;
2016-07-12 00:40:13 +00:00
cef_string_t ext = { NULL } ;
cef_string_to_utf8 ( url - > str , url - > length , & u8_url ) ;
rh - > resultcode = 404 ;
//hack at the url to hide the
2017-09-20 11:27:13 +00:00
q = strchr ( u8_url . str , ' ? ' ) ;
if ( q )
* q = 0 ;
for ( e = q ? q : u8_url . str + strlen ( u8_url . str ) ; e > u8_url . str ; )
2016-07-12 00:40:13 +00:00
{
2017-09-20 11:27:13 +00:00
e - - ;
if ( * e = = ' / ' )
break ; //no extension
if ( * e = = ' . ' )
2016-07-12 00:40:13 +00:00
{
2017-09-20 11:27:13 +00:00
e + + ;
cef_string_from_utf8 ( e , strlen ( e ) , & ext ) ;
break ;
2016-07-12 00:40:13 +00:00
}
}
2017-09-20 11:27:13 +00:00
res_catfield ( & rh - > responseheaders , " Access-Control-Allow-Origin " , " fte://data " ) ;
res_catfield ( & rh - > responseheaders , " Access-Control-Allow-Origin " , " fte://csqc " ) ;
res_catfield ( & rh - > responseheaders , " Access-Control-Allow-Origin " , " fte://ssqc " ) ;
res_catfield ( & rh - > responseheaders , " Access-Control-Allow-Origin " , " fte://menu " ) ;
2016-07-12 00:40:13 +00:00
//sandboxed to the same dir that qc can fopen/fwrite.
//(also blocks any fancy http:// parsing that an engine might do)
if ( ! strncmp ( u8_url . str , " fte://data/ " , 11 ) )
{
2020-05-14 15:50:26 +00:00
rh - > fh = fsfuncs - > OpenVFS ( u8_url . str + 6 , " rb " , FS_GAME ) ;
2016-07-12 00:40:13 +00:00
if ( rh - > fh )
{
cef_string_userfree_t mt = cef_get_mime_type ( & ext ) ;
2017-09-20 11:27:13 +00:00
if ( mt )
{
res_catfield_csuf ( & rh - > responseheaders , " Content-Type " , mt ) ;
cef_string_userfree_free ( mt ) ;
}
2016-07-12 00:40:13 +00:00
rh - > resultcode = 200 ;
}
else
{
rh - > resultcode = 404 ;
2017-09-20 11:27:13 +00:00
res_catfield ( & rh - > responseheaders , " Content-Type " , " text/html " ) ;
2016-07-12 00:40:13 +00:00
rh - > data = strdup ( " <html><style type= \" text/css \" >body {background-color: lightblue;}</style><title>not found</title>File not found within game filesystem.</html> " ) ;
rh - > datasize = strlen ( rh - > data ) ;
}
}
else if ( ! strncmp ( u8_url . str , " fte://ssqc/ " , 11 ) | | ! strncmp ( u8_url . str , " fte://csqc/ " , 11 ) | | ! strncmp ( u8_url . str , " fte://menu/ " , 11 ) )
{
struct pubprogfuncs_s * progs ;
const char * page ;
2017-09-20 11:27:13 +00:00
const char * respheaders = NULL ;
const char * reqheaders = NULL ;
2016-07-12 00:40:13 +00:00
if ( ext . str )
{
cef_string_userfree_t mt = cef_get_mime_type ( & ext ) ;
if ( mt )
{
2017-09-20 11:27:13 +00:00
res_catfield_csuf ( ( char * * ) & respheaders , " Content-Type " , mt ) ;
2016-07-12 00:40:13 +00:00
cef_string_userfree_free ( mt ) ;
}
}
2017-09-20 11:27:13 +00:00
if ( q )
* q = ' ? ' ; //put it back so the qc can get the full url.
2016-07-12 00:40:13 +00:00
rh - > resultcode = 404 ;
2020-05-14 15:50:26 +00:00
if ( ! strncmp ( u8_url . str , " fte://ssqc/ " , 11 ) )
progs = plugfuncs - > GetEngineInterface ( " SSQCVM " , sizeof ( * progs ) ) ; //WARNING: goes direct rather than via the server, so basically single-player only.
2016-07-12 00:40:13 +00:00
else if ( ! strncmp ( u8_url . str , " fte://csqc/ " , 11 ) )
2020-05-14 15:50:26 +00:00
progs = plugfuncs - > GetEngineInterface ( " CSQCVM " , sizeof ( * progs ) ) ;
2016-07-12 00:40:13 +00:00
else if ( ! strncmp ( u8_url . str , " fte://menu/ " , 11 ) )
2020-05-14 15:50:26 +00:00
progs = plugfuncs - > GetEngineInterface ( " MenuQCVM " , sizeof ( * progs ) ) ;
2016-07-12 00:40:13 +00:00
else
progs = NULL ;
if ( progs )
{
func_t func = progs - > FindFunction ( progs , " Cef_GeneratePage " , PR_ANY ) ;
if ( func )
{
void * pr_globals = PR_globals ( progs , PR_CURRENT ) ;
( ( string_t * ) pr_globals ) [ OFS_PARM0 ] = progs - > TempString ( progs , u8_url . str + 11 ) ;
2017-09-20 11:27:13 +00:00
method = request - > get_method ( request ) ;
cef_string_to_utf8 ( method - > str , method - > length , & u8 ) ;
( ( string_t * ) pr_globals ) [ OFS_PARM1 ] = progs - > TempString ( progs , u8 . str ) ;
cef_string_userfree_free ( method ) ;
cef_string_utf8_clear ( & u8 ) ;
postdata = request - > get_post_data ( request ) ;
if ( postdata )
{
numelements = countof ( elements ) ;
memset ( elements , 0 , sizeof ( elements ) ) ;
postdata - > get_elements ( postdata , & numelements , elements ) ;
postsize = elements [ 0 ] - > get_bytes_count ( elements [ 0 ] ) ;
postbytes = malloc ( postsize + 1 ) ;
elements [ 0 ] - > get_bytes ( elements [ 0 ] , postsize , postbytes ) ;
postbytes [ postsize ] = 0 ;
( ( string_t * ) pr_globals ) [ OFS_PARM2 ] = progs - > TempString ( progs , postbytes ) ;
free ( postbytes ) ;
cef_release ( elements [ 0 ] ) ;
}
else
( ( string_t * ) pr_globals ) [ OFS_PARM2 ] = 0 ;
{
size_t i , elems ;
cef_string_t key = { NULL } , val = { NULL } ;
cef_string_multimap_t hmap = cef_string_multimap_alloc ( ) ;
request - > get_header_map ( request , hmap ) ;
elems = cef_string_multimap_size ( hmap ) ;
for ( i = 0 ; i < elems ; i + + )
{
cef_string_multimap_key ( hmap , i , & key ) ;
cef_string_multimap_key ( hmap , i , & val ) ;
res_catfield_cs ( & rh - > responseheaders , & key , & val ) ;
cef_string_clear ( & key ) ;
cef_string_clear ( & val ) ;
}
cef_string_multimap_free ( hmap ) ;
}
( ( string_t * ) pr_globals ) [ OFS_PARM3 ] = reqheaders ? progs - > TempString ( progs , reqheaders ) : 0 ; //request heders
( ( string_t * ) pr_globals ) [ OFS_PARM4 ] = rh - > responseheaders ? progs - > TempString ( progs , rh - > responseheaders ) : 0 ; //response headers
( ( string_t * ) pr_globals ) [ OFS_PARM5 ] = 0 ;
( ( string_t * ) pr_globals ) [ OFS_PARM6 ] = 0 ;
( ( string_t * ) pr_globals ) [ OFS_PARM7 ] = 0 ;
2016-07-12 00:40:13 +00:00
progs - > ExecuteProgram ( progs , func ) ;
if ( ( ( string_t * ) pr_globals ) [ OFS_RETURN ] )
{
page = progs - > StringToNative ( progs , ( ( string_t * ) pr_globals ) [ OFS_RETURN ] ) ;
2017-09-20 11:27:13 +00:00
respheaders = progs - > StringToNative ( progs , ( ( string_t * ) pr_globals ) [ OFS_PARM4 ] ) ;
2016-07-12 00:40:13 +00:00
rh - > resultcode = 200 ;
}
else
page = " <html><style type= \" text/css \" >body {background-color: lightblue;}</style><title>not found</title>Cef_GeneratePage returned null</html> " ;
}
else
page = " <html><style type= \" text/css \" >body {background-color: lightblue;}</style><title>not found</title>Cef_GeneratePage not implemented by mod</html> " ;
}
else
page = " <html><style type= \" text/css \" >body {background-color: lightblue;}</style><title>not found</title>That QCVM is not running</html> " ;
2017-09-20 11:27:13 +00:00
if ( * respheaders = = ' \n ' )
respheaders + + ;
rh - > responseheaders = strdup ( respheaders ) ;
2016-07-12 00:40:13 +00:00
//FIXME: only return any data if we were successful OR the mime is text/html
rh - > data = strdup ( page ) ;
rh - > datasize = strlen ( rh - > data ) ;
}
else
{
rh - > resultcode = 403 ;
2017-09-20 11:27:13 +00:00
res_catfield ( & rh - > responseheaders , " Content-Type " , " text/html " ) ;
2016-07-12 00:40:13 +00:00
rh - > data = strdup ( " <html><style type= \" text/css \" >body {background-color: lightblue;}</style><title>forbidden</title><a href= \" fte://data/index.html \" >Try here</a> <a href= \" fte://csqc/index.html \" >Or try here</a></html> " ) ;
rh - > datasize = strlen ( rh - > data ) ;
}
cef_string_userfree_free ( url ) ;
cef_string_utf8_clear ( & u8_url ) ;
callback - > cont ( callback ) ; //headers are now known... should be delayed.
cef_release ( callback ) ;
cef_release ( request ) ;
return 1 ; //failure is reported as an http error code rather than an exception
}
2017-09-20 11:27:13 +00:00
static char * strseps ( char * str , char * chars )
{ //find the next separator
char * best = str + strlen ( str ) ;
char * c ;
if ( * str )
while ( * chars )
{
c = strchr ( str , * chars + + ) ;
if ( c & & c < best )
best = c ;
}
return best ;
}
2016-07-12 00:40:13 +00:00
static void CEF_CALLBACK resource_handler_get_response_headers ( cef_resource_handler_t * self , cef_response_t * response , int64 * response_length , cef_string_t * redirectUrl )
{
fteresource_t * rh = ( fteresource_t * ) ( ( char * ) self - offsetof ( fteresource_t , rh ) ) ;
2017-09-20 11:27:13 +00:00
cef_string_multimap_t * hmap ;
cef_string_t key = { NULL } , val = { NULL } ;
2016-07-12 00:40:13 +00:00
if ( rh - > fh )
* response_length = VFS_GETLEN ( rh - > fh ) ;
else if ( rh - > data )
* response_length = rh - > datasize ;
else
* response_length = - 1 ;
2017-09-20 11:27:13 +00:00
hmap = cef_string_multimap_alloc ( ) ;
if ( rh - > responseheaders )
{
char * start ;
char * sep ;
char * nl ;
for ( start = rh - > responseheaders ; * start ; )
{
sep = strseps ( start , " : \n " ) ;
nl = strseps ( sep + 1 , " \n " ) ;
cef_string_from_utf8 ( start , sep - start , & key ) ;
if ( * sep )
sep + + ;
cef_string_from_utf8 ( sep , nl - sep , & val ) ;
cef_string_multimap_append ( hmap , & key , & val ) ;
if ( * nl )
start = nl + 1 ;
else
break ;
}
}
cef_string_multimap_append ( hmap , makecefstringptr ( " Access-Control-Allow-Origin " , & key ) , makecefstringptr ( " fte://data " , & val ) ) ;
response - > set_header_map ( response , hmap ) ;
// response->set_mime_type(response, &rh->mimetype);
2016-07-12 00:40:13 +00:00
response - > set_status ( response , rh - > resultcode ) ;
2017-09-20 11:27:13 +00:00
cef_string_clear ( & key ) ;
cef_string_clear ( & val ) ;
2016-07-12 00:40:13 +00:00
cef_release ( response ) ;
}
static int CEF_CALLBACK resource_handler_read_response ( cef_resource_handler_t * self , void * data_out , int bytes_to_read , int * bytes_read , cef_callback_t * callback )
{
fteresource_t * rh = ( fteresource_t * ) ( ( char * ) self - offsetof ( fteresource_t , rh ) ) ;
if ( rh - > fh )
* bytes_read = VFS_READ ( rh - > fh , data_out , bytes_to_read ) ;
else if ( rh - > data )
{
if ( bytes_to_read > rh - > datasize - rh - > offset )
bytes_to_read = rh - > datasize - rh - > offset ;
* bytes_read = bytes_to_read ;
memcpy ( data_out , rh - > data + rh - > offset , bytes_to_read ) ;
rh - > offset + = bytes_to_read ;
}
else
* bytes_read = 0 ;
//callback->cont(callback); //headers are now known... should be delayed.
cef_release ( callback ) ;
if ( * bytes_read < = 0 )
{
* bytes_read = 0 ;
return 0 ;
}
return true ; //more to come
}
static void CEF_CALLBACK resource_handler_cancel ( cef_resource_handler_t * self )
{
fteresource_t * rh = ( fteresource_t * ) ( ( char * ) self - offsetof ( fteresource_t , rh ) ) ;
if ( rh - > fh )
VFS_CLOSE ( rh - > fh ) ;
rh - > fh = NULL ;
if ( rh - > data )
free ( rh - > data ) ;
rh - > data = NULL ;
rh - > offset = 0 ;
rh - > datasize = 0 ;
}
static cef_resource_handler_t * CEF_CALLBACK scheme_handler_factory_create ( cef_scheme_handler_factory_t * self , cef_browser_t * browser , cef_frame_t * frame , const cef_string_t * scheme_name , cef_request_t * request )
{
fteresource_t * rh = malloc ( sizeof ( * rh ) ) ;
memset ( rh , 0 , sizeof ( * rh ) ) ;
rh - > rh . base . size = sizeof ( * rh ) ;
rh - > rh . base . add_ref = resource_handler_addref ;
rh - > rh . base . release = resource_handler_release ;
rh - > rh . process_request = resource_handler_process_request ;
rh - > rh . get_response_headers = resource_handler_get_response_headers ;
rh - > rh . read_response = resource_handler_read_response ;
rh - > rh . cancel = resource_handler_cancel ;
2017-09-20 11:27:13 +00:00
2016-07-12 00:40:13 +00:00
cef_addref ( & rh - > rh ) ;
cef_release ( browser ) ;
cef_release ( frame ) ;
cef_release ( request ) ;
return & rh - > rh ;
}
static void app_initialize ( void )
{
app . base . size = sizeof ( app ) ;
app . get_browser_process_handler = app_get_browser_process_handler ;
app . get_render_process_handler = app_get_render_process_handler ;
app . on_register_custom_schemes = app_on_register_custom_schemes ;
browser_process_handler . base . size = sizeof ( browser_process_handler ) ;
browser_process_handler . on_before_child_process_launch = browser_process_handler_on_before_child_process_launch ;
browser_process_handler . on_context_initialized = browser_process_handler_on_context_initialized ;
render_process_handler . base . size = sizeof ( render_process_handler ) ;
render_process_handler . on_context_created = render_process_handler_on_context_created ;
render_process_handler . on_context_released = render_process_handler_on_context_released ;
render_process_handler . on_process_message_received = render_process_handler_on_process_message_received ;
v8handler_query . base . size = sizeof ( v8handler_query ) ;
v8handler_query . execute = fsfunc_execute ;
scheme_handler_factory . base . size = sizeof ( scheme_handler_factory ) ;
scheme_handler_factory . create = scheme_handler_factory_create ;
request_context_handler . base . size = sizeof ( request_context_handler ) ;
request_context_handler . on_before_plugin_load = request_context_handler_on_before_plugin_load ;
}
static int cefwasinitialised ;
cef_request_context_t * Cef_GetRequestContext ( void )
{
char utf8 [ MAX_OSPATH ] ;
cef_request_context_t * ret = NULL ;
qboolean incog ;
2020-05-14 15:50:26 +00:00
incog = cef_incognito - > value ;
2016-07-12 00:40:13 +00:00
if ( ! incog )
ret = request_context ;
if ( ! ret )
{
cef_request_context_settings_t csettings = { sizeof ( csettings ) } ;
csettings . persist_user_preferences = ! incog ;
2020-05-14 15:50:26 +00:00
if ( ! incog & & fsfuncs - > NativePath ( " cefcache " , FS_ROOT , utf8 , sizeof ( utf8 ) ) )
2016-07-12 00:40:13 +00:00
cef_string_from_utf8 ( utf8 , strlen ( utf8 ) , & csettings . cache_path ) ; //should be empty for incognito.
ret = cef_request_context_create_context ( & csettings , & request_context_handler ) ;
cef_string_clear ( & csettings . cache_path ) ;
}
else
cef_addref ( ret ) ;
if ( ! incog & & ! request_context )
{
request_context = ret ;
cef_addref ( request_context ) ;
}
return ret ;
}
2017-09-20 11:27:13 +00:00
static qboolean Cef_Init ( qboolean engineprocess ) ;
struct mediacallbacks_s ; //todo...
static void * Cef_Create ( const char * name , struct mediacallbacks_s * callbacks )
2016-07-12 00:40:13 +00:00
{
cef_window_info_t window_info = { 0 } ;
cef_browser_settings_t browserSettings = { sizeof ( browserSettings ) } ;
browser_t * newbrowser ;
cef_string_t url = { NULL } ;
if ( ! strcmp ( name , " cef " ) )
name + = 3 ;
else if ( ! strncmp ( name , " cef: " , 4 ) )
name + = 4 ;
else if ( ! strcmp ( name , " http " ) )
name + = 4 ;
else if ( ! strncmp ( name , " http: " , 5 ) )
;
else if ( ! strncmp ( name , " https: " , 6 ) )
;
else if ( ! strncmp ( name , " ftp: " , 4 ) )
;
else
return NULL ;
if ( ! cefwasinitialised )
{
char utf8 [ MAX_OSPATH ] ;
cef_main_args_t mainargs = { 0 } ;
cef_settings_t settings = { sizeof ( settings ) } ;
2017-09-20 11:27:13 +00:00
if ( ! Cef_Init ( true ) )
return NULL ;
2017-09-03 14:59:13 +00:00
//const char *ua = "FTEBrowser";
//cef_string_from_utf8(ua, strlen(ua), &settings.user_agent);
2020-05-14 15:50:26 +00:00
if ( fsfuncs - > NativePath ( " cefcache " , FS_ROOT , utf8 , sizeof ( utf8 ) ) )
2016-07-12 00:40:13 +00:00
cef_string_from_utf8 ( utf8 , strlen ( utf8 ) , & settings . cache_path ) ;
2020-05-14 15:50:26 +00:00
if ( fsfuncs - > NativePath ( " cef_debug.log " , FS_ROOT , utf8 , sizeof ( utf8 ) ) )
2016-07-12 00:40:13 +00:00
cef_string_from_utf8 ( utf8 , strlen ( utf8 ) , & settings . log_file ) ;
2020-05-14 15:50:26 +00:00
if ( fsfuncs - > NativePath ( " " , FS_BINARYPATH , utf8 , sizeof ( utf8 ) ) )
2017-09-20 11:27:13 +00:00
cef_string_from_utf8 ( utf8 , strlen ( utf8 ) , & settings . resources_dir_path ) ;
2020-05-14 15:50:26 +00:00
if ( fsfuncs - > NativePath ( " locales " , FS_BINARYPATH , utf8 , sizeof ( utf8 ) ) )
{
struct stat statbuf ;
if ( stat ( utf8 , & statbuf ) < 0 )
{
Con_Printf ( " %s not found \n " , utf8 ) ;
return NULL ;
}
2017-09-20 11:27:13 +00:00
cef_string_from_utf8 ( utf8 , strlen ( utf8 ) , & settings . locales_dir_path ) ;
2020-05-14 15:50:26 +00:00
}
2016-07-12 00:40:13 +00:00
# ifdef _WIN32
{
wchar_t omgwtfamonkey [ MAX_OSPATH ] ;
if ( GetModuleFileNameW ( NULL , omgwtfamonkey , countof ( omgwtfamonkey ) ) )
cef_string_from_utf16 ( omgwtfamonkey , wcslen ( omgwtfamonkey ) , & settings . browser_subprocess_path ) ;
mainargs . instance = GetModuleHandle ( NULL ) ;
}
# endif
# ifdef _DEBUG
settings . log_severity = LOGSEVERITY_VERBOSE ;
# else
settings . log_severity = LOGSEVERITY_DISABLE ;
# endif
2017-09-20 11:27:13 +00:00
settings . background_color = 0x00ffffff ;
2016-07-12 00:40:13 +00:00
// settings.single_process = true;
2017-09-03 14:59:13 +00:00
# ifdef _WIN32
// settings.multi_threaded_message_loop = true; //fixme: use this.
# endif
settings . windowless_rendering_enabled = true ;
2016-07-12 00:40:13 +00:00
// settings.command_line_args_disabled = true;
2017-09-03 14:59:13 +00:00
// settings.persist_session_cookies = false;
2016-07-12 00:40:13 +00:00
2021-10-05 05:05:15 +00:00
/* {
2016-07-12 00:40:13 +00:00
char * s ;
strcpy ( utf8 , FULLENGINENAME " / " STRINGIFY ( FTE_VER_MAJOR ) " . " STRINGIFY ( FTE_VER_MINOR ) ) ;
while ( ( s = strchr ( utf8 , ' ' ) ) )
* s = ' _ ' ;
cef_string_from_utf8 ( utf8 , strlen ( utf8 ) , & settings . product_version ) ;
}
2021-10-05 05:05:15 +00:00
*/
2016-07-12 00:40:13 +00:00
cefwasinitialised = ! ! cef_initialize ( & mainargs , & settings , & app , NULL ) ;
cef_string_clear ( & settings . browser_subprocess_path ) ;
2021-10-05 05:05:15 +00:00
// cef_string_clear(&settings.product_version);
2016-07-12 00:40:13 +00:00
cef_string_clear ( & settings . cache_path ) ;
cef_string_clear ( & settings . log_file ) ;
}
if ( ! cefwasinitialised )
return NULL ;
//tbh, web browser's are so horribly insecure that it seems pointless to even try disabling stuff that might be useful
browserSettings . windowless_frame_rate = 60 ;
browserSettings . javascript_close_windows = STATE_DISABLED ;
browserSettings . javascript_access_clipboard = STATE_DISABLED ;
// browserSettings.universal_access_from_file_urls = STATE_DISABLED;
// browserSettings.file_access_from_file_urls = STATE_DISABLED;
browserSettings . remote_fonts = STATE_DISABLED ;
browserSettings . plugins = STATE_DISABLED ;
2017-09-20 11:27:13 +00:00
browserSettings . background_color = 0x00ffffff ;
2016-07-12 00:40:13 +00:00
window_info . windowless_rendering_enabled = true ;
memset ( & window_info . parent_window , 0 , sizeof ( window_info . parent_window ) ) ;
newbrowser = browser_create ( ) ;
if ( ! newbrowser )
return NULL ;
if ( ! * name | | ! strcmp ( name , " http: " ) | | ! strcmp ( name , " https: " ) )
name = " about:blank " ;
cef_string_from_utf8 ( name , strlen ( name ) , & url ) ;
cef_addref ( & newbrowser - > client ) ;
2020-05-14 15:50:26 +00:00
newbrowser - > thebrowser = cef_browser_host_create_browser_sync ( & window_info , & newbrowser - > client , & url , & browserSettings , NULL , Cef_GetRequestContext ( ) ) ;
2016-07-12 00:40:13 +00:00
cef_string_to_utf8 ( url . str , url . length , & newbrowser - > currenturl ) ;
cef_string_clear ( & url ) ;
if ( ! newbrowser - > thebrowser )
{
browser_release ( newbrowser ) ;
return NULL ; //cef fucked up.
}
2020-05-14 15:50:26 +00:00
if ( cef_devtools - > value )
2016-07-12 00:40:13 +00:00
{
cef_browser_host_t * host = newbrowser - > thebrowser - > get_host ( newbrowser - > thebrowser ) ;
browser_t * devtools = browser_create ( ) ;
# ifdef _WIN32
window_info . style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE ;
window_info . parent_window = NULL ;
2021-11-03 20:30:48 +00:00
window_info . bounds . x = CW_USEDEFAULT ;
window_info . bounds . y = CW_USEDEFAULT ;
window_info . bounds . width = CW_USEDEFAULT ;
window_info . bounds . height = CW_USEDEFAULT ;
2016-07-12 00:40:13 +00:00
window_info . window_name = makecefstring ( " CEF Dev Tools " ) ;
# else
memset ( & window_info . parent_window , 0 , sizeof ( window_info . parent_window ) ) ;
window_info . x = 0 ;
window_info . y = 0 ;
window_info . width = 320 ;
window_info . height = 240 ;
# endif
window_info . windowless_rendering_enabled = false ;
cef_addref ( & devtools - > client ) ;
2020-05-14 15:50:26 +00:00
host - > show_dev_tools ( host , & window_info , & devtools - > client , & browserSettings , NULL ) ;
2016-07-12 00:40:13 +00:00
cef_release ( host ) ;
browser_release ( devtools ) ; //cef should continue to hold a reference to it while its visible, but its otherwise out of engine now.
# ifdef _WIN32
cef_string_clear ( & window_info . window_name ) ;
# endif
}
return ( void * ) newbrowser ;
}
2017-09-20 11:27:13 +00:00
static void * Cef_CreateOld ( const char * name )
{
return Cef_Create ( name , NULL ) ;
}
2016-07-12 00:40:13 +00:00
static qboolean VARGS Cef_DisplayFrame ( void * ctx , qboolean nosound , qboolean forcevideo , double mediatime , void ( QDECL * uploadtexture ) ( void * ectx , uploadfmt_t fmt , int width , int height , void * data , void * palette ) , void * ectx )
{
browser_t * browser = ( browser_t * ) ctx ;
if ( browser - > updated | | forcevideo )
{
uploadtexture ( ectx , TF_BGRA32 , browser - > videowidth , browser - > videoheight , browser - > videodata , NULL ) ;
browser - > updated = false ;
}
return true ;
}
static void Cef_Destroy ( void * ctx )
{ //engine isn't allowed to talk about the browser any more. kill it.
browser_t * br = ( browser_t * ) ctx ;
cef_browser_host_t * host = br - > thebrowser - > get_host ( br - > thebrowser ) ;
host - > close_browser ( host , true ) ;
cef_release ( host ) ;
if ( br - > thebrowser )
{
cef_release ( br - > thebrowser ) ;
br - > thebrowser = NULL ;
}
//now release our reference to it.
browser_release ( br ) ; //hopefully this should be the last reference, but we might be waiting for something on the cef side. hopefully nothing blocking on an unload event...
}
static void VARGS Cef_CursorMove ( void * ctx , float posx , float posy )
{
browser_t * br = ( browser_t * ) ctx ;
cef_browser_host_t * host = br - > thebrowser - > get_host ( br - > thebrowser ) ;
br - > mousepos . x = ( int ) ( posx * br - > desiredwidth ) ;
br - > mousepos . y = ( int ) ( posy * br - > desiredheight ) ;
br - > mousepos . modifiers = 0 ;
host - > send_mouse_move_event ( host , & br - > mousepos , false ) ;
cef_release ( host ) ;
}
static void VARGS Cef_Key ( void * ctx , int code , int unicode , int event )
{
browser_t * browser = ( browser_t * ) ctx ;
cef_browser_host_t * host = browser - > thebrowser - > get_host ( browser - > thebrowser ) ;
//handle mouse buttons
if ( code > = K_MOUSE1 & & code < = K_MOUSE3 )
{
int buttons [ ] = { MBT_LEFT , MBT_RIGHT , MBT_MIDDLE } ;
if ( ! event | | browser - > keystate [ code ] )
host - > send_mouse_click_event ( host , & browser - > mousepos , buttons [ code - K_MOUSE1 ] , event ? true : false , 1 ) ;
if ( event )
browser - > keystate [ code ] = 0 ;
else
browser - > keystate [ code ] = 1 ;
cef_release ( host ) ;
return ;
}
2024-07-14 18:56:31 +00:00
if ( code = = K_TOUCH )
{ //FIXME
cef_release ( host ) ;
return ;
}
if ( code = = K_TOUCHSLIDE | | code = = K_TOUCHTAP | | code = = K_TOUCHLONG )
{
cef_release ( host ) ;
return ; //has to do its own
}
2016-07-12 00:40:13 +00:00
//handle mouse wheels
if ( code = = K_MWHEELUP | | code = = K_MWHEELDOWN )
{
if ( ! event )
host - > send_mouse_wheel_event ( host , & browser - > mousepos , 0 , ( code = = K_MWHEELDOWN ) ? - 32 : 32 ) ;
cef_release ( host ) ;
return ;
}
//handle keypress/release events
if ( code )
{
cef_key_event_t kev = { 0 } ;
if ( event & & ! browser - > keystate [ code ] )
{
cef_release ( host ) ;
return ; //releasing a key that is already released is weird.
}
kev . type = event ? KEYEVENT_KEYUP : KEYEVENT_RAWKEYDOWN ;
kev . modifiers = 0 ;
switch ( code )
{
case 0 : kev . windows_key_code = 0 ; break ;
case K_UPARROW : kev . windows_key_code = 0x26 /*VK_UP*/ ; break ;
case K_DOWNARROW : kev . windows_key_code = 0x28 /*VK_DOWN*/ ; break ;
case K_LEFTARROW : kev . windows_key_code = 0x25 /*VK_LEFT*/ ; break ;
case K_RIGHTARROW : kev . windows_key_code = 0x27 /*VK_RIGHT*/ ; break ;
case K_ESCAPE : kev . windows_key_code = 0x1b /*VK_ESCAPE*/ ; break ;
case K_SPACE : kev . windows_key_code = 0x20 /*VK_SPACE*/ ; break ;
case K_RSHIFT : kev . windows_key_code = 0x10 /*VK_SHIFT*/ ; break ;
case K_LSHIFT : kev . windows_key_code = 0x10 /*VK_SHIFT*/ ; break ;
case K_RCTRL : kev . windows_key_code = 0x11 /*VK_CONTROL*/ ; break ;
case K_LCTRL : kev . windows_key_code = 0x11 /*VK_CONTROL*/ ; break ;
case K_RALT : kev . windows_key_code = 0x12 /*VK_MENU*/ ; break ;
case K_LALT : kev . windows_key_code = 0x12 /*VK_MENU*/ ; break ;
case K_TAB : kev . windows_key_code = 0x09 /*VK_TAB*/ ; break ;
case K_RWIN : kev . windows_key_code = 0x5c /*VK_RWIN*/ ; break ;
case K_LWIN : kev . windows_key_code = 0x5b /*VK_LWIN*/ ; break ;
case K_APP : kev . windows_key_code = 0x5d /*VK_APPS*/ ; break ;
case K_F1 : kev . windows_key_code = 0x70 /*VK_F1*/ ; break ;
case K_F2 : kev . windows_key_code = 0x71 /*VK_F2*/ ; break ;
case K_F3 : kev . windows_key_code = 0x72 /*VK_F3*/ ; break ;
case K_F4 : kev . windows_key_code = 0x73 /*VK_F4*/ ; break ;
case K_F5 : kev . windows_key_code = 0x74 /*VK_F5*/ ; break ;
case K_F6 : kev . windows_key_code = 0x75 /*VK_F6*/ ; break ;
case K_F7 : kev . windows_key_code = 0x76 /*VK_F7*/ ; break ;
case K_F8 : kev . windows_key_code = 0x77 /*VK_F8*/ ; break ;
case K_F9 : kev . windows_key_code = 0x78 /*VK_F9*/ ; break ;
case K_F10 : kev . windows_key_code = 0x79 /*VK_F10*/ ; break ;
case K_F11 : kev . windows_key_code = 0x81 /*VK_F11*/ ; break ;
case K_F12 : kev . windows_key_code = 0x82 /*VK_F12*/ ; break ;
case K_BACKSPACE : kev . windows_key_code = 0x08 /*VK_BACK*/ ; break ;
case K_DEL : kev . windows_key_code = 0x2e /*VK_DELETE*/ ; break ;
case K_HOME : kev . windows_key_code = 0x24 /*VK_HOME*/ ; break ;
case K_END : kev . windows_key_code = 0x23 /*VK_END*/ ; break ;
case K_INS : kev . windows_key_code = 0x2d /*VK_INSERT*/ ; break ;
case K_PGUP : kev . windows_key_code = 0x21 /*VK_PRIOR*/ ; break ;
case K_PGDN : kev . windows_key_code = 0x22 /*VK_NEXT*/ ; break ;
default :
if ( ( code > = 0x30 & & code < = 0x39 ) | | ( code > = 0x41 & & code < = 0x5a ) )
kev . windows_key_code = code ;
else if ( code > = ' a ' & & code < = ' z ' )
kev . windows_key_code = ( code - ' a ' ) + ' A ' ;
else
kev . windows_key_code = 0 ;
break ;
}
kev . native_key_code = unicode < < 16 ;
if ( browser - > keystate [ code ] )
kev . native_key_code | = 1 < < 30 ;
if ( event )
2020-05-14 15:50:26 +00:00
kev . native_key_code | = 1u < < 31 ;
2016-07-12 00:40:13 +00:00
if ( event )
browser - > keystate [ code ] = 0 ;
else
browser - > keystate [ code ] = 1 ;
kev . is_system_key = 0 ;
kev . character = unicode ;
kev . unmodified_character = unicode ;
kev . focus_on_editable_field = true ;
host - > send_key_event ( host , & kev ) ;
}
//handle text input events (down events only)
if ( unicode & & ! event )
{
cef_key_event_t kev ;
kev . type = KEYEVENT_CHAR ;
kev . modifiers = 0 ;
kev . windows_key_code = unicode ;
kev . native_key_code = unicode < < 16 ;
if ( browser - > keystate [ code ] )
kev . native_key_code | = 1 < < 30 ;
if ( event )
2020-05-14 15:50:26 +00:00
kev . native_key_code | = 1u < < 31 ;
2016-07-12 00:40:13 +00:00
kev . is_system_key = 0 ;
kev . character = unicode ;
kev . unmodified_character = unicode ;
kev . focus_on_editable_field = true ;
host - > send_key_event ( host , & kev ) ;
}
cef_release ( host ) ;
}
static qboolean VARGS Cef_SetSize ( void * ctx , int width , int height )
{
browser_t * browser = ( browser_t * ) ctx ;
cef_browser_host_t * host = browser - > thebrowser - > get_host ( browser - > thebrowser ) ;
if ( browser - > desiredwidth ! = width | | browser - > desiredheight ! = height )
{
browser - > desiredwidth = width ;
browser - > desiredheight = height ;
host - > was_resized ( host ) ;
}
cef_release ( host ) ;
return qtrue ;
}
static void VARGS Cef_GetSize ( void * ctx , int * width , int * height )
{
//this specifies the logical size/aspect of the browser object
browser_t * browser = ( browser_t * ) ctx ;
* width = browser - > desiredwidth ;
* height = browser - > desiredheight ;
}
static void VARGS Cef_ChangeStream ( void * ctx , const char * streamname )
{
browser_t * browser = ( browser_t * ) ctx ;
cef_browser_host_t * host = browser - > thebrowser - > get_host ( browser - > thebrowser ) ;
cef_frame_t * frame = NULL ;
if ( ! strncmp ( streamname , " cmd: " , 4 ) )
{
const char * cmd = streamname + 4 ;
if ( ! strcmp ( cmd , " focus " ) )
2021-11-03 20:30:48 +00:00
host - > set_focus ( host , true ) ;
2016-07-12 00:40:13 +00:00
else if ( ! strcmp ( cmd , " unfocus " ) )
2021-11-03 20:30:48 +00:00
host - > set_focus ( host , false ) ;
2016-07-12 00:40:13 +00:00
else if ( ! strcmp ( cmd , " refresh " ) )
browser - > thebrowser - > reload ( browser - > thebrowser ) ;
else if ( ! strcmp ( cmd , " transparent " ) )
;
else if ( ! strcmp ( cmd , " opaque " ) )
;
else if ( ! strcmp ( cmd , " stop " ) )
browser - > thebrowser - > stop_load ( browser - > thebrowser ) ;
else if ( ! strcmp ( cmd , " back " ) )
browser - > thebrowser - > go_back ( browser - > thebrowser ) ;
else if ( ! strcmp ( cmd , " forward " ) )
browser - > thebrowser - > go_forward ( browser - > thebrowser ) ;
2021-10-05 05:05:15 +00:00
else if ( ! strcmp ( cmd , " home " ) )
Cef_ChangeStream ( ctx , " http://fte.triptohell.info " ) ;
2016-07-12 00:40:13 +00:00
else
{
frame = browser - > thebrowser - > get_focused_frame ( browser - > thebrowser ) ;
if ( ! strcmp ( cmd , " undo " ) )
frame - > undo ( frame ) ;
else if ( ! strcmp ( cmd , " redo " ) )
frame - > redo ( frame ) ;
else if ( ! strcmp ( cmd , " cut " ) )
frame - > cut ( frame ) ;
else if ( ! strcmp ( cmd , " copy " ) )
frame - > copy ( frame ) ;
else if ( ! strcmp ( cmd , " paste " ) )
; //frame->paste(frame); //possible security hole, as this uses the system clipboard
else if ( ! strcmp ( cmd , " del " ) )
frame - > del ( frame ) ;
else if ( ! strcmp ( cmd , " selectall " ) )
frame - > select_all ( frame ) ;
else
Con_Printf ( " unrecognised cmd: %s \n " , cmd ) ;
}
}
else if ( ! strncmp ( streamname , " javascript: " , 11 ) )
{
cef_string_t thescript = { NULL } ;
cef_string_t url = { NULL } ;
cef_string_from_utf8 ( streamname + 11 , strlen ( streamname + 11 ) , & thescript ) ;
cef_string_from_utf8 ( " http://localhost/ " , strlen ( " http://localhost/ " ) , & url ) ;
frame = browser - > thebrowser - > get_main_frame ( browser - > thebrowser ) ;
frame - > execute_java_script ( frame , & thescript , & url , 1 ) ;
cef_string_clear ( & thescript ) ;
cef_string_clear ( & url ) ;
}
2020-05-14 15:50:26 +00:00
/*else if (!strncmp(streamname, "raw:", 4))
2016-07-12 00:40:13 +00:00
{
cef_string_t thehtml = { NULL } ;
cef_string_t url = { NULL } ;
cef_string_from_utf8 ( streamname + 4 , strlen ( streamname + 4 ) , & thehtml ) ;
cef_string_from_utf8 ( " http://localhost/ " , strlen ( " http://localhost/ " ) , & url ) ;
frame = browser - > thebrowser - > get_main_frame ( browser - > thebrowser ) ;
frame - > load_string ( frame , & thehtml , & url ) ;
cef_string_clear ( & thehtml ) ;
cef_string_clear ( & url ) ;
2020-05-14 15:50:26 +00:00
} */
2016-07-12 00:40:13 +00:00
else if ( * streamname & & strcmp ( streamname , " http: " ) & & strcmp ( streamname , " https: " ) )
{
cef_string_t url = { NULL } ;
cef_string_from_utf8 ( streamname , strlen ( streamname ) , & url ) ;
frame = browser - > thebrowser - > get_main_frame ( browser - > thebrowser ) ;
frame - > load_url ( frame , & url ) ;
cef_string_clear ( & url ) ;
}
if ( frame )
cef_release ( frame ) ;
cef_release ( host ) ;
}
qboolean VARGS Cef_GetProperty ( void * ctx , const char * field , char * out , size_t * outsize )
{
browser_t * browser = ( browser_t * ) ctx ;
const char * ret = NULL ;
if ( ! strcmp ( field , " url " ) )
ret = browser - > currenturl . str ;
else if ( ! strcmp ( field , " title " ) )
ret = browser - > currenttitle . str ;
else if ( ! strcmp ( field , " status " ) )
ret = browser - > currentstatus . str ;
2017-09-20 11:27:13 +00:00
else if ( ! strcmp ( field , " icon " ) )
ret = browser - > currenticon . str ;
2016-07-12 00:40:13 +00:00
if ( ret )
{
size_t retsize = strlen ( ret ) ;
if ( out )
{
if ( * outsize < retsize )
return false ; //caller fucked up
memcpy ( out , ret , retsize ) ;
}
* outsize = retsize ;
return true ;
}
return false ;
}
static media_decoder_funcs_t decoderfuncs ;
static qintptr_t Cef_Tick ( qintptr_t * args )
{
if ( cefwasinitialised )
{
cef_do_message_loop_work ( ) ;
/* libcef can't cope with this.
if ( ! numbrowsers )
{
if ( request_context )
{
cef_release ( request_context ) ;
request_context = NULL ;
}
cef_shutdown ( ) ;
cefwasinitialised = false ;
}
*/
}
return 0 ;
}
static qintptr_t Cef_Shutdown ( qintptr_t * args )
{
if ( cefwasinitialised )
{
int tries = 1000 * 10 ; //60*5; //keep trying for a duration (in ms)... give up after then as it just isn't working.
while ( numbrowsers & & tries > 0 )
{
cef_do_message_loop_work ( ) ;
tries - = 10 ;
# ifdef _WIN32
Sleep ( 10 ) ;
# else
usleep ( 10 * 1000 ) ;
# endif
}
# ifdef _WIN32
if ( numbrowsers )
{ //this really should NOT be happening.
MessageBox ( NULL , " Browsers are still open " , " CEF Fuckup " , 0 ) ;
}
# endif
if ( request_context )
{
cef_release ( request_context ) ;
request_context = NULL ;
}
cef_shutdown ( ) ;
cefwasinitialised = false ;
numbrowsers = 0 ;
}
# if defined(_DEBUG) && defined(_MSC_VER)
// _CrtDumpMemoryLeaks();
# endif
return 0 ;
}
# ifndef _WIN32
2020-05-14 15:50:26 +00:00
static int argc = 0 ;
static char * argv [ 64 ] ;
static char commandline [ 8192 ] ;
static void SetupArgv ( cef_main_args_t * a )
2016-07-12 00:40:13 +00:00
{
2020-05-14 15:50:26 +00:00
FILE * f ;
if ( ! argc )
2016-07-12 00:40:13 +00:00
{
2020-05-14 15:50:26 +00:00
f = fopen ( " /proc/self/cmdline " , " r " ) ;
if ( f )
{
char * s = commandline ;
char * e = commandline + fread ( commandline , 1 , sizeof ( commandline ) , f ) ;
fclose ( f ) ;
while ( s < e )
{
argv [ argc + + ] = s ;
while ( * s )
s + + ;
s + + ;
}
}
2016-07-12 00:40:13 +00:00
}
2020-05-14 15:50:26 +00:00
a - > argc = argc ;
a - > argv = argv ;
2016-07-12 00:40:13 +00:00
}
# endif
2021-10-05 05:05:15 +00:00
//if we're a subprocess and somehow failed to add the --plugwrapper arg to the engine, then make sure we're not starting endless processes.
2016-07-12 00:40:13 +00:00
static qboolean Cef_Init ( qboolean engineprocess )
{
2021-10-05 05:05:15 +00:00
static qboolean cefwasloaded = qfalse ;
2016-07-12 00:40:13 +00:00
# ifdef _WIN32
cef_main_args_t args = { GetModuleHandle ( NULL ) } ;
# else
2020-05-14 15:50:26 +00:00
cef_main_args_t args ;
SetupArgv ( & args ) ;
2016-07-12 00:40:13 +00:00
# endif
2021-10-05 05:05:15 +00:00
if ( cefwasloaded )
return qtrue ;
2016-07-12 00:40:13 +00:00
{
int result ;
2020-05-14 15:50:26 +00:00
# ifdef LIBCEF_DYNAMIC
2016-07-12 00:40:13 +00:00
dllfunction_t ceffuncs [ ] =
{
{ ( void * * ) & cef_version_info , " cef_version_info " } ,
{ ( void * * ) & cef_initialize , " cef_initialize " } ,
{ ( void * * ) & cef_do_message_loop_work , " cef_do_message_loop_work " } ,
{ ( void * * ) & cef_shutdown , " cef_shutdown " } ,
{ ( void * * ) & cef_execute_process , " cef_execute_process " } ,
{ ( void * * ) & cef_browser_host_create_browser_sync , " cef_browser_host_create_browser_sync " } ,
{ ( void * * ) & cef_string_utf8_to_utf16 , " cef_string_utf8_to_utf16 " } ,
{ ( void * * ) & cef_string_utf16_to_utf8 , " cef_string_utf16_to_utf8 " } ,
{ ( void * * ) & cef_string_utf16_clear , " cef_string_utf16_clear " } ,
{ ( void * * ) & cef_string_utf16_set , " cef_string_utf16_set " } ,
{ ( void * * ) & cef_string_utf8_clear , " cef_string_utf8_clear " } ,
{ ( void * * ) & cef_string_utf8_set , " cef_string_utf8_set " } ,
{ ( void * * ) & cef_string_userfree_utf16_free , " cef_string_userfree_utf16_free " } ,
{ ( void * * ) & cef_register_scheme_handler_factory , " cef_register_scheme_handler_factory " } ,
{ ( void * * ) & cef_v8value_create_function , " cef_v8value_create_function " } ,
{ ( void * * ) & cef_v8value_create_string , " cef_v8value_create_string " } ,
{ ( void * * ) & cef_process_message_create , " cef_process_message_create " } ,
{ ( void * * ) & cef_v8context_get_current_context , " cef_v8context_get_current_context " } ,
{ ( void * * ) & cef_post_task , " cef_post_task " } ,
{ ( void * * ) & cef_request_context_create_context , " cef_request_context_create_context " } ,
2017-09-20 11:27:13 +00:00
{ ( void * * ) & cef_string_multimap_alloc , " cef_string_multimap_alloc " } ,
{ ( void * * ) & cef_string_multimap_append , " cef_string_multimap_append " } ,
{ ( void * * ) & cef_string_multimap_size , " cef_string_multimap_size " } ,
{ ( void * * ) & cef_string_multimap_key , " cef_string_multimap_key " } ,
{ ( void * * ) & cef_string_multimap_value , " cef_string_multimap_value " } ,
{ ( void * * ) & cef_string_multimap_free , " cef_string_multimap_free " } ,
{ ( void * * ) & cef_string_list_size , " cef_string_list_size " } ,
{ ( void * * ) & cef_string_list_value , " cef_string_list_value " } ,
2016-07-12 00:40:13 +00:00
{ NULL }
} ;
2021-10-05 05:05:15 +00:00
2021-11-03 20:30:48 +00:00
# ifdef _WIN32
if ( plugfuncs & & ! plugfuncs - > LoadDLL ( " libcef " , ceffuncs ) )
# else
2021-10-05 05:05:15 +00:00
if ( plugfuncs & & ! plugfuncs - > LoadDLL ( " ./libcef " , ceffuncs ) )
2021-11-03 20:30:48 +00:00
# endif
2016-07-12 00:40:13 +00:00
{
if ( engineprocess )
Con_Printf ( " Unable to load libcef (version " CEF_VERSION " ) \n " ) ;
return false ;
}
2020-05-14 15:50:26 +00:00
# endif
2016-07-12 00:40:13 +00:00
if ( engineprocess )
{
2021-10-05 05:05:15 +00:00
Con_DPrintf ( " libcef %i.%i.%i.%i (chrome %i.%i.%i.%i) \n " , cef_version_info ( 0 ) , cef_version_info ( 1 ) , cef_version_info ( 2 ) , cef_version_info ( 3 ) , cef_version_info ( 4 ) , cef_version_info ( 5 ) , cef_version_info ( 6 ) , cef_version_info ( 7 ) ) ;
2020-05-14 15:50:26 +00:00
if ( cef_version_info ( 0 ) ! = CEF_VERSION_MAJOR | |
cef_version_info ( 1 ) ! = CEF_VERSION_MINOR | |
cef_version_info ( 2 ) ! = CEF_VERSION_PATCH | |
cef_version_info ( 3 ) ! = CEF_COMMIT_NUMBER | |
cef_version_info ( 4 ) ! = CHROME_VERSION_MAJOR | |
cef_version_info ( 5 ) ! = CHROME_VERSION_MINOR | |
cef_version_info ( 6 ) ! = CHROME_VERSION_BUILD | |
cef_version_info ( 7 ) ! = CHROME_VERSION_PATCH )
2016-07-12 00:40:13 +00:00
{ //the libcef api hash can be used to see if there's an api change that might break stuff.
//refuse to load it if the api changed.
Con_Printf ( " libcef outdated. Please install libcef version " CEF_VERSION " \n " ) ;
return false ;
}
}
app_initialize ( ) ;
2021-10-05 05:05:15 +00:00
if ( ! engineprocess )
{
result = cef_execute_process ( & args , & app , 0 ) ;
if ( result > = 0 | | ! engineprocess )
{ //result is meant to be the exit code that the child process is meant to exit with
//either way, we really don't want to return to the engine because that would run a second instance of it.
exit ( result ) ;
return qfalse ;
}
2016-07-12 00:40:13 +00:00
}
}
2021-10-05 05:05:15 +00:00
return cefwasloaded = qtrue ;
2016-07-12 00:40:13 +00:00
}
2021-10-05 05:05:15 +00:00
//works with the --plugwrapper engine argument
int NATIVEEXPORT CefSubprocessInit ( plugcorefuncs_t * corefuncs )
2016-07-12 00:40:13 +00:00
{
2021-10-05 05:05:15 +00:00
plugfuncs = corefuncs ;
2016-07-12 00:40:13 +00:00
return Cef_Init ( false ) ;
}
2022-03-08 05:31:34 +00:00
void Cef_ExecuteCommand ( void )
2016-07-12 00:40:13 +00:00
{
2022-03-08 05:31:34 +00:00
if ( confuncs & & Cef_Init ( true ) )
2016-07-12 00:40:13 +00:00
{
2022-03-08 05:31:34 +00:00
static int sequence ;
char f [ 128 ] ;
char videomap [ 8192 ] ;
Q_snprintf ( f , sizeof ( f ) , " libcef:%i " , + + sequence ) ;
newconsole = f ;
strcpy ( videomap , " cef: " ) ;
cmdfuncs - > Argv ( 1 , videomap + 4 , sizeof ( videomap ) - 4 ) ;
if ( ! videomap [ 4 ] )
2023-01-09 05:15:31 +00:00
strcpy ( videomap , " cef:https://fte.triptohell.info " ) ;
2022-03-08 05:31:34 +00:00
confuncs - > SetConsoleString ( f , " title " , videomap + 4 ) ;
confuncs - > SetConsoleFloat ( f , " iswindow " , true ) ;
confuncs - > SetConsoleFloat ( f , " forceutf8 " , true ) ;
confuncs - > SetConsoleFloat ( f , " wnd_w " , 640 + 16 ) ;
confuncs - > SetConsoleFloat ( f , " wnd_h " , 480 + 16 + 8 ) ;
confuncs - > SetConsoleString ( f , " backvideomap " , videomap ) ;
confuncs - > SetConsoleFloat ( f , " linebuffered " , 2 ) ;
confuncs - > SetActive ( f ) ;
newconsole = NULL ;
2016-07-12 00:40:13 +00:00
}
}
2021-10-05 05:05:15 +00:00
static qboolean QDECL Cef_PluginMayUnload ( void )
{
if ( cefwasinitialised )
return false ; //cef is a piece of shite. we have to leave it running or the threads it spawns will crash+burn...
return true ;
}
2020-05-14 15:50:26 +00:00
qboolean Plug_Init ( void )
2016-07-12 00:40:13 +00:00
{
2020-05-14 15:50:26 +00:00
fsfuncs = ( plugfsfuncs_t * ) plugfuncs - > GetEngineInterface ( plugfsfuncs_name , sizeof ( * fsfuncs ) ) ; //for fte://data/ scheme
confuncs = ( plugsubconsolefuncs_t * ) plugfuncs - > GetEngineInterface ( plugsubconsolefuncs_name , sizeof ( * confuncs ) ) ; //for cef command etc.
clientfuncs = ( plugclientfuncs_t * ) plugfuncs - > GetEngineInterface ( plugclientfuncs_name , sizeof ( * clientfuncs ) ) ; //for weird people trying to use xml requests to query game status (for hud stuff)
if ( ! fsfuncs | | ! confuncs | | ! clientfuncs
2021-10-05 05:05:15 +00:00
| | ! plugfuncs - > GetPluginName ( - 1 , plugname , sizeof ( plugname ) )
| | ! plugfuncs - > ExportFunction ( " MayUnload " , Cef_PluginMayUnload )
2020-05-14 15:50:26 +00:00
| | ! plugfuncs - > ExportFunction ( " Tick " , Cef_Tick )
| | ! plugfuncs - > ExportFunction ( " Shutdown " , Cef_Shutdown ) )
2016-07-12 00:40:13 +00:00
{
2020-05-14 15:50:26 +00:00
Con_Printf ( " CEF plugin failed: Required engine feature missing. \n " ) ;
2016-07-12 00:40:13 +00:00
return false ;
}
decoderfuncs . structsize = sizeof ( media_decoder_funcs_t ) ;
decoderfuncs . drivername = " cef " ;
2017-09-20 11:27:13 +00:00
decoderfuncs . createdecoder = Cef_CreateOld ;
// decoderfuncs.createdecoderCB = Cef_Create;
2016-07-12 00:40:13 +00:00
decoderfuncs . decodeframe = Cef_DisplayFrame ;
decoderfuncs . shutdown = Cef_Destroy ;
decoderfuncs . cursormove = Cef_CursorMove ;
decoderfuncs . key = Cef_Key ;
decoderfuncs . setsize = Cef_SetSize ;
decoderfuncs . getsize = Cef_GetSize ;
decoderfuncs . changestream = Cef_ChangeStream ;
decoderfuncs . getproperty = Cef_GetProperty ;
2020-05-14 15:50:26 +00:00
if ( ! plugfuncs - > ExportInterface ( " Media_VideoDecoder " , & decoderfuncs , sizeof ( decoderfuncs ) ) )
2016-07-12 00:40:13 +00:00
{
Con_Printf ( " CEF plugin failed: Engine doesn't support media decoder plugins \n " ) ;
return false ;
}
2022-03-08 05:31:34 +00:00
cmdfuncs - > AddCommand ( " cef " , Cef_ExecuteCommand , " Open a web page! " ) ;
2016-07-12 00:40:13 +00:00
2020-05-14 15:50:26 +00:00
cef_incognito = cvarfuncs - > GetNVFDG ( " cef_incognito " , " 0 " , 0 , NULL , " browser settings " ) ;
cef_allowplugins = cvarfuncs - > GetNVFDG ( " cef_allowplugins " , " 0 " , 0 , NULL , " browser settings " ) ;
cef_allowcvars = cvarfuncs - > GetNVFDG ( " cef_allowcvars " , " 0 " , 0 , NULL , " browser settings " ) ;
cef_devtools = cvarfuncs - > GetNVFDG ( " cef_devtools " , " 0 " , 0 , NULL , " browser settings " ) ;
2016-07-12 00:40:13 +00:00
return true ;
}