avm2: Add an option to simulate event dispatch

This commit is contained in:
Kamil Jarosz 2024-07-07 13:04:13 +02:00 committed by TÖRÖK Attila
parent ebfff6aea1
commit 010310dd1b
3 changed files with 39 additions and 8 deletions

View File

@ -431,13 +431,36 @@ impl<'gc> Avm2<'gc> {
/// Dispatch an event on an object.
///
/// This will become its own self-contained activation and swallow
/// any resulting resulting error (after logging).
/// any resulting error (after logging).
///
/// Attempts to dispatch a non-event object will panic.
pub fn dispatch_event(
context: &mut UpdateContext<'_, 'gc>,
event: Object<'gc>,
target: Object<'gc>,
) {
Self::dispatch_event_internal(context, event, target, false)
}
/// Simulate dispatching an event.
///
/// This method is similar to [`Self::dispatch_event`],
/// but it does not execute event handlers.
///
/// Returns `true` when the event would have been handled if not simulated.
pub fn simulate_event_dispatch(
context: &mut UpdateContext<'_, 'gc>,
event: Object<'gc>,
target: Object<'gc>,
) {
Self::dispatch_event_internal(context, event, target, true)
}
fn dispatch_event_internal(
context: &mut UpdateContext<'_, 'gc>,
event: Object<'gc>,
target: Object<'gc>,
simulate_dispatch: bool,
) {
let event_name = event
.as_event()
@ -445,7 +468,8 @@ impl<'gc> Avm2<'gc> {
.unwrap_or_else(|| panic!("cannot dispatch non-event object: {:?}", event));
let mut activation = Activation::from_nothing(context.reborrow());
if let Err(err) = events::dispatch_event(&mut activation, target, event) {
if let Err(err) = events::dispatch_event(&mut activation, target, event, simulate_dispatch)
{
tracing::error!(
"Encountered AVM2 error when dispatching `{}` event: {:?}",
event_name,
@ -537,7 +561,8 @@ impl<'gc> Avm2<'gc> {
let mut activation = Activation::from_nothing(context.reborrow());
if object.is_of_type(on_type.inner_class_definition()) {
if let Err(err) = events::dispatch_event(&mut activation, object, event) {
if let Err(err) = events::dispatch_event(&mut activation, object, event, false)
{
tracing::error!(
"Encountered AVM2 error when broadcasting `{}` event: {:?}",
event_name,

View File

@ -370,11 +370,12 @@ pub fn parent_of(target: Object<'_>) -> Option<Object<'_>> {
/// `EventObject`, or this function will panic. You must have already set the
/// event's phase to match what targets you are dispatching to, or you will
/// call the wrong handlers.
pub fn dispatch_event_to_target<'gc>(
fn dispatch_event_to_target<'gc>(
activation: &mut Activation<'_, 'gc>,
dispatcher: Object<'gc>,
target: Object<'gc>,
event: Object<'gc>,
simulate_dispatch: bool,
) -> Result<(), Error<'gc>> {
avm_debug!(
activation.context.avm2,
@ -413,6 +414,10 @@ pub fn dispatch_event_to_target<'gc>(
drop(evtmut);
if simulate_dispatch {
return Ok(());
}
for handler in handlers.iter() {
if event
.as_event()
@ -441,6 +446,7 @@ pub fn dispatch_event<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Object<'gc>,
event: Object<'gc>,
simulate_dispatch: bool,
) -> Result<bool, Error<'gc>> {
let target = this
.get_property(
@ -486,7 +492,7 @@ pub fn dispatch_event<'gc>(
break;
}
dispatch_event_to_target(activation, *ancestor, *ancestor, event)?;
dispatch_event_to_target(activation, *ancestor, *ancestor, event, simulate_dispatch)?;
}
event
@ -495,7 +501,7 @@ pub fn dispatch_event<'gc>(
.set_phase(EventPhase::AtTarget);
if !event.as_event().unwrap().is_propagation_stopped() {
dispatch_event_to_target(activation, this, target, event)?;
dispatch_event_to_target(activation, this, target, event, simulate_dispatch)?;
}
event
@ -509,7 +515,7 @@ pub fn dispatch_event<'gc>(
break;
}
dispatch_event_to_target(activation, *ancestor, *ancestor, event)?;
dispatch_event_to_target(activation, *ancestor, *ancestor, event, simulate_dispatch)?;
}
}

View File

@ -139,7 +139,7 @@ pub fn dispatch_event<'gc>(
return Err("Dispatched Events must be subclasses of Event.".into());
}
Ok(dispatch_event_internal(activation, this, event)?.into())
Ok(dispatch_event_internal(activation, this, event, false)?.into())
}
/// Implements `EventDispatcher.toString`.