From 8d80f24fb730ae593053b3d9cbfcf49bf2a95d59 Mon Sep 17 00:00:00 2001 From: Lord-McSweeney Date: Thu, 16 Jan 2025 16:46:43 -0800 Subject: [PATCH 1/7] core/avm1/avm2: Remove Default impl for AvmString --- core/src/avm1/globals/selection.rs | 2 +- core/src/avm1/object/stage_object.rs | 8 ++- core/src/avm2/e4x.rs | 22 ++++--- .../globals/flash/display/display_object.rs | 7 ++- core/src/avm2/globals/xml.rs | 2 +- core/src/avm2/traits.rs | 29 +++++---- core/src/debug_ui/display_object.rs | 19 ++++-- core/src/debug_ui/movie.rs | 4 +- core/src/display_object.rs | 49 ++++++++------- core/src/display_object/container.rs | 63 +++++++++---------- core/src/display_object/edit_text.rs | 4 +- core/src/display_object/movie_clip.rs | 2 +- core/src/string/avm_string.rs | 8 --- 13 files changed, 119 insertions(+), 100 deletions(-) diff --git a/core/src/avm1/globals/selection.rs b/core/src/avm1/globals/selection.rs index 0295823856dc2..eef0f08ffb907 100644 --- a/core/src/avm1/globals/selection.rs +++ b/core/src/avm1/globals/selection.rs @@ -105,7 +105,7 @@ pub fn get_focus<'gc>( .as_displayobject() .object() .coerce_to_string(activation) - .unwrap_or_default() + .unwrap_or_else(|_| activation.strings().empty()) .into(), None => Value::Null, }) diff --git a/core/src/avm1/object/stage_object.rs b/core/src/avm1/object/stage_object.rs index 5e79d67eac29a..9e4948b632a3d 100644 --- a/core/src/avm1/object/stage_object.rs +++ b/core/src/avm1/object/stage_object.rs @@ -341,7 +341,7 @@ impl<'gc> TObject<'gc> for StageObject<'gc> { // Button/MovieClip children are included in key list. for child in ctr.iter_render_list().rev() { if child.as_interactive().is_some() { - keys.push(child.name()); + keys.push(child.name().expect("Interactive DisplayObjects have names")); } } } @@ -657,8 +657,10 @@ fn frames_loaded<'gc>( .map_or(Value::Undefined, Value::from) } -fn name<'gc>(_activation: &mut Activation<'_, 'gc>, this: DisplayObject<'gc>) -> Value<'gc> { - this.name().into() +fn name<'gc>(activation: &mut Activation<'_, 'gc>, this: DisplayObject<'gc>) -> Value<'gc> { + this.name() + .unwrap_or_else(|| activation.strings().empty()) + .into() } fn set_name<'gc>( diff --git a/core/src/avm2/e4x.rs b/core/src/avm2/e4x.rs index c80b1b319c24d..59e0cbcd96bed 100644 --- a/core/src/avm2/e4x.rs +++ b/core/src/avm2/e4x.rs @@ -755,7 +755,7 @@ impl<'gc> E4XNode<'gc> { ) -> Result, Error<'gc>> { let string = match &value { // The docs claim that this throws a TypeError, but it actually doesn't - Value::Null | Value::Undefined => AvmString::default(), + Value::Null | Value::Undefined => activation.strings().empty(), // The docs claim that only String, Number or Boolean are accepted, but that's also a lie val => { if let Some(obj) = val.as_object() { @@ -962,7 +962,7 @@ impl<'gc> E4XNode<'gc> { } else { ( AvmString::new_utf8_bytes(activation.gc(), text.as_bytes()), - AvmString::default(), + activation.strings().empty(), ) }; let node = E4XNode(GcCell::new( @@ -1312,16 +1312,22 @@ impl<'gc> E4XNode<'gc> { return true; } - let self_ns = self.namespace().map(|ns| ns.uri).unwrap_or_default(); + let self_ns = self.namespace().map(|ns| ns.uri); // FIXME: For cases where we don't have *any* explicit namespace // we just give up and assume we should match the default public namespace. if !name.namespace_set().iter().any(|ns| ns.is_namespace()) { - return self_ns.is_empty(); + return self_ns.is_none_or(|n| n.is_empty()); } - name.namespace_set() - .iter() - .any(|ns| ns.as_uri_opt().expect("NS set cannot contain Any") == self_ns) + name.namespace_set().iter().any(|ns| { + let uri = ns.as_uri_opt().expect("NS set cannot contain Any"); + + if let Some(self_ns) = self_ns { + uri == self_ns + } else { + uri.is_empty() + } + }) } pub fn descendants(&self, name: &Multiname<'gc>, out: &mut Vec>) { @@ -1412,7 +1418,7 @@ pub fn simple_content_to_string<'gc>( children: impl Iterator>, activation: &mut Activation<'_, 'gc>, ) -> AvmString<'gc> { - let mut out = AvmString::default(); + let mut out = activation.strings().empty(); for child in children { if matches!( &*child.node().kind(), diff --git a/core/src/avm2/globals/flash/display/display_object.rs b/core/src/avm2/globals/flash/display/display_object.rs index 89e5b959b8449..0ade10498bdcb 100644 --- a/core/src/avm2/globals/flash/display/display_object.rs +++ b/core/src/avm2/globals/flash/display/display_object.rs @@ -542,14 +542,17 @@ pub fn set_rotation<'gc>( /// Implements `name`'s getter. pub fn get_name<'gc>( - _activation: &mut Activation<'_, 'gc>, + activation: &mut Activation<'_, 'gc>, this: Value<'gc>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { let this = this.as_object().unwrap(); if let Some(dobj) = this.as_display_object() { - return Ok(dobj.name().into()); + return Ok(dobj + .name() + .unwrap_or_else(|| activation.strings().empty()) + .into()); } Ok(Value::Undefined) diff --git a/core/src/avm2/globals/xml.rs b/core/src/avm2/globals/xml.rs index c7ad44cbb0e89..07ba781ec6928 100644 --- a/core/src/avm2/globals/xml.rs +++ b/core/src/avm2/globals/xml.rs @@ -54,7 +54,7 @@ pub fn init<'gc>( let node = match nodes.as_slice() { // XML defaults to an empty text node when nothing was parsed - [] => E4XNode::text(activation.gc(), AvmString::default(), None), + [] => E4XNode::text(activation.gc(), activation.strings().empty(), None), [node] => *node, nodes => { let mut single_element_node = None; diff --git a/core/src/avm2/traits.rs b/core/src/avm2/traits.rs index ee44465544ac7..8ff2448b40530 100644 --- a/core/src/avm2/traits.rs +++ b/core/src/avm2/traits.rs @@ -405,19 +405,24 @@ fn default_value_for_type<'gc>(type_name: Option>>) -> Va // like `Activation::resolve_type` to get an actual `Class` object, and then check something like `Class::built_in_type`. // The Multiname is guaranteed to be static by `pool.pool_multiname_static` earlier. if type_name.contains_public_namespace() { - let name = type_name.local_name().unwrap_or_default(); - if &name == b"Boolean" { - false.into() - } else if &name == b"Number" { - f64::NAN.into() - } else if &name == b"int" { - 0.into() - } else if &name == b"String" { - Value::Null - } else if &name == b"uint" { - 0.into() + let name = type_name.local_name(); + if let Some(name) = name { + if &name == b"Boolean" { + false.into() + } else if &name == b"Number" { + f64::NAN.into() + } else if &name == b"int" { + 0.into() + } else if &name == b"String" { + Value::Null + } else if &name == b"uint" { + 0.into() + } else { + Value::Null // Object type + } } else { - Value::Null // Object type + // No local name? + Value::Null } } else { // Object type diff --git a/core/src/debug_ui/display_object.rs b/core/src/debug_ui/display_object.rs index 2283382824a00..15b837e56b113 100644 --- a/core/src/debug_ui/display_object.rs +++ b/core/src/debug_ui/display_object.rs @@ -1128,7 +1128,9 @@ impl DisplayObjectWindow { ui.label("Name"); // &mut of a temporary thing because we don't want to actually be able to change this // If we disable it, the user can't highlight or interact with it, so this makes it readonly but enabled - ui.text_edit_singleline(&mut object.name().to_string()); + ui.text_edit_singleline( + &mut object.name().map(|s| s.to_string()).unwrap_or_default(), + ); ui.end_row(); if let crate::avm1::Value::Object(object) = object.object() { @@ -1315,7 +1317,10 @@ impl DisplayObjectWindow { } fn matches_search(object: DisplayObject, search: &WStr) -> bool { - if object.name().to_ascii_lowercase().contains(search) { + if object + .name() + .is_some_and(|n| n.to_ascii_lowercase().contains(search)) + { return true; } @@ -1392,10 +1397,14 @@ fn summary_name(object: DisplayObject) -> Cow<'static, str> { let do_type = display_object_type(object); let name = object.name(); - if name.is_empty() { - Cow::Borrowed(do_type) + if let Some(name) = name { + if name.is_empty() { + Cow::Borrowed(do_type) + } else { + Cow::Owned(format!("{do_type} \"{name}\"")) + } } else { - Cow::Owned(format!("{do_type} \"{name}\"")) + Cow::Borrowed("") } } diff --git a/core/src/debug_ui/movie.rs b/core/src/debug_ui/movie.rs index abcc6547ae9fe..d0c792a96433b 100644 --- a/core/src/debug_ui/movie.rs +++ b/core/src/debug_ui/movie.rs @@ -132,8 +132,8 @@ impl MovieWindow { let name = export_characters .iter() .find_map(|(k, v)| if *v == id { Some(k) } else { None }) - .unwrap_or_default() - .to_string(); + .map(|s| s.to_string()) + .unwrap_or_default(); let search = self.character_search.to_ascii_lowercase(); if !id.to_string().to_ascii_lowercase().contains(&search) diff --git a/core/src/display_object.rs b/core/src/display_object.rs index 8caa8483ad090..7019148ece55c 100644 --- a/core/src/display_object.rs +++ b/core/src/display_object.rs @@ -1556,10 +1556,7 @@ pub trait TDisplayObject<'gc>: } } - fn name(&self) -> AvmString<'gc> { - self.base().name().unwrap_or_default() - } - fn name_optional(&self) -> Option> { + fn name(&self) -> Option> { self.base().name() } fn set_name(&self, gc_context: &Mutation<'gc>, name: AvmString<'gc>) { @@ -1581,7 +1578,9 @@ pub trait TDisplayObject<'gc>: if let Some(parent) = self.avm1_parent() { let mut path = parent.path(); path.push_byte(b'.'); - path.push_str(&self.name()); + if let Some(name) = self.name() { + path.push_str(&name); + } path } else { WString::from_utf8_owned(format!("_level{}", self.depth())) @@ -1595,7 +1594,9 @@ pub trait TDisplayObject<'gc>: if let Some(parent) = object.avm1_parent() { let mut path = build_slash_path(parent); path.push_byte(b'/'); - path.push_str(&object.name()); + if let Some(name) = object.name() { + path.push_str(&name); + } path } else { let level = object.depth(); @@ -2046,20 +2047,24 @@ pub trait TDisplayObject<'gc>: if self.has_explicit_name() { if let Some(parent @ Avm2Value::Object(_)) = self.parent().map(|p| p.object2()) { if let Avm2Value::Object(child) = self.object2() { - let domain = context - .library - .library_for_movie(self.movie()) - .unwrap() - .avm2_domain(); - let mut activation = Avm2Activation::from_domain(context, domain); - let name = - Avm2Multiname::new(activation.avm2().find_public_namespace(), self.name()); - if let Err(e) = parent.init_property(&name, child.into(), &mut activation) { - tracing::error!( - "Got error when setting AVM2 child named \"{}\": {}", - &self.name(), - e - ); + if let Some(name) = self.name() { + let domain = context + .library + .library_for_movie(self.movie()) + .unwrap() + .avm2_domain(); + let mut activation = Avm2Activation::from_domain(context, domain); + let multiname = + Avm2Multiname::new(activation.avm2().find_public_namespace(), name); + if let Err(e) = + parent.init_property(&multiname, child.into(), &mut activation) + { + tracing::error!( + "Got error when setting AVM2 child named \"{}\": {}", + &name, + e + ); + } } } } @@ -2138,7 +2143,7 @@ pub trait TDisplayObject<'gc>: bounds.x_min.to_pixels(), bounds.y_min.to_pixels(), classname, - self.name(), + self.name().map(|s| s.to_string()).unwrap_or_default(), self_str, self.id(), depth @@ -2470,7 +2475,7 @@ pub trait TDisplayObject<'gc>: let name = AvmString::new_utf8(context.gc(), format!("root{}", self.depth() + 1)); self.set_name(context.gc(), name); } else { - self.set_name(context.gc(), Default::default()); + self.set_name(context.gc(), context.strings.empty()); } } diff --git a/core/src/display_object/container.rs b/core/src/display_object/container.rs index d4929dcbb791c..ed372571ecd75 100644 --- a/core/src/display_object/container.rs +++ b/core/src/display_object/container.rs @@ -718,29 +718,29 @@ impl<'gc> ChildContainer<'gc> { "Parent must be removed *after* calling `remove_child_from_render_list`", ); if child.has_explicit_name() { - if let Avm2Value::Object(parent_obj) = parent.object2() { - let parent_obj = Avm2Value::from(parent_obj); - - let mut activation = Avm2Activation::from_nothing(context); - let name = Avm2Multiname::new( - activation.avm2().find_public_namespace(), - child.name(), - ); - let current_val = parent_obj.get_property(&name, &mut activation); - match current_val { - Ok(Avm2Value::Null) | Ok(Avm2Value::Undefined) => {} - Ok(_other) => { - let res = parent_obj.set_property( - &name, - Avm2Value::Null, - &mut activation, - ); - if let Err(e) = res { - tracing::error!("Failed to set child {} ({:?}) to null on parent obj {:?}: {:?}", child.name(), child, parent_obj, e); + if let Some(name) = child.name() { + if let Avm2Value::Object(parent_obj) = parent.object2() { + let parent_obj = Avm2Value::from(parent_obj); + + let mut activation = Avm2Activation::from_nothing(context); + let multiname = + Avm2Multiname::new(activation.avm2().find_public_namespace(), name); + let current_val = parent_obj.get_property(&multiname, &mut activation); + match current_val { + Ok(Avm2Value::Null) | Ok(Avm2Value::Undefined) => {} + Ok(_other) => { + let res = parent_obj.set_property( + &multiname, + Avm2Value::Null, + &mut activation, + ); + if let Err(e) = res { + tracing::error!("Failed to set child {} ({:?}) to null on parent obj {:?}: {:?}", name, child, parent_obj, e); + } + } + Err(e) => { + tracing::error!("Failed to get current value of child {} ({:?}) on parent obj {:?}: {:?}", name, child, parent_obj, e); } - } - Err(e) => { - tracing::error!("Failed to get current value of child {} ({:?}) on parent obj {:?}: {:?}", child.name(), child, parent_obj, e); } } } @@ -844,16 +844,12 @@ impl<'gc> ChildContainer<'gc> { let mut matching_render_children = if case_sensitive { self.depth_list .iter() - .filter(|(_, child)| child.name_optional().is_some_and(|n| n == name)) + .filter(|(_, child)| child.name().is_some_and(|n| n == name)) .collect::>() } else { self.depth_list .iter() - .filter(|(_, child)| { - child - .name_optional() - .is_some_and(|n| n.eq_ignore_case(name)) - }) + .filter(|(_, child)| child.name().is_some_and(|n| n.eq_ignore_case(name))) .collect::>() }; @@ -872,13 +868,12 @@ impl<'gc> ChildContainer<'gc> { self.render_list .iter() .copied() - .find(|child| child.name_optional().is_some_and(|n| n == name)) + .find(|child| child.name().is_some_and(|n| n == name)) } else { - self.render_list.iter().copied().find(|child| { - child - .name_optional() - .is_some_and(|n| n.eq_ignore_case(name)) - }) + self.render_list + .iter() + .copied() + .find(|child| child.name().is_some_and(|n| n.eq_ignore_case(name))) } } } diff --git a/core/src/display_object/edit_text.rs b/core/src/display_object/edit_text.rs index 20f979138e221..499da572f318d 100644 --- a/core/src/display_object/edit_text.rs +++ b/core/src/display_object/edit_text.rs @@ -1354,7 +1354,9 @@ impl<'gc> EditText<'gc> { if object.has_property(activation, property) { let value = object.get(property, activation).unwrap(); self.set_html_text( - &value.coerce_to_string(activation).unwrap_or_default(), + &value + .coerce_to_string(activation) + .unwrap_or_else(|_| activation.strings().empty()), activation.context, ); } else { diff --git a/core/src/display_object/movie_clip.rs b/core/src/display_object/movie_clip.rs index 04d9129019020..f284418340900 100644 --- a/core/src/display_object/movie_clip.rs +++ b/core/src/display_object/movie_clip.rs @@ -1727,7 +1727,7 @@ impl<'gc> MovieClip<'gc> { if cfg!(feature = "timeline_debug") { tracing::debug!( "[{}]: {} from frame {} to frame {}", - self.name(), + self.name().map(|s| s.to_string()).unwrap_or_default(), if is_implicit { "looping" } else { "goto" }, self.current_frame(), frame diff --git a/core/src/string/avm_string.rs b/core/src/string/avm_string.rs index 06c6b0ac99db2..5da2acd58812d 100644 --- a/core/src/string/avm_string.rs +++ b/core/src/string/avm_string.rs @@ -165,14 +165,6 @@ impl<'gc> From>> for AvmString<'gc> { } } -impl Default for AvmString<'_> { - fn default() -> Self { - Self { - source: Source::Static(WStr::empty()), - } - } -} - impl From<&'static str> for AvmString<'_> { #[inline] fn from(str: &'static str) -> Self { From ea3ea52bf122c96e7ec5eac219a9e352205cd40e Mon Sep 17 00:00:00 2001 From: Lord-McSweeney Date: Thu, 16 Jan 2025 21:09:48 -0800 Subject: [PATCH 2/7] avm1/avm2: Add `AvmString::from_static_wstr` and use it Replaces the old `From<&'static WStr>` impl on AvmString --- core/src/avm1/globals/bevel_filter.rs | 2 +- .../src/avm1/globals/displacement_map_filter.rs | 2 +- core/src/avm1/globals/gradient_filter.rs | 2 +- core/src/avm2/globals/flash/display/bitmap.rs | 8 ++++++-- core/src/string/avm_string.rs | 17 ++++++++--------- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/core/src/avm1/globals/bevel_filter.rs b/core/src/avm1/globals/bevel_filter.rs index cab2bcf75a66f..f11d8b8a4f34c 100644 --- a/core/src/avm1/globals/bevel_filter.rs +++ b/core/src/avm1/globals/bevel_filter.rs @@ -515,7 +515,7 @@ fn method<'gc>( } GET_TYPE => { let type_: &WStr = this.type_().into(); - AvmString::from(type_).into() + AvmString::from_static_wstr(activation.gc(), type_).into() } SET_TYPE => { this.set_type(activation, args.get(0))?; diff --git a/core/src/avm1/globals/displacement_map_filter.rs b/core/src/avm1/globals/displacement_map_filter.rs index d1150530ca1b7..c8c3c285bc762 100644 --- a/core/src/avm1/globals/displacement_map_filter.rs +++ b/core/src/avm1/globals/displacement_map_filter.rs @@ -418,7 +418,7 @@ fn method<'gc>( } GET_MODE => { let mode: &WStr = this.mode().into(); - AvmString::from(mode).into() + AvmString::from_static_wstr(activation.gc(), mode).into() } SET_MODE => { this.set_mode(activation, args.get(0))?; diff --git a/core/src/avm1/globals/gradient_filter.rs b/core/src/avm1/globals/gradient_filter.rs index 468dbbcfa804d..a0f95865d29de 100644 --- a/core/src/avm1/globals/gradient_filter.rs +++ b/core/src/avm1/globals/gradient_filter.rs @@ -506,7 +506,7 @@ fn method<'gc>( } GET_TYPE => { let type_: &WStr = this.type_().into(); - AvmString::from(type_).into() + AvmString::from_static_wstr(activation.gc(), type_).into() } SET_TYPE => { this.set_type(activation, args.get(0))?; diff --git a/core/src/avm2/globals/flash/display/bitmap.rs b/core/src/avm2/globals/flash/display/bitmap.rs index 257a2d1d019c9..eacab1a8f1447 100644 --- a/core/src/avm2/globals/flash/display/bitmap.rs +++ b/core/src/avm2/globals/flash/display/bitmap.rs @@ -6,6 +6,7 @@ use crate::avm2::globals::flash::display::display_object::initialize_for_allocat use crate::avm2::object::{BitmapDataObject, ClassObject, Object, TObject}; use crate::avm2::value::Value; use crate::avm2::Error; +use crate::string::AvmString; use ruffle_render::bitmap::PixelSnapping; use ruffle_wstr::WStr; @@ -156,7 +157,7 @@ pub fn set_bitmap_data<'gc>( /// Stub `Bitmap.pixelSnapping`'s getter pub fn get_pixel_snapping<'gc>( - _activation: &mut Activation<'_, 'gc>, + activation: &mut Activation<'_, 'gc>, this: Value<'gc>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { @@ -164,7 +165,10 @@ pub fn get_pixel_snapping<'gc>( if let Some(bitmap) = this.as_display_object().and_then(|dobj| dobj.as_bitmap()) { let value: &WStr = bitmap.pixel_snapping().into(); - return Ok(Value::String(value.into())); + return Ok(Value::String(AvmString::from_static_wstr( + activation.gc(), + value, + ))); } Ok(Value::Undefined) } diff --git a/core/src/string/avm_string.rs b/core/src/string/avm_string.rs index 5da2acd58812d..439bd6cfe926a 100644 --- a/core/src/string/avm_string.rs +++ b/core/src/string/avm_string.rs @@ -68,6 +68,14 @@ impl<'gc> AvmString<'gc> { } } + pub fn from_static_wstr(gc_context: &Mutation<'gc>, string: &'static WStr) -> Self { + let repr = AvmStringRepr::from_raw_static(string, false); + + Self { + source: Source::Managed(Gc::new(gc_context, repr)), + } + } + pub fn substring(mc: &Mutation<'gc>, string: AvmString<'gc>, start: usize, end: usize) -> Self { match string.source { Source::Managed(repr) => { @@ -175,15 +183,6 @@ impl From<&'static str> for AvmString<'_> { } } -impl From<&'static WStr> for AvmString<'_> { - #[inline] - fn from(str: &'static WStr) -> Self { - Self { - source: Source::Static(str), - } - } -} - impl Deref for AvmString<'_> { type Target = WStr; #[inline] From 29458a200af9b60793e88e811738bc962d08fc29 Mon Sep 17 00:00:00 2001 From: Lord-McSweeney Date: Sat, 18 Jan 2025 19:51:58 -0800 Subject: [PATCH 3/7] avm2: Allocate a non-static string for the Event name when creating an EventObject --- core/src/avm2/events.rs | 7 +-- core/src/avm2/object/event_object.rs | 83 +++++++++++++--------------- core/src/net_connection.rs | 10 ++-- core/src/streams.rs | 20 +++---- 4 files changed, 53 insertions(+), 67 deletions(-) diff --git a/core/src/avm2/events.rs b/core/src/avm2/events.rs index c8ce94842b802..62f7b48dbc59d 100644 --- a/core/src/avm2/events.rs +++ b/core/src/avm2/events.rs @@ -76,10 +76,7 @@ pub struct Event<'gc> { impl<'gc> Event<'gc> { /// Construct a new event of a given type. - pub fn new(event_type: S) -> Self - where - S: Into>, - { + pub fn new(event_type: AvmString<'gc>) -> Self { Event { bubbles: false, cancelable: false, @@ -88,7 +85,7 @@ impl<'gc> Event<'gc> { current_target: None, event_phase: EventPhase::AtTarget, target: None, - event_type: event_type.into(), + event_type, } } diff --git a/core/src/avm2/object/event_object.rs b/core/src/avm2/object/event_object.rs index 18da68d9cb2b2..79d27b6a7bd89 100644 --- a/core/src/avm2/object/event_object.rs +++ b/core/src/avm2/object/event_object.rs @@ -61,31 +61,27 @@ impl<'gc> EventObject<'gc> { /// It's just slightly faster and doesn't require an Activation. /// This is equivalent to /// classes.event.construct(activation, &[event_type, false, false]) - pub fn bare_default_event( + pub fn bare_default_event( context: &mut UpdateContext<'gc>, - event_type: S, - ) -> EventObject<'gc> - where - S: Into>, - { + event_type: &str, + ) -> EventObject<'gc> { Self::bare_event(context, event_type, false, false) } /// Create a bare Event instance while skipping the usual `construct()` pipeline. /// It's just slightly faster and doesn't require an Activation. /// Note that if you need an Event subclass, you need to construct it via .construct(). - pub fn bare_event( + pub fn bare_event( context: &mut UpdateContext<'gc>, - event_type: S, + event_type: &str, bubbles: bool, cancelable: bool, - ) -> EventObject<'gc> - where - S: Into>, - { + ) -> EventObject<'gc> { let class = context.avm2.classes().event; let base = ScriptObjectData::new(class); + let event_type = AvmString::new_utf8(context.gc(), event_type); + let mut event = Event::new(event_type); event.set_bubbles(bubbles); event.set_cancelable(cancelable); @@ -116,21 +112,18 @@ impl<'gc> EventObject<'gc> { .unwrap() } - pub fn mouse_event( + pub fn mouse_event( activation: &mut Activation<'_, 'gc>, - event_type: S, + event_type: &str, target: DisplayObject<'gc>, related_object: Option>, delta: i32, bubbles: bool, button: MouseButton, - ) -> EventObject<'gc> - where - S: Into>, - { + ) -> EventObject<'gc> { let local = target.local_mouse_position(activation.context); - let event_type: AvmString<'gc> = event_type.into(); + let event_type = AvmString::new_utf8(activation.gc(), event_type); let mouse_event_cls = activation.avm2().classes().mouseevent; Self::from_class_and_args( @@ -231,17 +224,14 @@ impl<'gc> EventObject<'gc> { ) } - pub fn text_event( + pub fn text_event( activation: &mut Activation<'_, 'gc>, - event_type: S, + event_type: &str, text: AvmString<'gc>, bubbles: bool, cancelable: bool, - ) -> EventObject<'gc> - where - S: Into>, - { - let event_type: AvmString<'gc> = event_type.into(); + ) -> EventObject<'gc> { + let event_type = AvmString::new_utf8(activation.gc(), event_type); let text_event_cls = activation.avm2().classes().textevent; Self::from_class_and_args( @@ -261,12 +251,17 @@ impl<'gc> EventObject<'gc> { pub fn net_status_event( activation: &mut Activation<'_, 'gc>, - info: Vec<(impl Into>, impl Into>)>, + info: Vec<(&str, &str)>, ) -> EventObject<'gc> { + let event_type = AvmString::new_utf8(activation.gc(), "netStatus"); + let info_object = ScriptObject::new_object(activation); for (key, value) in info { + let key = AvmString::new_utf8(activation.gc(), key); + let value = AvmString::new_utf8(activation.gc(), value); + info_object - .set_string_property_local(key.into(), Value::String(value.into()), activation) + .set_string_property_local(key, Value::String(value), activation) .unwrap(); } @@ -275,7 +270,7 @@ impl<'gc> EventObject<'gc> { activation, net_status_cls, &[ - "netStatus".into(), + event_type.into(), //bubbles false.into(), //cancelable @@ -285,16 +280,13 @@ impl<'gc> EventObject<'gc> { ) } - pub fn progress_event( + pub fn progress_event( activation: &mut Activation<'_, 'gc>, - event_type: S, + event_type: &str, bytes_loaded: usize, bytes_total: usize, - ) -> EventObject<'gc> - where - S: Into>, - { - let event_type: AvmString<'gc> = event_type.into(); + ) -> EventObject<'gc> { + let event_type = AvmString::new_utf8(activation.gc(), event_type); let progress_event_cls = activation.avm2().classes().progressevent; Self::from_class_and_args( @@ -314,17 +306,14 @@ impl<'gc> EventObject<'gc> { ) } - pub fn focus_event( + pub fn focus_event( activation: &mut Activation<'_, 'gc>, - event_type: S, + event_type: &str, cancelable: bool, related_object: Option>, key_code: u32, - ) -> EventObject<'gc> - where - S: Into>, - { - let event_type: AvmString<'gc> = event_type.into(); + ) -> EventObject<'gc> { + let event_type = AvmString::new_utf8(activation.gc(), event_type); let shift_key = activation.context.input.is_key_down(KeyCode::SHIFT); let focus_event_cls = activation.avm2().classes().focusevent; @@ -350,12 +339,14 @@ impl<'gc> EventObject<'gc> { error_msg: AvmString<'gc>, error_code: u32, ) -> EventObject<'gc> { + let event_type = AvmString::new_utf8(activation.gc(), "ioError"); + let io_error_event_cls = activation.avm2().classes().ioerrorevent; Self::from_class_and_args( activation, io_error_event_cls, &[ - "ioError".into(), + event_type.into(), false.into(), false.into(), error_msg.into(), @@ -369,12 +360,14 @@ impl<'gc> EventObject<'gc> { status: u16, redirected: bool, ) -> EventObject<'gc> { + let event_type = AvmString::new_utf8(activation.gc(), "httpStatus"); + let http_status_event_cls = activation.avm2().classes().httpstatusevent; Self::from_class_and_args( activation, http_status_event_cls, &[ - "httpStatus".into(), + event_type.into(), false.into(), false.into(), status.into(), diff --git a/core/src/net_connection.rs b/core/src/net_connection.rs index 140512d54dae4..961ab3bd3b2f7 100644 --- a/core/src/net_connection.rs +++ b/core/src/net_connection.rs @@ -7,7 +7,6 @@ use crate::avm2::{Activation as Avm2Activation, Avm2, EventObject as Avm2EventOb use crate::backend::navigator::{ErrorResponse, NavigatorBackend, OwnedFuture, Request}; use crate::context::UpdateContext; use crate::loader::Error; -use crate::string::AvmString; use crate::Player; use flash_lso::packet::{Header, Message, Packet}; use flash_lso::types::{AMFVersion, Value as AmfValue}; @@ -540,14 +539,13 @@ impl FlashRemoting { match connection.object { NetConnectionObject::Avm2(object) => { let mut activation = Avm2Activation::from_nothing(uc); - let url = AvmString::new_utf8(activation.gc(), response.url); let event = Avm2EventObject::net_status_event( &mut activation, vec![ - ("code", "NetConnection.Call.Failed".into()), - ("level", "error".into()), - ("details", url), - ("description", "HTTP: Failed".into()), + ("code", "NetConnection.Call.Failed"), + ("level", "error"), + ("details", &response.url), + ("description", "HTTP: Failed"), ], ); Avm2::dispatch_event(activation.context, event, object.into()); diff --git a/core/src/streams.rs b/core/src/streams.rs index 1c9ad4b154295..90ae6ca8a067e 100644 --- a/core/src/streams.rs +++ b/core/src/streams.rs @@ -398,14 +398,13 @@ impl<'gc> NetStream<'gc> { StreamManager::activate(context, self); if notify { - let trigger = - AvmString::new_utf8(context.gc(), format!("Start Seeking {}", offset as u64)); + let trigger = format!("Start Seeking {}", offset as u64); self.trigger_status_event( context, vec![ - ("description", trigger), - ("level", "status".into()), - ("code", "NetStream.SeekStart.Notify".into()), + ("description", &trigger), + ("level", "status"), + ("code", "NetStream.SeekStart.Notify"), ], ); } @@ -1277,11 +1276,7 @@ impl<'gc> NetStream<'gc> { } /// Trigger a status event on the stream. - pub fn trigger_status_event( - self, - context: &mut UpdateContext<'gc>, - values: Vec<(impl Into>, impl Into>)>, - ) { + pub fn trigger_status_event(self, context: &mut UpdateContext<'gc>, values: Vec<(&str, &str)>) { let object = self.0.read().avm_object; match object { Some(AvmObject::Avm1(object)) => { @@ -1295,8 +1290,11 @@ impl<'gc> NetStream<'gc> { let info_object = Avm1ScriptObject::new(activation.gc(), Some(object_proto)); for (key, value) in values { + let key = AvmString::new_utf8(activation.gc(), key); + let value = AvmString::new_utf8(activation.gc(), value); + info_object - .set(key.into(), Avm1Value::String(value.into()), &mut activation) + .set(key, Avm1Value::String(value), &mut activation) .expect("valid set"); } From 95823763eeea8ade2aa3d988a900b60b3ca6104c Mon Sep 17 00:00:00 2001 From: Lord-McSweeney Date: Sat, 18 Jan 2025 20:20:26 -0800 Subject: [PATCH 4/7] avm2: Remove some uses of static strings --- core/src/avm2/globals/q_name.rs | 6 +++--- core/src/avm2/globals/xml.rs | 12 +++++++----- core/src/avm2/object/proxy_object.rs | 4 ++-- core/src/avm2/object/qname_object.rs | 6 +++--- core/src/avm2/value.rs | 7 ++++--- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/core/src/avm2/globals/q_name.rs b/core/src/avm2/globals/q_name.rs index c8eb21771114a..bf61a121b0456 100644 --- a/core/src/avm2/globals/q_name.rs +++ b/core/src/avm2/globals/q_name.rs @@ -65,7 +65,7 @@ pub fn q_name_constructor<'gc>( }; if let Value::Object(Object::QNameObject(qname)) = local_arg { - this.set_local_name(activation.gc(), qname.local_name()); + this.set_local_name(activation.gc(), qname.local_name(activation.strings())); } else { this.set_local_name(activation.gc(), local_arg.coerce_to_string(activation)?); } @@ -102,14 +102,14 @@ pub fn q_name_constructor<'gc>( /// Implements `QName.localName`'s getter pub fn get_local_name<'gc>( - _activation: &mut Activation<'_, 'gc>, + activation: &mut Activation<'_, 'gc>, this: Value<'gc>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { let this = this.as_object().unwrap(); if let Some(this) = this.as_qname_object() { - return Ok(this.local_name().into()); + return Ok(this.local_name(activation.strings()).into()); } Ok(Value::Undefined) diff --git a/core/src/avm2/globals/xml.rs b/core/src/avm2/globals/xml.rs index 07ba781ec6928..ba76727eac5d7 100644 --- a/core/src/avm2/globals/xml.rs +++ b/core/src/avm2/globals/xml.rs @@ -253,7 +253,7 @@ pub fn set_name<'gc>( // 2. If (Type(name) is Object) and (name.[[Class]] == "QName") and (name.uri == null) Value::Object(Object::QNameObject(qname)) if qname.is_any_namespace() => { // a. Let name = name.localName - qname.local_name().into() + qname.local_name(activation.strings()).into() } value => value, }; @@ -269,9 +269,11 @@ pub fn set_name<'gc>( .as_qname_object() .unwrap(); + let new_local_name = new_name.local_name(activation.strings()); + // NOTE: avmplus addition - if !crate::avm2::e4x::is_xml_name(new_name.local_name()) { - return Err(make_error_1117(activation, new_name.local_name())); + if !crate::avm2::e4x::is_xml_name(new_local_name) { + return Err(make_error_1117(activation, new_local_name)); } // 4. If x.[[Class]] == "processing-instruction", let n.uri be the empty string @@ -288,7 +290,7 @@ pub fn set_name<'gc>( // 5. Let x.[[Name]] = n node.set_namespace(ns, activation.gc()); - node.set_local_name(new_name.local_name(), activation.gc()); + node.set_local_name(new_local_name, activation.gc()); // NOTE: avmplus addition if let Some(ns) = ns { @@ -1303,7 +1305,7 @@ pub fn set_local_name<'gc>( // 2. If (Type(name) is Object) and (name.[[Class]] == "QName") let name = if let Some(qname) = name.as_object().and_then(|x| x.as_qname_object()) { // 2.a. Let name = name.localName - qname.local_name() + qname.local_name(activation.strings()) // 3. Else } else { // 3.a. Let name = ToString(name) diff --git a/core/src/avm2/object/proxy_object.rs b/core/src/avm2/object/proxy_object.rs index e11c7e845af13..016adee325f34 100644 --- a/core/src/avm2/object/proxy_object.rs +++ b/core/src/avm2/object/proxy_object.rs @@ -132,8 +132,8 @@ impl<'gc> TObject<'gc> for ProxyObject<'gc> { &prop, &[name .local_name() - .map(Value::from) - .unwrap_or_else(|| "*".into())], + .unwrap_or_else(|| activation.strings().ascii_char(b'*')) + .into()], activation, )? .coerce_to_boolean()) diff --git a/core/src/avm2/object/qname_object.rs b/core/src/avm2/object/qname_object.rs index 80a116e8a1acf..999677c1c60f2 100644 --- a/core/src/avm2/object/qname_object.rs +++ b/core/src/avm2/object/qname_object.rs @@ -89,10 +89,10 @@ impl<'gc> QNameObject<'gc> { write_name.set_local_name(local); } - pub fn local_name(&self) -> AvmString<'gc> { + pub fn local_name(&self, context: &mut StringContext<'gc>) -> AvmString<'gc> { let name = self.name(); - name.local_name().unwrap_or("*".into()) + name.local_name().unwrap_or(context.ascii_char(b'*')) } pub fn set_is_qname(&self, mc: &Mutation<'gc>, is_qname: bool) { @@ -159,7 +159,7 @@ impl<'gc> TObject<'gc> for QNameObject<'gc> { ) -> Result, Error<'gc>> { // NOTE: Weird avmplus behavior, get_enumerant_name returns uri first, but get_enumerant_value returns localName first. Ok(match index { - 1 => self.local_name().into(), + 1 => self.local_name(activation.strings()).into(), 2 => self .uri(activation.strings()) .unwrap_or_else(|| activation.strings().empty()) diff --git a/core/src/avm2/value.rs b/core/src/avm2/value.rs index 87303b628c4f7..fc1ba8d172de1 100644 --- a/core/src/avm2/value.rs +++ b/core/src/avm2/value.rs @@ -776,7 +776,7 @@ impl<'gc> Value<'gc> { Value::Bool(true) => "true".into(), Value::Bool(false) => "false".into(), Value::Number(n) if n.is_nan() => "NaN".into(), - Value::Number(n) if *n == 0.0 => "0".into(), + Value::Number(n) if *n == 0.0 => activation.strings().ascii_char(b'0'), Value::Number(n) if *n < 0.0 => AvmString::new_utf8( activation.gc(), format!("-{}", Value::Number(-n).coerce_to_string(activation)?), @@ -806,7 +806,7 @@ impl<'gc> Value<'gc> { } Value::Integer(i) => { if *i >= 0 && *i < 10 { - activation.strings().make_char('0' as u16 + *i as u16) + activation.strings().ascii_char(b'0' + *i as u8) } else { AvmString::new_utf8(activation.gc(), i.to_string()) } @@ -1706,7 +1706,8 @@ impl<'gc> Value<'gc> { if let Value::Object(Object::QNameObject(other_qname)) = other { return Ok(self_qname.uri(activation.strings()) == other_qname.uri(activation.strings()) - && self_qname.local_name() == other_qname.local_name()); + && self_qname.local_name(activation.strings()) + == other_qname.local_name(activation.strings())); } } From 47b704cb296290a2bd38cbddf685be6cd3dcc2dd Mon Sep 17 00:00:00 2001 From: Lord-McSweeney Date: Sun, 19 Jan 2025 10:26:50 -0800 Subject: [PATCH 5/7] avm2: Make `TObject::has_own_property_string` take an AvmString directly --- core/src/avm2/object.rs | 2 +- core/src/avm2/object/proxy_object.rs | 3 +-- core/src/avm2/object/xml_list_object.rs | 4 ++-- core/src/avm2/object/xml_object.rs | 4 ++-- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/core/src/avm2/object.rs b/core/src/avm2/object.rs index 6f8e798eafe25..c6a87c1ccab3d 100644 --- a/core/src/avm2/object.rs +++ b/core/src/avm2/object.rs @@ -386,7 +386,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy /// Same as has_own_property, but constructs a public Multiname for you. fn has_own_property_string( self, - name: impl Into>, + name: AvmString<'gc>, activation: &mut Activation<'_, 'gc>, ) -> Result> { Ok(self.has_own_property(&Multiname::new( diff --git a/core/src/avm2/object/proxy_object.rs b/core/src/avm2/object/proxy_object.rs index 016adee325f34..0c18198be2127 100644 --- a/core/src/avm2/object/proxy_object.rs +++ b/core/src/avm2/object/proxy_object.rs @@ -141,12 +141,11 @@ impl<'gc> TObject<'gc> for ProxyObject<'gc> { fn has_own_property_string( self, - name: impl Into>, + name: AvmString<'gc>, activation: &mut Activation<'_, 'gc>, ) -> Result> { let self_val = Value::from(self); - let name = name.into(); let prop = Multiname::new(activation.avm2().namespaces.proxy, "hasProperty"); Ok(self_val .call_property(&prop, &[name.into()], activation)? diff --git a/core/src/avm2/object/xml_list_object.rs b/core/src/avm2/object/xml_list_object.rs index 9c1a5d52327f2..7f4e8f93c1a1d 100644 --- a/core/src/avm2/object/xml_list_object.rs +++ b/core/src/avm2/object/xml_list_object.rs @@ -633,10 +633,10 @@ impl<'gc> TObject<'gc> for XmlListObject<'gc> { fn has_own_property_string( self, - name: impl Into>, + name: AvmString<'gc>, activation: &mut Activation<'_, 'gc>, ) -> Result> { - let multiname = string_to_multiname(activation, name.into()); + let multiname = string_to_multiname(activation, name); Ok(self.has_own_property(&multiname)) } diff --git a/core/src/avm2/object/xml_object.rs b/core/src/avm2/object/xml_object.rs index afe774875c83f..8b4a9525c7452 100644 --- a/core/src/avm2/object/xml_object.rs +++ b/core/src/avm2/object/xml_object.rs @@ -400,10 +400,10 @@ impl<'gc> TObject<'gc> for XmlObject<'gc> { fn has_own_property_string( self, - name: impl Into>, + name: AvmString<'gc>, activation: &mut Activation<'_, 'gc>, ) -> Result> { - let multiname = string_to_multiname(activation, name.into()); + let multiname = string_to_multiname(activation, name); Ok(self.has_own_property(&multiname)) } From 78e425eb7188094a8d232b2d00bf97d8d4727ab0 Mon Sep 17 00:00:00 2001 From: Lord-McSweeney Date: Sun, 19 Jan 2025 13:35:04 -0800 Subject: [PATCH 6/7] avm2: Remove uses of more static strings 1. We no longer create a static AvmString to compare broadcast event types to to ensure they're a whitelisted event. 2. We now allocate an AvmString for looking up builtin classes before storing them on SystemClasses/SystemClassDefs. --- core/src/avm2.rs | 13 ++++--------- core/src/avm2/globals.rs | 23 +++++++++++++++++++---- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/core/src/avm2.rs b/core/src/avm2.rs index 77604c9809176..5d541d9827e48 100644 --- a/core/src/avm2.rs +++ b/core/src/avm2.rs @@ -97,7 +97,8 @@ use self::api_version::ApiVersion; use self::object::WeakObject; use self::scope::Scope; -const BROADCAST_WHITELIST: [&str; 4] = ["enterFrame", "exitFrame", "frameConstructed", "render"]; +const BROADCAST_WHITELIST: [&[u8]; 4] = + [b"enterFrame", b"exitFrame", b"frameConstructed", b"render"]; const PREALLOCATED_STACK_SIZE: usize = 120000; @@ -483,10 +484,7 @@ impl<'gc> Avm2<'gc> { object: Object<'gc>, event_name: AvmString<'gc>, ) { - if !BROADCAST_WHITELIST - .iter() - .any(|x| AvmString::from(*x) == event_name) - { + if !BROADCAST_WHITELIST.iter().any(|x| *x == &event_name) { return; } @@ -521,10 +519,7 @@ impl<'gc> Avm2<'gc> { ) { let event_name = event.event().event_type(); - if !BROADCAST_WHITELIST - .iter() - .any(|x| AvmString::from(*x) == event_name) - { + if !BROADCAST_WHITELIST.iter().any(|x| *x == &event_name) { return; } diff --git a/core/src/avm2/globals.rs b/core/src/avm2/globals.rs index 0ffcd80e6fa26..bb9ea00cb52a0 100644 --- a/core/src/avm2/globals.rs +++ b/core/src/avm2/globals.rs @@ -9,6 +9,7 @@ use crate::avm2::traits::Trait; use crate::avm2::value::Value; use crate::avm2::vtable::VTable; use crate::avm2::{Avm2, Error, Multiname, Namespace, QName}; +use crate::string::WStr; use crate::tag_utils::{self, ControlFlow, SwfMovie, SwfSlice, SwfStream}; use gc_arena::Collect; use std::sync::Arc; @@ -812,9 +813,16 @@ macro_rules! avm2_system_classes_playerglobal { ($activation:expr, [$(($package:expr, $class_name:expr, $field:ident)),* $(,)?]) => { let activation = $activation; $( + // Package and class names are ASCII + let package = WStr::from_units($package.as_bytes()); + let class_name = WStr::from_units($class_name.as_bytes()); + + let package = activation.strings().intern_static(package); + let class_name = activation.strings().intern_static(class_name); + // Lookup with the highest version, so we we see all defined classes here - let ns = Namespace::package($package, ApiVersion::VM_INTERNAL, activation.strings()); - let name = QName::new(ns, $class_name); + let ns = Namespace::package(package, ApiVersion::VM_INTERNAL, activation.strings()); + let name = QName::new(ns, class_name); let class_object = activation.domain().get_defined_value(activation, name).unwrap_or_else(|e| panic!("Failed to lookup {name:?}: {e:?}")); let class_object = class_object.as_object().unwrap().as_class_object().unwrap(); let sc = activation.avm2().system_classes.as_mut().unwrap(); @@ -827,11 +835,18 @@ macro_rules! avm2_system_class_defs_playerglobal { ($activation:expr, [$(($package:expr, $class_name:expr, $field:ident)),* $(,)?]) => { let activation = $activation; $( + // Package and class names are ASCII + let package = WStr::from_units($package.as_bytes()); + let class_name = WStr::from_units($class_name.as_bytes()); + + let package = activation.strings().intern_static(package); + let class_name = activation.strings().intern_static(class_name); + let domain = activation.domain(); // Lookup with the highest version, so we we see all defined classes here - let ns = Namespace::package($package, ApiVersion::VM_INTERNAL, activation.strings()); - let name = Multiname::new(ns, $class_name); + let ns = Namespace::package(package, ApiVersion::VM_INTERNAL, activation.strings()); + let name = Multiname::new(ns, class_name); let class_def = domain.get_class(activation.context, &name).unwrap_or_else(|| panic!("Failed to lookup {name:?}")); let sc = activation.avm2().system_class_defs.as_mut().unwrap(); sc.$field = class_def; From 8e8e6a0ad5a57469a35dc5b50e87f94ea591d423 Mon Sep 17 00:00:00 2001 From: Lord-McSweeney Date: Sun, 19 Jan 2025 14:15:45 -0800 Subject: [PATCH 7/7] avm2: Make some functions take `AvmString` directly instead of `impl Into` --- core/src/avm2/events.rs | 32 +++++++++++++------------------- core/src/avm2/method.rs | 11 ----------- core/src/avm2/multiname.rs | 4 ++-- core/src/avm2/object.rs | 2 +- core/src/avm2/regexp.rs | 14 ++++---------- 5 files changed, 20 insertions(+), 43 deletions(-) diff --git a/core/src/avm2/events.rs b/core/src/avm2/events.rs index 62f7b48dbc59d..0a014526f9c6b 100644 --- a/core/src/avm2/events.rs +++ b/core/src/avm2/events.rs @@ -93,11 +93,8 @@ impl<'gc> Event<'gc> { self.event_type } - pub fn set_event_type(&mut self, event_type: S) - where - S: Into>, - { - self.event_type = event_type.into(); + pub fn set_event_type(&mut self, event_type: AvmString<'gc>) { + self.event_type = event_type; } pub fn is_bubbling(&self) -> bool { @@ -182,11 +179,8 @@ impl<'gc> DispatchList<'gc> { /// Get all of the event handlers for a given event type, if such a type /// exists. - fn get_event( - &self, - event: impl Into>, - ) -> Option<&BTreeMap>>> { - self.0.get(&event.into()) + fn get_event(&self, event: AvmString<'gc>) -> Option<&BTreeMap>>> { + self.0.get(&event) } /// Get all of the event handlers for a given event type, for mutation. @@ -195,20 +189,20 @@ impl<'gc> DispatchList<'gc> { /// list. fn get_event_mut( &mut self, - event: impl Into>, + event: AvmString<'gc>, ) -> &mut BTreeMap>> { - self.0.entry(event.into()).or_default() + self.0.entry(event).or_default() } /// Get a single priority level of event handlers for a given event type, /// for mutation. fn get_event_priority_mut( &mut self, - event: impl Into>, + event: AvmString<'gc>, priority: i32, ) -> &mut Vec> { self.0 - .entry(event.into()) + .entry(event) .or_default() .entry(priority) .or_default() @@ -222,14 +216,14 @@ impl<'gc> DispatchList<'gc> { /// be added again, and this function will silently fail. pub fn add_event_listener( &mut self, - event: impl Into> + Clone, + event: AvmString<'gc>, priority: i32, handler: Object<'gc>, use_capture: bool, ) { let new_handler = EventHandler::new(handler, use_capture); - if let Some(event_sheaf) = self.get_event(event.clone()) { + if let Some(event_sheaf) = self.get_event(event) { for (_other_prio, other_set) in event_sheaf.iter() { if other_set.contains(&new_handler) { return; @@ -247,7 +241,7 @@ impl<'gc> DispatchList<'gc> { /// removed from any priority in the list. pub fn remove_event_listener( &mut self, - event: impl Into>, + event: AvmString<'gc>, handler: Object<'gc>, use_capture: bool, ) { @@ -261,7 +255,7 @@ impl<'gc> DispatchList<'gc> { } /// Determine if there are any event listeners in this dispatch list. - pub fn has_event_listener(&self, event: impl Into>) -> bool { + pub fn has_event_listener(&self, event: AvmString<'gc>) -> bool { if let Some(event_sheaf) = self.get_event(event) { for (_prio, set) in event_sheaf.iter() { if !set.is_empty() { @@ -283,7 +277,7 @@ impl<'gc> DispatchList<'gc> { /// phases. pub fn iter_event_handlers<'a>( &'a mut self, - event: impl Into>, + event: AvmString<'gc>, use_capture: bool, ) -> impl 'a + Iterator> { self.get_event_mut(event) diff --git a/core/src/avm2/method.rs b/core/src/avm2/method.rs index ee07272bc1078..61642bce04021 100644 --- a/core/src/avm2/method.rs +++ b/core/src/avm2/method.rs @@ -92,17 +92,6 @@ impl<'gc> ParamConfig<'gc> { }) } - pub fn of_type( - name: impl Into>, - param_type_name: Option>>, - ) -> Self { - Self { - param_name: name.into(), - param_type_name, - default_value: None, - } - } - pub fn optional( name: impl Into>, param_type_name: Option>>, diff --git a/core/src/avm2/multiname.rs b/core/src/avm2/multiname.rs index e6fbc0e346b6c..5fafd692d7384 100644 --- a/core/src/avm2/multiname.rs +++ b/core/src/avm2/multiname.rs @@ -362,10 +362,10 @@ impl<'gc> Multiname<'gc> { } /// Creates a new Multiname with the `MultinameFlags::ATTRIBUTE` flag. - pub fn attribute(ns: Namespace<'gc>, name: impl Into>) -> Self { + pub fn attribute(ns: Namespace<'gc>, name: AvmString<'gc>) -> Self { Self { ns: NamespaceSet::single(ns), - name: Some(name.into()), + name: Some(name), param: None, flags: MultinameFlags::ATTRIBUTE, } diff --git a/core/src/avm2/object.rs b/core/src/avm2/object.rs index c6a87c1ccab3d..7fad80470c9ac 100644 --- a/core/src/avm2/object.rs +++ b/core/src/avm2/object.rs @@ -239,7 +239,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy #[no_dynamic] fn get_string_property_local( self, - name: impl Into>, + name: AvmString<'gc>, activation: &mut Activation<'_, 'gc>, ) -> Result, Error<'gc>> { let name = Multiname::new(activation.avm2().namespaces.public_vm_internal(), name); diff --git a/core/src/avm2/regexp.rs b/core/src/avm2/regexp.rs index 125e713e466d3..6e267cd6bd0d3 100644 --- a/core/src/avm2/regexp.rs +++ b/core/src/avm2/regexp.rs @@ -52,12 +52,9 @@ bitflags! { } impl<'gc> RegExp<'gc> { - pub fn new(source: S) -> Self - where - S: Into>, - { + pub fn new(source: AvmString<'gc>) -> Self { Self { - source: source.into(), + source, flags: RegExpFlags::empty(), last_index: 0, cached_regex: None, @@ -69,12 +66,9 @@ impl<'gc> RegExp<'gc> { self.source } - pub fn set_source(&mut self, source: S) - where - S: Into>, - { + pub fn set_source(&mut self, source: AvmString<'gc>) { self.cached_regex = None; - self.source = source.into(); + self.source = source; } pub fn flags(&self) -> RegExpFlags {