add: preload scripts (#6)

This commit is contained in:
elm
2025-08-19 19:54:19 +09:00
committed by GitHub
parent 1d3512c6b8
commit 6031e1c9d4
6 changed files with 182 additions and 52 deletions

View File

@@ -8,10 +8,11 @@ use bevy::platform::collections::HashMap;
use bevy::prelude::*;
use bevy_remote::BrpMessage;
use cef::{
Browser, BrowserHost, BrowserSettings, Client, CompositionUnderline, ImplBrowser,
ImplBrowserHost, ImplFrame, ImplListValue, ImplProcessMessage, ImplRequestContext,
MouseButtonType, ProcessId, Range, RequestContext, RequestContextSettings, WindowInfo,
browser_host_create_browser_sync, process_message_create,
Browser, BrowserHost, BrowserSettings, CefString, Client, CompositionUnderline,
DictionaryValue, ImplBrowser, ImplBrowserHost, ImplDictionaryValue, ImplFrame, ImplListValue,
ImplProcessMessage, ImplRequestContext, MouseButtonType, ProcessId, Range, RequestContext,
RequestContextSettings, WindowInfo, browser_host_create_browser_sync, dictionary_value_create,
process_message_create,
};
use cef_dll_sys::{cef_event_flags_t, cef_mouse_button_type_t};
#[allow(deprecated)]
@@ -62,6 +63,7 @@ impl Browsers {
ipc_event_sender: Sender<IpcEventRaw>,
brp_sender: Sender<BrpMessage>,
system_cursor_icon_sender: SystemCursorIconSenderInner,
initialize_scripts: &[String],
_window_handle: Option<RawWindowHandle>,
) {
let mut context = Self::request_context(requester);
@@ -93,10 +95,11 @@ impl Browsers {
windowless_frame_rate: 60,
..Default::default()
}),
None,
Self::create_extra_info(initialize_scripts).as_mut(),
context.as_mut(),
)
.expect("Failed to create browser");
self.browsers.insert(
webview,
WebviewBrowser {
@@ -415,6 +418,18 @@ impl Browsers {
.get(webview)
.and_then(|b| b.client.focused_frame().is_some().then_some(b))
}
fn create_extra_info(scripts: &[String]) -> Option<DictionaryValue> {
if scripts.is_empty() {
return None;
}
let extra = dictionary_value_create()?;
extra.set_string(
Some(&CefString::from(INIT_SCRIPT_KEY)),
Some(&CefString::from(scripts.join(";").as_str())),
);
Some(extra)
}
}
pub fn modifiers_from_mouse_buttons<'a>(buttons: impl IntoIterator<Item = &'a MouseButton>) -> u32 {

View File

@@ -8,9 +8,10 @@ use bevy::platform::collections::HashMap;
use bevy_remote::BrpResult;
use cef::rc::{Rc, RcImpl};
use cef::{
Browser, Frame, ImplFrame, ImplListValue, ImplProcessMessage, ImplRenderProcessHandler,
ImplV8Context, ImplV8Value, ProcessId, ProcessMessage, V8Context, V8Propertyattribute, V8Value,
WrapRenderProcessHandler, sys, v8_value_create_function, v8_value_create_object,
Browser, CefString, DictionaryValue, Frame, ImplBrowser, ImplDictionaryValue, ImplFrame,
ImplListValue, ImplProcessMessage, ImplRenderProcessHandler, ImplV8Context, ImplV8Value,
ProcessId, ProcessMessage, V8Context, V8Propertyattribute, V8Value, WrapRenderProcessHandler,
sys, v8_value_create_function, v8_value_create_object,
};
use std::os::raw::c_int;
use std::sync::Mutex;
@@ -18,6 +19,9 @@ use std::sync::Mutex;
pub(crate) static BRP_PROMISES: Mutex<HashMap<String, V8Value>> = Mutex::new(HashMap::new());
pub(crate) static LISTEN_EVENTS: Mutex<HashMap<String, V8Value>> = Mutex::new(HashMap::new());
static INIT_SCRIPTS: Mutex<HashMap<c_int, String>> = Mutex::new(HashMap::new());
pub const INIT_SCRIPT_KEY: &str = "init_script";
pub const PROCESS_MESSAGE_BRP: &str = "brp";
pub const PROCESS_MESSAGE_HOST_EMIT: &str = "host-emit";
pub const PROCESS_MESSAGE_JS_EMIT: &str = "js-emit";
@@ -61,52 +65,34 @@ impl Clone for RenderProcessHandlerBuilder {
}
impl ImplRenderProcessHandler for RenderProcessHandlerBuilder {
fn on_browser_created(
&self,
browser: Option<&mut Browser>,
extra: Option<&mut DictionaryValue>,
) {
if let (Some(browser), Some(extra)) = (browser, extra) {
let script = extra.string(Some(&INIT_SCRIPT_KEY.into())).into_string();
if script.is_empty() {
return;
}
let id = browser.identifier();
INIT_SCRIPTS.lock().unwrap().insert(id, script);
}
}
fn on_context_created(
&self,
_browser: Option<&mut Browser>,
browser: Option<&mut Browser>,
frame: Option<&mut Frame>,
context: Option<&mut V8Context>,
) {
if let Some(g) = context.and_then(|c| c.global())
if let Some(context) = context
&& let Some(frame) = frame
&& let Some(mut cef) = v8_value_create_object(
Some(&mut V8DefaultAccessorBuilder::build()),
Some(&mut V8DefaultInterceptorBuilder::build()),
)
&& let Some(mut brp) = v8_value_create_function(
Some(&"brp".into()),
Some(&mut BrpBuilder::build(frame.clone())),
)
&& let Some(mut emit) = v8_value_create_function(
Some(&"emit".into()),
Some(&mut EmitBuilder::build(frame.clone())),
)
&& let Some(mut listen) = v8_value_create_function(
Some(&"listen".into()),
Some(&mut ListenBuilder::build(frame.clone())),
)
&& let Some(browser) = browser
{
cef.set_value_bykey(
Some(&"brp".into()),
Some(&mut brp),
V8Propertyattribute::default(),
);
cef.set_value_bykey(
Some(&"emit".into()),
Some(&mut emit),
V8Propertyattribute::default(),
);
cef.set_value_bykey(
Some(&"listen".into()),
Some(&mut listen),
V8Propertyattribute::default(),
);
g.set_value_bykey(
Some(&"cef".into()),
Some(&mut cef),
V8Propertyattribute::default(),
);
};
inject_initialize_scripts(browser, context, frame);
inject_cef_api(context, frame);
}
}
fn on_process_message_received(
@@ -139,6 +125,60 @@ impl ImplRenderProcessHandler for RenderProcessHandlerBuilder {
}
}
fn inject_initialize_scripts(browser: &mut Browser, context: &mut V8Context, frame: &mut Frame) {
let id = browser.identifier();
if let Some(script) = INIT_SCRIPTS.lock().ok().and_then(|scripts| {
let script = scripts.get(&id)?;
Some(CefString::from(script.as_str()))
}) {
context.enter();
frame.execute_java_script(Some(&script), Some(&(&frame.url()).into()), 0);
context.exit();
}
}
fn inject_cef_api(context: &mut V8Context, frame: &mut Frame) {
if let Some(g) = context.global()
&& let Some(mut cef) = v8_value_create_object(
Some(&mut V8DefaultAccessorBuilder::build()),
Some(&mut V8DefaultInterceptorBuilder::build()),
)
&& let Some(mut brp) = v8_value_create_function(
Some(&"brp".into()),
Some(&mut BrpBuilder::build(frame.clone())),
)
&& let Some(mut emit) = v8_value_create_function(
Some(&"emit".into()),
Some(&mut EmitBuilder::build(frame.clone())),
)
&& let Some(mut listen) = v8_value_create_function(
Some(&"listen".into()),
Some(&mut ListenBuilder::build(frame.clone())),
)
{
cef.set_value_bykey(
Some(&"brp".into()),
Some(&mut brp),
V8Propertyattribute::default(),
);
cef.set_value_bykey(
Some(&"emit".into()),
Some(&mut emit),
V8Propertyattribute::default(),
);
cef.set_value_bykey(
Some(&"listen".into()),
Some(&mut listen),
V8Propertyattribute::default(),
);
g.set_value_bykey(
Some(&"cef".into()),
Some(&mut cef),
V8Propertyattribute::default(),
);
}
}
fn handle_brp_message(message: &ProcessMessage, ctx: V8Context) {
let Some(argument_list) = message.argument_list() else {
return;