From 19662503caa08e226866bfa760ff97cee11e1911 Mon Sep 17 00:00:00 2001 From: relrelb Date: Sat, 23 Jan 2021 02:47:29 +0200 Subject: [PATCH] swf: Convert ButtonActionCondition to bitflags --- core/src/display_object/button.rs | 43 ++++++++++------ core/src/display_object/movie_clip.rs | 6 +-- swf/src/read.rs | 39 ++------------ swf/src/test_data.rs | 26 +++------- swf/src/types.rs | 28 +++++----- swf/src/write.rs | 74 ++------------------------- 6 files changed, 59 insertions(+), 157 deletions(-) diff --git a/core/src/display_object/button.rs b/core/src/display_object/button.rs index de519ee06..5687c7a9e 100644 --- a/core/src/display_object/button.rs +++ b/core/src/display_object/button.rs @@ -11,6 +11,7 @@ use gc_arena::{Collect, GcCell, MutationContext}; use std::collections::BTreeMap; use std::convert::TryFrom; use std::sync::Arc; +use swf::ButtonActionCondition; #[derive(Clone, Debug, Collect, Copy)] #[collect(no_drop)] @@ -42,15 +43,19 @@ impl<'gc> Button<'gc> { let action_data = source_movie .to_unbounded_subslice(action.action_data) .unwrap(); - for condition in &action.conditions { - let button_action = ButtonAction { - action_data: action_data.clone(), - condition: *condition, - key_code: action - .key_code - .and_then(|k| ButtonKeyCode::try_from(k).ok()), - }; - actions.push(button_action); + let bits = action.conditions.bits(); + let mut bit = 1u16; + while bits & !(bit - 1) != 0 { + if bits & bit != 0 { + actions.push(ButtonAction { + action_data: action_data.clone(), + condition: ButtonActionCondition::from_bits_truncate(bit), + key_code: action + .key_code + .and_then(|k| ButtonKeyCode::try_from(k).ok()), + }); + } + bit <<= 1; } } @@ -406,7 +411,7 @@ impl<'gc> TDisplayObject<'gc> for Button<'gc> { ClipEvent::KeyPress { key_code } => { handled = write.run_actions( context, - swf::ButtonActionCondition::KeyPress, + swf::ButtonActionCondition::KEY_PRESS, Some(key_code), ); cur_state @@ -416,22 +421,30 @@ impl<'gc> TDisplayObject<'gc> for Button<'gc> { match (cur_state, new_state) { (ButtonState::Up, ButtonState::Over) => { - write.run_actions(context, swf::ButtonActionCondition::IdleToOverUp, None); + write.run_actions(context, swf::ButtonActionCondition::IDLE_TO_OVER_UP, None); write.play_sound(context, write.static_data.read().up_to_over_sound.as_ref()); } (ButtonState::Over, ButtonState::Up) => { - write.run_actions(context, swf::ButtonActionCondition::OverUpToIdle, None); + write.run_actions(context, swf::ButtonActionCondition::OVER_UP_TO_IDLE, None); write.play_sound(context, write.static_data.read().over_to_up_sound.as_ref()); } (ButtonState::Over, ButtonState::Down) => { - write.run_actions(context, swf::ButtonActionCondition::OverUpToOverDown, None); + write.run_actions( + context, + swf::ButtonActionCondition::OVER_UP_TO_OVER_DOWN, + None, + ); write.play_sound( context, write.static_data.read().over_to_down_sound.as_ref(), ); } (ButtonState::Down, ButtonState::Over) => { - write.run_actions(context, swf::ButtonActionCondition::OverDownToOverUp, None); + write.run_actions( + context, + swf::ButtonActionCondition::OVER_DOWN_TO_OVER_UP, + None, + ); write.play_sound( context, write.static_data.read().down_to_over_sound.as_ref(), @@ -512,7 +525,7 @@ impl<'gc> ButtonData<'gc> { if let Some(parent) = self.base.parent { for action in &self.static_data.read().actions { if action.condition == condition - && (action.condition != swf::ButtonActionCondition::KeyPress + && (action.condition != swf::ButtonActionCondition::KEY_PRESS || action.key_code == key_code) { // Note that AVM1 buttons run actions relative to their parent, not themselves. diff --git a/core/src/display_object/movie_clip.rs b/core/src/display_object/movie_clip.rs index 6dbdd67d2..e5390f78b 100644 --- a/core/src/display_object/movie_clip.rs +++ b/core/src/display_object/movie_clip.rs @@ -3108,10 +3108,10 @@ impl ClipAction { .unwrap(); let mut events = Vec::new(); - let flags = other.events.bits(); + let bits = other.events.bits(); let mut bit = 1u32; - while flags & !(bit - 1) != 0 { - if (flags & bit) != 0 { + while bits & !(bit - 1) != 0 { + if bits & bit != 0 { events.push(ClipEventFlag::from_bits_truncate(bit)); } bit <<= 1; diff --git a/swf/src/read.rs b/swf/src/read.rs index 2949a46c4..3a2d228d1 100644 --- a/swf/src/read.rs +++ b/swf/src/read.rs @@ -13,7 +13,6 @@ use crate::{ }; use bitstream_io::BitRead; use byteorder::{LittleEndian, ReadBytesExt}; -use std::collections::HashSet; use std::io::{self, Read}; /// Parse a decompressed SWF and return a `Vec` of tags. @@ -802,9 +801,7 @@ impl<'a> Reader<'a> { is_track_as_menu: false, records, actions: vec![ButtonAction { - conditions: vec![ButtonActionCondition::OverDownToOverUp] - .into_iter() - .collect(), + conditions: ButtonActionCondition::OVER_DOWN_TO_OVER_UP, key_code: None, action_data, }], @@ -937,39 +934,9 @@ impl<'a> Reader<'a> { fn read_button_action(&mut self) -> Result<(ButtonAction<'a>, bool)> { let length = self.read_u16()?; let flags = self.read_u16()?; - let mut conditions = HashSet::with_capacity(8); - if (flags & 0b1) != 0 { - conditions.insert(ButtonActionCondition::IdleToOverUp); - } - if (flags & 0b10) != 0 { - conditions.insert(ButtonActionCondition::OverUpToIdle); - } - if (flags & 0b100) != 0 { - conditions.insert(ButtonActionCondition::OverUpToOverDown); - } - if (flags & 0b1000) != 0 { - conditions.insert(ButtonActionCondition::OverDownToOverUp); - } - if (flags & 0b1_0000) != 0 { - conditions.insert(ButtonActionCondition::OverDownToOutDown); - } - if (flags & 0b10_0000) != 0 { - conditions.insert(ButtonActionCondition::OutDownToOverDown); - } - if (flags & 0b100_0000) != 0 { - conditions.insert(ButtonActionCondition::OutDownToIdle); - } - if (flags & 0b1000_0000) != 0 { - conditions.insert(ButtonActionCondition::IdleToOverDown); - } - - if (flags & 0b1_0000_0000) != 0 { - conditions.insert(ButtonActionCondition::OverDownToIdle); - } + let mut conditions = ButtonActionCondition::from_bits_truncate(flags); let key_code = (flags >> 9) as u8; - if key_code != 0 { - conditions.insert(ButtonActionCondition::KeyPress); - } + conditions.set(ButtonActionCondition::KEY_PRESS, key_code != 0); let action_data = if length >= 4 { self.read_slice(length as usize - 4)? } else if length == 0 { diff --git a/swf/src/test_data.rs b/swf/src/test_data.rs index 1174d3c58..f4f8a5158 100644 --- a/swf/src/test_data.rs +++ b/swf/src/test_data.rs @@ -201,9 +201,7 @@ pub fn tag_tests() -> Vec { records: vec![ ButtonRecord { id: 1, - states: vec![ButtonState::Up, ButtonState::Over] - .into_iter() - .collect(), + states: ButtonState::UP | ButtonState::OVER, depth: 1, matrix: Matrix::identity(), color_transform: ColorTransform::new(), @@ -212,9 +210,7 @@ pub fn tag_tests() -> Vec { }, ButtonRecord { id: 2, - states: vec![ButtonState::Down, ButtonState::HitTest] - .into_iter() - .collect(), + states: ButtonState::DOWN | ButtonState::HIT_TEST, depth: 1, matrix: Matrix::identity(), color_transform: ColorTransform::new(), @@ -223,9 +219,7 @@ pub fn tag_tests() -> Vec { }, ], actions: vec![ButtonAction { - conditions: vec![ButtonActionCondition::OverDownToOverUp] - .into_iter() - .collect(), + conditions: ButtonActionCondition::OVER_DOWN_TO_OVER_UP, key_code: None, action_data: &[0], }], @@ -240,9 +234,7 @@ pub fn tag_tests() -> Vec { records: vec![ ButtonRecord { id: 2, - states: vec![ButtonState::Up, ButtonState::Over] - .into_iter() - .collect(), + states: ButtonState::UP | ButtonState::OVER, depth: 1, matrix: Matrix::identity(), color_transform: ColorTransform { @@ -264,9 +256,7 @@ pub fn tag_tests() -> Vec { }, ButtonRecord { id: 3, - states: vec![ButtonState::Down, ButtonState::HitTest] - .into_iter() - .collect(), + states: ButtonState::DOWN | ButtonState::HIT_TEST, depth: 1, matrix: Matrix::identity(), color_transform: ColorTransform { @@ -285,14 +275,12 @@ pub fn tag_tests() -> Vec { ], actions: vec![ ButtonAction { - conditions: vec![ButtonActionCondition::OverDownToOverUp] - .into_iter() - .collect(), + conditions: ButtonActionCondition::OVER_DOWN_TO_OVER_UP, key_code: None, action_data: &[150, 3, 0, 0, 65, 0, 38, 0], // trace("A"); }, ButtonAction { - conditions: vec![ButtonActionCondition::KeyPress].into_iter().collect(), + conditions: ButtonActionCondition::KEY_PRESS, key_code: Some(3), // Home action_data: &[150, 3, 0, 0, 66, 0, 38, 0], // trace("B"); }, diff --git a/swf/src/types.rs b/swf/src/types.rs index d2491ef56..80dd24f83 100644 --- a/swf/src/types.rs +++ b/swf/src/types.rs @@ -5,7 +5,6 @@ //! https://www.adobe.com/content/dam/acom/en/devnet/pdf/swf-file-format-spec.pdf use crate::string::SwfStr; use bitflags::bitflags; -use std::collections::HashSet; mod matrix; @@ -851,23 +850,24 @@ pub type ButtonSound = (CharacterId, SoundInfo); #[derive(Debug, PartialEq, Clone)] pub struct ButtonAction<'a> { - pub conditions: HashSet, + pub conditions: ButtonActionCondition, pub key_code: Option, pub action_data: &'a [u8], } -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] -pub enum ButtonActionCondition { - IdleToOverDown, - OutDownToIdle, - OutDownToOverDown, - OverDownToOutDown, - OverDownToOverUp, - OverUpToOverDown, - OverUpToIdle, - IdleToOverUp, - OverDownToIdle, - KeyPress, +bitflags! { + pub struct ButtonActionCondition: u16 { + const IDLE_TO_OVER_UP = 1 << 0; + const OVER_UP_TO_IDLE = 1 << 1; + const OVER_UP_TO_OVER_DOWN = 1 << 2; + const OVER_DOWN_TO_OVER_UP = 1 << 3; + const OVER_DOWN_TO_OUT_DOWN = 1 << 4; + const OUT_DOWN_TO_OVER_DOWN = 1 << 5; + const OUT_DOWN_TO_IDLE = 1 << 6; + const IDLE_TO_OVER_DOWN = 1 << 7; + const OVER_DOWN_TO_IDLE = 1 << 8; + const KEY_PRESS = 1 << 9; + } } #[derive(Clone, Debug, PartialEq)] diff --git a/swf/src/write.rs b/swf/src/write.rs index 9756413ea..1cd41004b 100644 --- a/swf/src/write.rs +++ b/swf/src/write.rs @@ -1064,79 +1064,13 @@ impl Writer { } else { writer.write_u16(0)?; } - writer.write_u8( - if action - .conditions - .contains(&ButtonActionCondition::IdleToOverDown) - { - 0b1000_0000 - } else { - 0 - } | if action - .conditions - .contains(&ButtonActionCondition::OutDownToIdle) - { - 0b100_0000 - } else { - 0 - } | if action - .conditions - .contains(&ButtonActionCondition::OutDownToOverDown) - { - 0b10_0000 - } else { - 0 - } | if action - .conditions - .contains(&ButtonActionCondition::OverDownToOutDown) - { - 0b1_0000 - } else { - 0 - } | if action - .conditions - .contains(&ButtonActionCondition::OverDownToOverUp) - { - 0b1000 - } else { - 0 - } | if action - .conditions - .contains(&ButtonActionCondition::OverUpToOverDown) - { - 0b100 - } else { - 0 - } | if action - .conditions - .contains(&ButtonActionCondition::OverUpToIdle) - { - 0b10 - } else { - 0 - } | if action - .conditions - .contains(&ButtonActionCondition::IdleToOverUp) - { - 0b1 - } else { - 0 - }, - )?; - let mut flags = if action - .conditions - .contains(&ButtonActionCondition::OverDownToIdle) - { - 0b1 - } else { - 0 - }; - if action.conditions.contains(&ButtonActionCondition::KeyPress) { + let mut flags = action.conditions.bits(); + if action.conditions.contains(ButtonActionCondition::KEY_PRESS) { if let Some(key_code) = action.key_code { - flags |= key_code << 1; + flags |= (key_code as u16) << 9; } } - writer.write_u8(flags)?; + writer.write_u16(flags)?; writer.output.write_all(&action.action_data)?; } }