core: Add Stub and StubCollection for tracking stubs used during a movie

This commit is contained in:
Nathan Adams 2023-01-31 16:45:14 +01:00
parent caaf6d5c87
commit 4a0529dedc
4 changed files with 69 additions and 0 deletions

View File

@ -20,6 +20,7 @@ use crate::library::Library;
use crate::loader::LoadManager;
use crate::player::Player;
use crate::prelude::*;
use crate::stub::StubCollection;
use crate::tag_utils::{SwfMovie, SwfSlice};
use crate::timer::Timers;
use core::fmt;
@ -45,6 +46,9 @@ pub struct UpdateContext<'a, 'gc> {
/// The mutation context to allocate and mutate `GcCell` types.
pub gc_context: MutationContext<'gc, 'a>,
/// A collection of stubs encountered during this movie.
pub stub_tracker: &'a mut StubCollection,
/// The library containing character definitions for this SWF.
/// Used to instantiate a `DisplayObject` of a given ID.
pub library: &'a mut Library<'gc>,
@ -300,6 +304,7 @@ impl<'a, 'gc> UpdateContext<'a, 'gc> {
UpdateContext {
action_queue: self.action_queue,
gc_context: self.gc_context,
stub_tracker: self.stub_tracker,
library: self.library,
player_version: self.player_version,
needs_render: self.needs_render,

View File

@ -45,6 +45,7 @@ mod xml;
pub mod backend;
pub mod config;
pub mod external;
pub mod stub;
pub use context_menu::ContextMenuItem;
pub use events::PlayerEvent;

View File

@ -37,6 +37,7 @@ use crate::loader::{LoadBehavior, LoadManager};
use crate::locale::get_current_date_time;
use crate::prelude::*;
use crate::string::AvmString;
use crate::stub::StubCollection;
use crate::tag_utils::SwfMovie;
use crate::timer::Timers;
use crate::vminterface::Instantiator;
@ -240,6 +241,8 @@ pub struct Player {
frame_phase: FramePhase,
stub_tracker: StubCollection,
/// A time budget for executing frames.
/// Gained by passage of time between host frames, spent by executing SWF frames.
/// This is how we support custom SWF framerates
@ -1742,6 +1745,7 @@ impl Player {
frame_rate: &mut self.frame_rate,
actions_since_timeout_check: &mut self.actions_since_timeout_check,
frame_phase: &mut self.frame_phase,
stub_tracker: &mut self.stub_tracker,
};
let old_frame_rate = *update_context.frame_rate;
@ -2165,6 +2169,7 @@ impl PlayerBuilder {
self_reference: self_ref.clone(),
load_behavior: self.load_behavior,
spoofed_url: self.spoofed_url.clone(),
stub_tracker: StubCollection::new(),
// GC data
gc_arena: Rc::new(RefCell::new(GcArena::new(

58
core/src/stub.rs Normal file
View File

@ -0,0 +1,58 @@
use fnv::FnvHashSet;
use std::borrow::Cow;
use std::collections::hash_set::Iter;
use std::fmt::{Debug, Display, Formatter};
#[derive(Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Clone)]
pub enum Stub {
Avm1Method {
class: &'static str,
method: &'static str,
specifics: Option<Cow<'static, str>>,
},
Other(Cow<'static, str>),
}
impl Display for Stub {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Stub::Avm1Method {
class,
method,
specifics: None,
} => {
write!(f, "AVM1 {class}.{method}")
}
Stub::Avm1Method {
class,
method,
specifics: Some(specifics),
} => {
write!(f, "AVM1 {class}.{method} {specifics}")
}
Stub::Other(text) => write!(f, "{text}"),
}
}
}
#[derive(Debug, Default)]
pub struct StubCollection {
inner: FnvHashSet<Stub>,
}
impl StubCollection {
pub fn new() -> Self {
Self::default()
}
pub fn encounter(&mut self, stub: Stub) {
if !self.inner.contains(&stub) {
tracing::warn!("Encountered stub: {stub}");
self.inner.insert(stub);
}
}
pub fn iter(&self) -> Iter<Stub> {
self.inner.iter()
}
}