core: Move fscommand execution outside of ExternalInterfaceProvider, so it can be implemented without causing ExternalInterface.available to become true

This commit is contained in:
Nathan Adams 2023-07-24 22:58:30 +02:00
parent 4252d035af
commit 1a0a82d898
5 changed files with 42 additions and 23 deletions

View File

@ -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 { pub trait ExternalInterfaceProvider {
fn get_method(&self, name: &str) -> Option<Box<dyn ExternalInterfaceMethod>>; fn get_method(&self, name: &str) -> Option<Box<dyn ExternalInterfaceMethod>>;
fn on_callback_available(&self, name: &str); fn on_callback_available(&self, name: &str);
fn on_fs_command(&self, command: &str, args: &str) -> bool;
} }
pub trait ExternalInterfaceMethod { pub trait ExternalInterfaceMethod {
@ -330,19 +340,25 @@ where
} }
} }
#[derive(Default, Collect)] #[derive(Collect)]
#[collect(no_drop)] #[collect(no_drop)]
pub struct ExternalInterface<'gc> { pub struct ExternalInterface<'gc> {
#[collect(require_static)] #[collect(require_static)]
providers: Vec<Box<dyn ExternalInterfaceProvider>>, providers: Vec<Box<dyn ExternalInterfaceProvider>>,
callbacks: BTreeMap<String, Callback<'gc>>, callbacks: BTreeMap<String, Callback<'gc>>,
#[collect(require_static)]
fs_commands: Box<dyn FsCommandProvider>,
} }
impl<'gc> ExternalInterface<'gc> { impl<'gc> ExternalInterface<'gc> {
pub fn new(providers: Vec<Box<dyn ExternalInterfaceProvider>>) -> Self { pub fn new(
providers: Vec<Box<dyn ExternalInterfaceProvider>>,
fs_commands: Box<dyn FsCommandProvider>,
) -> Self {
Self { Self {
providers, 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 { pub fn invoke_fs_command(&self, command: &str, args: &str) -> bool {
for provider in &self.providers { self.fs_commands.on_fs_command(command, args)
if provider.on_fs_command(command, args) {
return true;
}
}
false
} }
} }

View File

@ -30,8 +30,8 @@ use crate::display_object::{
TInteractiveObject, WindowMode, TInteractiveObject, WindowMode,
}; };
use crate::events::{ButtonKeyCode, ClipEvent, ClipEventResult, KeyCode, MouseButton, PlayerEvent}; use crate::events::{ButtonKeyCode, ClipEvent, ClipEventResult, KeyCode, MouseButton, PlayerEvent};
use crate::external::Value as ExternalValue; use crate::external::{ExternalInterface, ExternalInterfaceProvider, NullFsCommandProvider};
use crate::external::{ExternalInterface, ExternalInterfaceProvider}; use crate::external::{FsCommandProvider, Value as ExternalValue};
use crate::focus_tracker::FocusTracker; use crate::focus_tracker::FocusTracker;
use crate::font::Font; use crate::font::Font;
use crate::frame_lifecycle::{run_all_phases_avm2, FramePhase}; use crate::frame_lifecycle::{run_all_phases_avm2, FramePhase};
@ -2110,6 +2110,7 @@ pub struct PlayerBuilder {
sandbox_type: SandboxType, sandbox_type: SandboxType,
frame_rate: Option<f64>, frame_rate: Option<f64>,
external_interface_providers: Vec<Box<dyn ExternalInterfaceProvider>>, external_interface_providers: Vec<Box<dyn ExternalInterfaceProvider>>,
fs_command_provider: Box<dyn FsCommandProvider>,
} }
impl PlayerBuilder { impl PlayerBuilder {
@ -2154,6 +2155,7 @@ impl PlayerBuilder {
sandbox_type: SandboxType::LocalTrusted, sandbox_type: SandboxType::LocalTrusted,
frame_rate: None, frame_rate: None,
external_interface_providers: vec![], external_interface_providers: vec![],
fs_command_provider: Box::new(NullFsCommandProvider),
} }
} }
@ -2318,12 +2320,19 @@ impl PlayerBuilder {
self self
} }
/// Adds an FSCommand implementation for movies to communicate with
pub fn with_fs_commands(mut self, provider: Box<dyn FsCommandProvider>) -> Self {
self.fs_command_provider = provider;
self
}
fn create_gc_root<'gc>( fn create_gc_root<'gc>(
gc_context: &'gc gc_arena::Mutation<'gc>, gc_context: &'gc gc_arena::Mutation<'gc>,
player_version: u8, player_version: u8,
fullscreen: bool, fullscreen: bool,
fake_movie: Arc<SwfMovie>, fake_movie: Arc<SwfMovie>,
external_interface_providers: Vec<Box<dyn ExternalInterfaceProvider>>, external_interface_providers: Vec<Box<dyn ExternalInterfaceProvider>>,
fs_command_provider: Box<dyn FsCommandProvider>,
) -> GcRoot<'gc> { ) -> GcRoot<'gc> {
let mut interner = AvmStringInterner::new(); let mut interner = AvmStringInterner::new();
let mut init = GcContext { let mut init = GcContext {
@ -2344,7 +2353,10 @@ impl PlayerBuilder {
interner, interner,
current_context_menu: None, current_context_menu: None,
drag_object: 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), focus_tracker: FocusTracker::new(gc_context),
library: Library::empty(), library: Library::empty(),
load_manager: LoadManager::new(), load_manager: LoadManager::new(),
@ -2459,6 +2471,7 @@ impl PlayerBuilder {
self.fullscreen, self.fullscreen,
fake_movie.clone(), fake_movie.clone(),
self.external_interface_providers, self.external_interface_providers,
self.fs_command_provider,
) )
}, },
))), ))),

View File

@ -9,8 +9,4 @@ impl ExternalInterfaceProvider for DesktopExternalInterfaceProvider {
} }
fn on_callback_available(&self, _name: &str) {} fn on_callback_available(&self, _name: &str) {}
fn on_fs_command(&self, _command: &str, _args: &str) -> bool {
false
}
} }

View File

@ -47,8 +47,4 @@ impl ExternalInterfaceProvider for ExternalInterfaceTestProvider {
} }
fn on_callback_available(&self, _name: &str) {} fn on_callback_available(&self, _name: &str) {}
fn on_fs_command(&self, _command: &str, _args: &str) -> bool {
false
}
} }

View File

@ -15,7 +15,8 @@ use ruffle_core::config::{Letterbox, NetworkingAccessMode};
use ruffle_core::context::UpdateContext; use ruffle_core::context::UpdateContext;
use ruffle_core::events::{KeyCode, MouseButton, MouseWheelDelta, TextControlCode}; use ruffle_core::events::{KeyCode, MouseButton, MouseWheelDelta, TextControlCode};
use ruffle_core::external::{ 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::tag_utils::SwfMovie;
use ruffle_core::{ use ruffle_core::{
@ -1436,7 +1437,9 @@ impl ExternalInterfaceProvider for JavascriptInterface {
fn on_callback_available(&self, name: &str) { fn on_callback_available(&self, name: &str) {
self.js_player.on_callback_available(name); self.js_player.on_callback_available(name);
} }
}
impl FsCommandProvider for JavascriptInterface {
fn on_fs_command(&self, command: &str, args: &str) -> bool { fn on_fs_command(&self, command: &str, args: &str) -> bool {
self.js_player self.js_player
.on_fs_command(command, args) .on_fs_command(command, args)