From eb3aa1c8788dec98c388d1fc95c821127772a7f3 Mon Sep 17 00:00:00 2001 From: Mike Welsh Date: Sun, 1 Dec 2019 16:07:13 -0800 Subject: [PATCH] core: Move `ClipAction` into crate::events --- core/src/display_object.rs | 14 +++- core/src/display_object/movie_clip.rs | 114 +++++++++++++++++++------- core/src/events.rs | 28 ++++++- 3 files changed, 124 insertions(+), 32 deletions(-) diff --git a/core/src/display_object.rs b/core/src/display_object.rs index ae5ccfb1f..ef8a2ac85 100644 --- a/core/src/display_object.rs +++ b/core/src/display_object.rs @@ -657,7 +657,17 @@ pub trait TDisplayObject<'gc>: 'gc + Collect + Debug { } // Clip events only apply to movie clips. if let Some(clip) = self.as_movie_clip() { - clip.set_clip_actions(gc_context, &place_object.clip_actions[..]); + // Convert from `swf::ClipAction` to Ruffle's `ClipAction`. + use crate::display_object::movie_clip::ClipAction; + clip.set_clip_actions( + gc_context, + place_object + .clip_actions + .iter() + .cloned() + .map(ClipAction::from) + .collect(), + ); } // TODO: Others will go here eventually. } @@ -677,7 +687,7 @@ pub trait TDisplayObject<'gc>: 'gc + Collect + Debug { } // onEnterFrame actions only apply to movie clips. if let (Some(me), Some(other)) = (self.as_movie_clip(), other.as_movie_clip()) { - me.set_clip_actions(gc_context, &*other.clip_actions()); + me.set_clip_actions(gc_context, other.clip_actions().iter().cloned().collect()); } // TODO: More in here eventually. } diff --git a/core/src/display_object/movie_clip.rs b/core/src/display_object/movie_clip.rs index d48be60b1..774d4838c 100644 --- a/core/src/display_object/movie_clip.rs +++ b/core/src/display_object/movie_clip.rs @@ -6,14 +6,16 @@ use crate::context::{ActionType, RenderContext, UpdateContext}; use crate::display_object::{ Bitmap, Button, DisplayObjectBase, EditText, Graphic, MorphShapeStatic, TDisplayObject, Text, }; +use crate::events::ClipEvent; use crate::font::Font; use crate::prelude::*; -use crate::tag_utils::{self, DecodeResult, SwfStream}; +use crate::tag_utils::{self, DecodeResult, SwfSlice, SwfStream}; use enumset::{EnumSet, EnumSetType}; use gc_arena::{Collect, Gc, GcCell, MutationContext}; use smallvec::SmallVec; +use std::cell::Ref; use std::collections::{BTreeMap, HashMap}; -use swf::{read::SwfRead, ClipAction, ClipEventFlag}; +use swf::read::SwfRead; type Depth = i16; type FrameNumber = u16; @@ -166,14 +168,18 @@ impl<'gc> MovieClip<'gc> { } /// Gets the clip events for this movieclip. - pub fn clip_actions(&self) -> std::cell::Ref<[ClipAction]> { - std::cell::Ref::map(self.0.read(), |mc| mc.clip_actions()) + pub fn clip_actions(&self) -> Ref<[ClipAction]> { + Ref::map(self.0.read(), |mc| mc.clip_actions()) } /// Sets the clip actions (a.k.a. clip events) for this movieclip. /// Clip actions are created in the Flash IDE by using the `onEnterFrame` /// tag on a movieclip instance. - pub fn set_clip_actions(&self, gc_context: MutationContext<'gc, '_>, actions: &[ClipAction]) { + pub fn set_clip_actions( + self, + gc_context: MutationContext<'gc, '_>, + actions: SmallVec<[ClipAction; 2]>, + ) { self.0.write(gc_context).set_clip_actions(actions); } } @@ -246,9 +252,11 @@ impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> { } fn unload(&mut self, context: &mut UpdateContext<'_, 'gc, '_>) { - self.0 - .write(context.gc_context) - .run_clip_action(context, ClipEventFlag::Unload, None); + self.0.write(context.gc_context).run_clip_action( + (*self).into(), + context, + ClipEvent::Unload, + ); self.set_removed(context.gc_context, true); } } @@ -379,10 +387,10 @@ impl<'gc> MovieClipData<'gc> { // Run my load/enterFrame clip event. if !self.initialized() { - self.run_clip_action(context, ClipEventFlag::Load, None); + self.run_clip_action(self_display_object, context, ClipEvent::Load); self.set_initialized(true); } else { - self.run_clip_action(context, ClipEventFlag::EnterFrame, None); + self.run_clip_action(self_display_object, context, ClipEvent::EnterFrame); } let _tag_pos = self.tag_stream_pos; @@ -709,37 +717,34 @@ impl<'gc> MovieClipData<'gc> { /// Run all actions for the given clip event. fn run_clip_action( &self, + self_display_object: DisplayObject<'gc>, context: &mut UpdateContext<'_, 'gc, '_>, - event: ClipEventFlag, - key_code: Option, + event: ClipEvent, ) { for clip_action in self .clip_actions .iter() - .filter(|action| action.events.contains(event) && action.key_code == key_code) + .filter(|action| action.events.contains(&event)) { - let slice = crate::tag_utils::SwfSlice { - data: std::sync::Arc::new(clip_action.action_data.clone()), - start: 0, - end: clip_action.action_data.len(), - }; - let action_type = if event == ClipEventFlag::Unload { + let action_type = if event == ClipEvent::Unload { ActionType::Unload } else { ActionType::Normal }; - context - .action_queue - .queue_actions(context.active_clip, slice, action_type); + context.action_queue.queue_actions( + self_display_object, + clip_action.action_data.clone(), + action_type, + ); } } - fn clip_actions(&self) -> &[ClipAction] { - &self.clip_actions[..] + pub fn clip_actions(&self) -> &[ClipAction] { + &self.clip_actions } - fn set_clip_actions(&mut self, actions: &[ClipAction]) { - self.clip_actions = actions.iter().cloned().collect(); + pub fn set_clip_actions(&mut self, actions: SmallVec<[ClipAction; 2]>) { + self.clip_actions = actions; } fn initialized(&self) -> bool { @@ -1369,7 +1374,7 @@ impl<'gc, 'a> MovieClipData<'gc> { // so make sure to get the proper offsets. This feels kind of bad. let start = (self.tag_stream_start() + reader.get_ref().position()) as usize; let end = start + tag_len; - let slice = crate::tag_utils::SwfSlice { + let slice = SwfSlice { data: std::sync::Arc::clone(context.swf_data), start, end, @@ -1399,7 +1404,7 @@ impl<'gc, 'a> MovieClipData<'gc> { // so make sure to get the proper offsets. This feels kind of bad. let start = (self.tag_stream_start() + reader.get_ref().position()) as usize; let end = start + tag_len; - let slice = crate::tag_utils::SwfSlice { + let slice = SwfSlice { data: std::sync::Arc::clone(context.swf_data), start, end, @@ -1494,7 +1499,7 @@ impl<'gc, 'a> MovieClipData<'gc> { if let (Some(stream_info), None) = (&self.static_data.audio_stream_info, self.audio_stream) { let pos = self.tag_stream_start() + self.tag_stream_pos; - let slice = crate::tag_utils::SwfSlice { + let slice = SwfSlice { data: std::sync::Arc::clone(context.swf_data), start: pos as usize, end: self.tag_stream_start() as usize + self.tag_stream_len(), @@ -1646,3 +1651,54 @@ enum MovieClipFlags { /// Whether this `MovieClip` is playing or stopped. Playing, } + +/// Actions that are attached to a `MovieClip` event in +/// an `onClipEvent`/`on` handler. +#[derive(Debug, Clone)] +pub struct ClipAction { + /// The events that trigger this handler. + events: SmallVec<[ClipEvent; 1]>, + + /// The actions to run. + action_data: SwfSlice, +} + +impl From for ClipAction { + fn from(other: swf::ClipAction) -> Self { + use swf::ClipEventFlag; + Self { + events: other + .events + .into_iter() + .map(|event| match event { + ClipEventFlag::Construct => ClipEvent::Construct, + ClipEventFlag::Data => ClipEvent::Data, + ClipEventFlag::DragOut => ClipEvent::DragOut, + ClipEventFlag::DragOver => ClipEvent::DragOver, + ClipEventFlag::EnterFrame => ClipEvent::EnterFrame, + ClipEventFlag::Initialize => ClipEvent::Initialize, + ClipEventFlag::KeyUp => ClipEvent::KeyUp, + ClipEventFlag::KeyDown => ClipEvent::KeyDown, + ClipEventFlag::KeyPress => ClipEvent::KeyPress { + key_code: other.key_code.unwrap_or(0), + }, + ClipEventFlag::Load => ClipEvent::Load, + ClipEventFlag::MouseUp => ClipEvent::MouseUp, + ClipEventFlag::MouseDown => ClipEvent::MouseDown, + ClipEventFlag::MouseMove => ClipEvent::MouseMove, + ClipEventFlag::Press => ClipEvent::Press, + ClipEventFlag::RollOut => ClipEvent::RollOut, + ClipEventFlag::RollOver => ClipEvent::RollOver, + ClipEventFlag::Release => ClipEvent::Release, + ClipEventFlag::ReleaseOutside => ClipEvent::ReleaseOutside, + ClipEventFlag::Unload => ClipEvent::Unload, + }) + .collect(), + action_data: SwfSlice { + data: std::sync::Arc::new(other.action_data.clone()), + start: 0, + end: other.action_data.len(), + }, + } + } +} diff --git a/core/src/events.rs b/core/src/events.rs index 1efdf6c53..8c4c323a7 100644 --- a/core/src/events.rs +++ b/core/src/events.rs @@ -25,6 +25,32 @@ pub enum ButtonEvent { KeyPress(KeyCode), } +/// An event type that can be handled by a movie clip +/// instance. +/// TODO: Move this representation in the swf crate? +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ClipEvent { + Construct, + Data, + DragOut, + DragOver, + EnterFrame, + Initialize, + KeyUp, + KeyDown, + KeyPress { key_code: KeyCode }, + Load, + MouseUp, + MouseDown, + MouseMove, + Press, + RollOut, + RollOver, + Release, + ReleaseOutside, + Unload, +} + /// Flash virtual keycode. /// TODO: This will eventually move to a separate module. -pub type KeyCode = u8; +pub type KeyCode = swf::KeyCode;