From 010310dd1bd07c292cf641e71745115bc2f38d99 Mon Sep 17 00:00:00 2001 From: Kamil Jarosz Date: Sun, 7 Jul 2024 13:04:13 +0200 Subject: [PATCH] avm2: Add an option to simulate event dispatch --- core/src/avm2.rs | 31 +++++++++++++++++-- core/src/avm2/events.rs | 14 ++++++--- .../globals/flash/events/event_dispatcher.rs | 2 +- 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/core/src/avm2.rs b/core/src/avm2.rs index 9383a460b..98e6f59c1 100644 --- a/core/src/avm2.rs +++ b/core/src/avm2.rs @@ -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, diff --git a/core/src/avm2/events.rs b/core/src/avm2/events.rs index 8d2375db9..0b55c24cd 100644 --- a/core/src/avm2/events.rs +++ b/core/src/avm2/events.rs @@ -370,11 +370,12 @@ pub fn parent_of(target: Object<'_>) -> Option> { /// `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> { 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)?; } } diff --git a/core/src/avm2/globals/flash/events/event_dispatcher.rs b/core/src/avm2/globals/flash/events/event_dispatcher.rs index e0e51d3b7..4e95f31f3 100644 --- a/core/src/avm2/globals/flash/events/event_dispatcher.rs +++ b/core/src/avm2/globals/flash/events/event_dispatcher.rs @@ -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`.