diff --git a/core/src/external.rs b/core/src/external.rs index cd062e06d..9ab460587 100644 --- a/core/src/external.rs +++ b/core/src/external.rs @@ -309,12 +309,22 @@ impl<'gc> Callback<'gc> { } } +pub trait FsCommandProvider { + fn on_fs_command(&self, command: &str, args: &str) -> bool; +} + +pub struct NullFsCommandProvider; + +impl FsCommandProvider for NullFsCommandProvider { + fn on_fs_command(&self, _command: &str, _args: &str) -> bool { + false + } +} + pub trait ExternalInterfaceProvider { fn get_method(&self, name: &str) -> Option>; fn on_callback_available(&self, name: &str); - - fn on_fs_command(&self, command: &str, args: &str) -> bool; } pub trait ExternalInterfaceMethod { @@ -330,19 +340,25 @@ where } } -#[derive(Default, Collect)] +#[derive(Collect)] #[collect(no_drop)] pub struct ExternalInterface<'gc> { #[collect(require_static)] providers: Vec>, callbacks: BTreeMap>, + #[collect(require_static)] + fs_commands: Box, } impl<'gc> ExternalInterface<'gc> { - pub fn new(providers: Vec>) -> Self { + pub fn new( + providers: Vec>, + fs_commands: Box, + ) -> Self { Self { providers, - ..Default::default() + callbacks: Default::default(), + fs_commands, } } @@ -375,11 +391,6 @@ impl<'gc> ExternalInterface<'gc> { } pub fn invoke_fs_command(&self, command: &str, args: &str) -> bool { - for provider in &self.providers { - if provider.on_fs_command(command, args) { - return true; - } - } - false + self.fs_commands.on_fs_command(command, args) } } diff --git a/core/src/player.rs b/core/src/player.rs index 1dd017881..bbd3bf7db 100644 --- a/core/src/player.rs +++ b/core/src/player.rs @@ -30,8 +30,8 @@ use crate::display_object::{ TInteractiveObject, WindowMode, }; use crate::events::{ButtonKeyCode, ClipEvent, ClipEventResult, KeyCode, MouseButton, PlayerEvent}; -use crate::external::Value as ExternalValue; -use crate::external::{ExternalInterface, ExternalInterfaceProvider}; +use crate::external::{ExternalInterface, ExternalInterfaceProvider, NullFsCommandProvider}; +use crate::external::{FsCommandProvider, Value as ExternalValue}; use crate::focus_tracker::FocusTracker; use crate::font::Font; use crate::frame_lifecycle::{run_all_phases_avm2, FramePhase}; @@ -2110,6 +2110,7 @@ pub struct PlayerBuilder { sandbox_type: SandboxType, frame_rate: Option, external_interface_providers: Vec>, + fs_command_provider: Box, } impl PlayerBuilder { @@ -2154,6 +2155,7 @@ impl PlayerBuilder { sandbox_type: SandboxType::LocalTrusted, frame_rate: None, external_interface_providers: vec![], + fs_command_provider: Box::new(NullFsCommandProvider), } } @@ -2318,12 +2320,19 @@ impl PlayerBuilder { self } + /// Adds an FSCommand implementation for movies to communicate with + pub fn with_fs_commands(mut self, provider: Box) -> Self { + self.fs_command_provider = provider; + self + } + fn create_gc_root<'gc>( gc_context: &'gc gc_arena::Mutation<'gc>, player_version: u8, fullscreen: bool, fake_movie: Arc, external_interface_providers: Vec>, + fs_command_provider: Box, ) -> GcRoot<'gc> { let mut interner = AvmStringInterner::new(); let mut init = GcContext { @@ -2344,7 +2353,10 @@ impl PlayerBuilder { interner, current_context_menu: None, drag_object: None, - external_interface: ExternalInterface::new(external_interface_providers), + external_interface: ExternalInterface::new( + external_interface_providers, + fs_command_provider, + ), focus_tracker: FocusTracker::new(gc_context), library: Library::empty(), load_manager: LoadManager::new(), @@ -2459,6 +2471,7 @@ impl PlayerBuilder { self.fullscreen, fake_movie.clone(), self.external_interface_providers, + self.fs_command_provider, ) }, ))), diff --git a/desktop/src/backends/external_interface.rs b/desktop/src/backends/external_interface.rs index b44851f08..534376907 100644 --- a/desktop/src/backends/external_interface.rs +++ b/desktop/src/backends/external_interface.rs @@ -9,8 +9,4 @@ impl ExternalInterfaceProvider for DesktopExternalInterfaceProvider { } fn on_callback_available(&self, _name: &str) {} - - fn on_fs_command(&self, _command: &str, _args: &str) -> bool { - false - } } diff --git a/tests/tests/external_interface/mod.rs b/tests/tests/external_interface/mod.rs index 5ff72d495..cf6f17f4f 100644 --- a/tests/tests/external_interface/mod.rs +++ b/tests/tests/external_interface/mod.rs @@ -47,8 +47,4 @@ impl ExternalInterfaceProvider for ExternalInterfaceTestProvider { } fn on_callback_available(&self, _name: &str) {} - - fn on_fs_command(&self, _command: &str, _args: &str) -> bool { - false - } } diff --git a/web/src/lib.rs b/web/src/lib.rs index 8946bc659..3b296da85 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -15,7 +15,8 @@ use ruffle_core::config::{Letterbox, NetworkingAccessMode}; use ruffle_core::context::UpdateContext; use ruffle_core::events::{KeyCode, MouseButton, MouseWheelDelta, TextControlCode}; use ruffle_core::external::{ - ExternalInterfaceMethod, ExternalInterfaceProvider, Value as ExternalValue, Value, + ExternalInterfaceMethod, ExternalInterfaceProvider, FsCommandProvider, Value as ExternalValue, + Value, }; use ruffle_core::tag_utils::SwfMovie; use ruffle_core::{ @@ -1436,7 +1437,9 @@ impl ExternalInterfaceProvider for JavascriptInterface { fn on_callback_available(&self, name: &str) { self.js_player.on_callback_available(name); } +} +impl FsCommandProvider for JavascriptInterface { fn on_fs_command(&self, command: &str, args: &str) -> bool { self.js_player .on_fs_command(command, args)