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 {
fn get_method(&self, name: &str) -> Option<Box<dyn ExternalInterfaceMethod>>;
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<Box<dyn ExternalInterfaceProvider>>,
callbacks: BTreeMap<String, Callback<'gc>>,
#[collect(require_static)]
fs_commands: Box<dyn FsCommandProvider>,
}
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 {
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)
}
}

View File

@ -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<f64>,
external_interface_providers: Vec<Box<dyn ExternalInterfaceProvider>>,
fs_command_provider: Box<dyn FsCommandProvider>,
}
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<dyn FsCommandProvider>) -> 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<SwfMovie>,
external_interface_providers: Vec<Box<dyn ExternalInterfaceProvider>>,
fs_command_provider: Box<dyn FsCommandProvider>,
) -> 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,
)
},
))),

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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)