core: Move `ClipAction` into crate::events

This commit is contained in:
Mike Welsh 2019-12-01 16:07:13 -08:00
parent 1fe170400c
commit eb3aa1c878
3 changed files with 124 additions and 32 deletions

View File

@ -657,7 +657,17 @@ pub trait TDisplayObject<'gc>: 'gc + Collect + Debug {
} }
// Clip events only apply to movie clips. // Clip events only apply to movie clips.
if let Some(clip) = self.as_movie_clip() { 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. // TODO: Others will go here eventually.
} }
@ -677,7 +687,7 @@ pub trait TDisplayObject<'gc>: 'gc + Collect + Debug {
} }
// onEnterFrame actions only apply to movie clips. // onEnterFrame actions only apply to movie clips.
if let (Some(me), Some(other)) = (self.as_movie_clip(), other.as_movie_clip()) { 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. // TODO: More in here eventually.
} }

View File

@ -6,14 +6,16 @@ use crate::context::{ActionType, RenderContext, UpdateContext};
use crate::display_object::{ use crate::display_object::{
Bitmap, Button, DisplayObjectBase, EditText, Graphic, MorphShapeStatic, TDisplayObject, Text, Bitmap, Button, DisplayObjectBase, EditText, Graphic, MorphShapeStatic, TDisplayObject, Text,
}; };
use crate::events::ClipEvent;
use crate::font::Font; use crate::font::Font;
use crate::prelude::*; use crate::prelude::*;
use crate::tag_utils::{self, DecodeResult, SwfStream}; use crate::tag_utils::{self, DecodeResult, SwfSlice, SwfStream};
use enumset::{EnumSet, EnumSetType}; use enumset::{EnumSet, EnumSetType};
use gc_arena::{Collect, Gc, GcCell, MutationContext}; use gc_arena::{Collect, Gc, GcCell, MutationContext};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::cell::Ref;
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use swf::{read::SwfRead, ClipAction, ClipEventFlag}; use swf::read::SwfRead;
type Depth = i16; type Depth = i16;
type FrameNumber = u16; type FrameNumber = u16;
@ -166,14 +168,18 @@ impl<'gc> MovieClip<'gc> {
} }
/// Gets the clip events for this movieclip. /// Gets the clip events for this movieclip.
pub fn clip_actions(&self) -> std::cell::Ref<[ClipAction]> { pub fn clip_actions(&self) -> Ref<[ClipAction]> {
std::cell::Ref::map(self.0.read(), |mc| mc.clip_actions()) Ref::map(self.0.read(), |mc| mc.clip_actions())
} }
/// Sets the clip actions (a.k.a. clip events) for this movieclip. /// Sets the clip actions (a.k.a. clip events) for this movieclip.
/// Clip actions are created in the Flash IDE by using the `onEnterFrame` /// Clip actions are created in the Flash IDE by using the `onEnterFrame`
/// tag on a movieclip instance. /// 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); 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, '_>) { fn unload(&mut self, context: &mut UpdateContext<'_, 'gc, '_>) {
self.0 self.0.write(context.gc_context).run_clip_action(
.write(context.gc_context) (*self).into(),
.run_clip_action(context, ClipEventFlag::Unload, None); context,
ClipEvent::Unload,
);
self.set_removed(context.gc_context, true); self.set_removed(context.gc_context, true);
} }
} }
@ -379,10 +387,10 @@ impl<'gc> MovieClipData<'gc> {
// Run my load/enterFrame clip event. // Run my load/enterFrame clip event.
if !self.initialized() { 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); self.set_initialized(true);
} else { } 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; let _tag_pos = self.tag_stream_pos;
@ -709,37 +717,34 @@ impl<'gc> MovieClipData<'gc> {
/// Run all actions for the given clip event. /// Run all actions for the given clip event.
fn run_clip_action( fn run_clip_action(
&self, &self,
self_display_object: DisplayObject<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>, context: &mut UpdateContext<'_, 'gc, '_>,
event: ClipEventFlag, event: ClipEvent,
key_code: Option<u8>,
) { ) {
for clip_action in self for clip_action in self
.clip_actions .clip_actions
.iter() .iter()
.filter(|action| action.events.contains(event) && action.key_code == key_code) .filter(|action| action.events.contains(&event))
{ {
let slice = crate::tag_utils::SwfSlice { let action_type = if event == ClipEvent::Unload {
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 {
ActionType::Unload ActionType::Unload
} else { } else {
ActionType::Normal ActionType::Normal
}; };
context context.action_queue.queue_actions(
.action_queue self_display_object,
.queue_actions(context.active_clip, slice, action_type); clip_action.action_data.clone(),
action_type,
);
} }
} }
fn clip_actions(&self) -> &[ClipAction] { pub fn clip_actions(&self) -> &[ClipAction] {
&self.clip_actions[..] &self.clip_actions
} }
fn set_clip_actions(&mut self, actions: &[ClipAction]) { pub fn set_clip_actions(&mut self, actions: SmallVec<[ClipAction; 2]>) {
self.clip_actions = actions.iter().cloned().collect(); self.clip_actions = actions;
} }
fn initialized(&self) -> bool { 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. // 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 start = (self.tag_stream_start() + reader.get_ref().position()) as usize;
let end = start + tag_len; let end = start + tag_len;
let slice = crate::tag_utils::SwfSlice { let slice = SwfSlice {
data: std::sync::Arc::clone(context.swf_data), data: std::sync::Arc::clone(context.swf_data),
start, start,
end, end,
@ -1399,7 +1404,7 @@ impl<'gc, 'a> MovieClipData<'gc> {
// so make sure to get the proper offsets. This feels kind of bad. // 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 start = (self.tag_stream_start() + reader.get_ref().position()) as usize;
let end = start + tag_len; let end = start + tag_len;
let slice = crate::tag_utils::SwfSlice { let slice = SwfSlice {
data: std::sync::Arc::clone(context.swf_data), data: std::sync::Arc::clone(context.swf_data),
start, start,
end, 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) 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 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), data: std::sync::Arc::clone(context.swf_data),
start: pos as usize, start: pos as usize,
end: self.tag_stream_start() as usize + self.tag_stream_len(), end: self.tag_stream_start() as usize + self.tag_stream_len(),
@ -1646,3 +1651,54 @@ enum MovieClipFlags {
/// Whether this `MovieClip` is playing or stopped. /// Whether this `MovieClip` is playing or stopped.
Playing, 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<swf::ClipAction> 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(),
},
}
}
}

View File

@ -25,6 +25,32 @@ pub enum ButtonEvent {
KeyPress(KeyCode), 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. /// Flash virtual keycode.
/// TODO: This will eventually move to a separate module. /// TODO: This will eventually move to a separate module.
pub type KeyCode = u8; pub type KeyCode = swf::KeyCode;