diff --git a/core/src/avm2/amf.rs b/core/src/avm2/amf.rs index a330e96d331a..b235064ab7a9 100644 --- a/core/src/avm2/amf.rs +++ b/core/src/avm2/amf.rs @@ -82,7 +82,7 @@ pub fn serialize_value<'gc>( let int_vec: Vec<_> = vec .iter() .map(|v| { - v.as_integer(activation.context.gc_context) + v.as_integer(activation.strings()) .expect("Unexpected non-int value in int vector") }) .collect(); @@ -91,7 +91,7 @@ pub fn serialize_value<'gc>( let uint_vec: Vec<_> = vec .iter() .map(|v| { - v.as_u32(activation.context.gc_context) + v.as_u32(activation.strings()) .expect("Unexpected non-uint value in int vector") }) .collect(); @@ -100,7 +100,7 @@ pub fn serialize_value<'gc>( let num_vec: Vec<_> = vec .iter() .map(|v| { - v.as_number(activation.context.gc_context) + v.as_number(activation.strings()) .expect("Unexpected non-uint value in int vector") }) .collect(); diff --git a/core/src/avm2/globals/array.rs b/core/src/avm2/globals/array.rs index 0f59204b61e6..1f7f7aaeb401 100644 --- a/core/src/avm2/globals/array.rs +++ b/core/src/avm2/globals/array.rs @@ -75,7 +75,7 @@ pub fn instance_init<'gc>( if args.len() == 1 { if let Some(expected_len) = args .get(0) - .and_then(|v| v.as_number(activation.context.gc_context).ok()) + .and_then(|v| v.as_number(activation.strings()).ok()) { if expected_len < 0.0 || expected_len.is_nan() || expected_len.fract() != 0.0 { return Err(Error::AvmError(range_error( diff --git a/core/src/avm2/globals/date.rs b/core/src/avm2/globals/date.rs index 4596eb6f0968..593171887e52 100644 --- a/core/src/avm2/globals/date.rs +++ b/core/src/avm2/globals/date.rs @@ -260,7 +260,7 @@ pub fn get_time<'gc>( _args: &[Value<'gc>], ) -> Result, Error<'gc>> { let this = this.as_date_object().unwrap(); - this.value_of(activation.context.gc_context) + this.value_of(activation.strings()) } /// Implements `setTime` method. diff --git a/core/src/avm2/globals/flash/display/graphics.rs b/core/src/avm2/globals/flash/display/graphics.rs index 6c3dfeac46c8..e0aef2284158 100644 --- a/core/src/avm2/globals/flash/display/graphics.rs +++ b/core/src/avm2/globals/flash/display/graphics.rs @@ -1286,13 +1286,13 @@ fn read_point<'gc>( let x = data .get(*data_index, activation) .ok()? - .as_number(activation.context.gc_context) + .as_number(activation.strings()) .expect("data is not a Vec."); let y = data .get(*data_index + 1, activation) .ok()? - .as_number(activation.context.gc_context) + .as_number(activation.strings()) .expect("data is not a Vec."); *data_index += 2; @@ -1395,7 +1395,7 @@ fn process_commands<'gc>( let command = commands .get(i, activation) .expect("missing command") - .as_integer(activation.context.gc_context) + .as_integer(activation.strings()) .expect("commands is not a Vec."); if process_command(activation, drawing, data, command, &mut data_index).is_none() { diff --git a/core/src/avm2/globals/flash/display/shader_job.rs b/core/src/avm2/globals/flash/display/shader_job.rs index 6cf4dc7a1ff5..bdef3b993ff0 100644 --- a/core/src/avm2/globals/flash/display/shader_job.rs +++ b/core/src/avm2/globals/flash/display/shader_job.rs @@ -107,18 +107,18 @@ pub fn get_shader_args<'gc>( let width = shader_input .get_public_property("width", activation) .unwrap() - .as_u32(activation.context.gc_context) + .as_u32(activation.strings()) .unwrap(); let height = shader_input .get_public_property("height", activation) .unwrap() - .as_u32(activation.context.gc_context) + .as_u32(activation.strings()) .unwrap(); let input_channels = shader_input .get_public_property("channels", activation) .unwrap() - .as_u32(activation.context.gc_context) + .as_u32(activation.strings()) .unwrap(); assert_eq!(*channels as u32, input_channels); @@ -156,8 +156,7 @@ pub fn get_shader_args<'gc>( bytes: vector .iter() .flat_map(|val| { - (val.as_number(activation.context.gc_context).unwrap() - as f32) + (val.as_number(activation.strings()).unwrap() as f32) .to_le_bytes() }) .collect(), @@ -210,12 +209,12 @@ pub fn start<'gc>( let output_width = this .get_public_property("width", activation)? - .as_u32(activation.context.gc_context) + .as_u32(activation.strings()) .expect("ShaderJob.width is not a number"); let output_height = this .get_public_property("height", activation)? - .as_u32(activation.context.gc_context) + .as_u32(activation.strings()) .expect("ShaderJob.height is not a number"); let pixel_bender_target = if let Some(bitmap) = target.as_bitmap_data() { diff --git a/core/src/avm2/globals/flash/display3D/context_3d.rs b/core/src/avm2/globals/flash/display3D/context_3d.rs index c5cb70281add..0d9bfa68c081 100644 --- a/core/src/avm2/globals/flash/display3D/context_3d.rs +++ b/core/src/avm2/globals/flash/display3D/context_3d.rs @@ -365,10 +365,7 @@ pub fn set_program_constants_from_vector<'gc>( let raw_data = vector .iter() - .map(|val| { - val.as_number(activation.context.gc_context) - .map(|val| val as f32) - }) + .map(|val| val.as_number(activation.strings()).map(|val| val as f32)) .take(to_take) .collect::, _>>()?; @@ -384,13 +381,13 @@ pub fn clear<'gc>( ) -> Result, Error<'gc>> { if let Some(context) = this.as_context_3d() { // This is a native method, so all of the arguments have been checked and coerced for us - let red = args[0].as_number(activation.context.gc_context)?; - let green = args[1].as_number(activation.context.gc_context)?; - let blue = args[2].as_number(activation.context.gc_context)?; - let alpha = args[3].as_number(activation.context.gc_context)?; - let depth = args[4].as_number(activation.context.gc_context)?; - let stencil = args[5].as_integer(activation.context.gc_context)? as u32; - let mask = args[6].as_integer(activation.context.gc_context)? as u32; + let red = args[0].as_number(activation.strings())?; + let green = args[1].as_number(activation.strings())?; + let blue = args[2].as_number(activation.strings())?; + let alpha = args[3].as_number(activation.strings())?; + let depth = args[4].as_number(activation.strings())?; + let stencil = args[5].as_integer(activation.strings())? as u32; + let mask = args[6].as_integer(activation.strings())? as u32; context.set_clear(red, green, blue, alpha, depth, stencil, mask); } Ok(Value::Undefined) @@ -403,11 +400,11 @@ pub fn create_texture<'gc>( ) -> Result, Error<'gc>> { if let Some(context) = this.as_context_3d() { // This is a native method, so all of the arguments have been checked and coerced for us - let width = args[0].as_integer(activation.context.gc_context)? as u32; - let height = args[1].as_integer(activation.context.gc_context)? as u32; + let width = args[0].as_integer(activation.strings())? as u32; + let height = args[1].as_integer(activation.strings())? as u32; let format = args[2].coerce_to_string(activation)?; let optimize_for_render_to_texture = args[3].coerce_to_boolean(); - let streaming_levels = args[4].as_integer(activation.context.gc_context)? as u32; + let streaming_levels = args[4].as_integer(activation.strings())? as u32; let format = Context3DTextureFormat::from_wstr(&format).ok_or_else(|| { Error::RustError( format!("Unsupported texture format in createTexture: {:?}", format).into(), @@ -436,8 +433,8 @@ pub fn create_rectangle_texture<'gc>( ) -> Result, Error<'gc>> { if let Some(context) = this.as_context_3d() { // This is a native method, so all of the arguments have been checked and coerced for us - let width = args[0].as_integer(activation.context.gc_context)? as u32; - let height = args[1].as_integer(activation.context.gc_context)? as u32; + let width = args[0].as_integer(activation.strings())? as u32; + let height = args[1].as_integer(activation.strings())? as u32; let format = args[2].coerce_to_string(activation)?; let optimize_for_render_to_texture = args[3].coerce_to_boolean(); let format = Context3DTextureFormat::from_wstr(&format).ok_or_else(|| { @@ -472,10 +469,10 @@ pub fn create_cube_texture<'gc>( ) -> Result, Error<'gc>> { if let Some(context) = this.as_context_3d() { // This is a native method, so all of the arguments have been checked and coerced for us - let size = args[0].as_integer(activation.context.gc_context)? as u32; + let size = args[0].as_integer(activation.strings())? as u32; let format = args[1].coerce_to_string(activation)?; let optimize_for_render_to_texture = args[2].coerce_to_boolean(); - let streaming_levels = args[3].as_integer(activation.context.gc_context)? as u32; + let streaming_levels = args[3].as_integer(activation.strings())? as u32; let format = Context3DTextureFormat::from_wstr(&format).ok_or_else(|| { Error::RustError( format!( @@ -504,7 +501,7 @@ pub fn set_texture_at<'gc>( ) -> Result, Error<'gc>> { if let Some(context) = this.as_context_3d() { // This is a native method, so all of the arguments have been checked and coerced for us - let sampler = args[0].as_integer(activation.context.gc_context)? as u32; + let sampler = args[0].as_integer(activation.strings())? as u32; let mut cube = false; let texture = if matches!(args[1], Value::Null) { None @@ -655,7 +652,7 @@ pub fn set_sampler_state_at<'gc>( ) -> Result, Error<'gc>> { if let Some(context) = this.as_context_3d() { // This is a native method, so all of the arguments have been checked and coerced for us - let sampler = args[0].as_integer(activation.context.gc_context)? as u32; + let sampler = args[0].as_integer(activation.strings())? as u32; let wrap = args[1].coerce_to_string(activation)?; let filter = args[2].coerce_to_string(activation)?; let mip_filter = args[3].coerce_to_string(activation)?; diff --git a/core/src/avm2/globals/json.rs b/core/src/avm2/globals/json.rs index 33ee7f4640cf..d22a0b9ef0d2 100644 --- a/core/src/avm2/globals/json.rs +++ b/core/src/avm2/globals/json.rs @@ -334,7 +334,7 @@ pub fn stringify<'gc>( } } else { let indent_size = spaces - .as_number(activation.context.gc_context) + .as_number(activation.strings()) .unwrap_or(0.0) .clamp(0.0, 10.0) as u16; if indent_size == 0 { diff --git a/core/src/avm2/globals/object.rs b/core/src/avm2/globals/object.rs index 26c44c6dfd89..a3884082b0e6 100644 --- a/core/src/avm2/globals/object.rs +++ b/core/src/avm2/globals/object.rs @@ -181,7 +181,7 @@ fn value_of<'gc>( this: Object<'gc>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - this.value_of(activation.context.gc_context) + this.value_of(activation.strings()) } /// `Object.prototype.hasOwnProperty` diff --git a/core/src/avm2/globals/string.rs b/core/src/avm2/globals/string.rs index 216c61489bc7..ffb729e213ae 100644 --- a/core/src/avm2/globals/string.rs +++ b/core/src/avm2/globals/string.rs @@ -103,7 +103,7 @@ fn length<'gc>( this: Object<'gc>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - if let Value::String(s) = this.value_of(activation.context.gc_context)? { + if let Value::String(s) = this.value_of(activation.strings())? { return Ok(s.len().into()); } @@ -116,7 +116,7 @@ fn char_at<'gc>( this: Object<'gc>, args: &[Value<'gc>], ) -> Result, Error<'gc>> { - if let Value::String(s) = this.value_of(activation.context.gc_context)? { + if let Value::String(s) = this.value_of(activation.strings())? { // This function takes Number, so if we use coerce_to_i32 instead of coerce_to_number, the value may overflow. let n = args .get(0) @@ -144,7 +144,7 @@ fn char_code_at<'gc>( this: Object<'gc>, args: &[Value<'gc>], ) -> Result, Error<'gc>> { - if let Value::String(s) = this.value_of(activation.context.gc_context)? { + if let Value::String(s) = this.value_of(activation.strings())? { // This function takes Number, so if we use coerce_to_i32 instead of coerce_to_number, the value may overflow. let n = args .get(0) @@ -634,7 +634,7 @@ fn value_of<'gc>( this: Object<'gc>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - this.value_of(activation.context.gc_context) + this.value_of(activation.strings()) } /// Implements `String.toUpperCase` diff --git a/core/src/avm2/object.rs b/core/src/avm2/object.rs index 433f0594328f..66f67b113d9d 100644 --- a/core/src/avm2/object.rs +++ b/core/src/avm2/object.rs @@ -20,7 +20,7 @@ use crate::bitmap::bitmap_data::BitmapDataWrapper; use crate::display_object::DisplayObject; use crate::html::TextFormat; use crate::streams::NetStream; -use crate::string::AvmString; +use crate::string::{AvmString, StringContext}; use gc_arena::{Collect, Gc, Mutation}; use ruffle_macros::enum_trait_object; use std::cell::{Ref, RefMut}; @@ -990,7 +990,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy /// /// The default implementation wraps the object in a `Value`, using the /// `Into>` implementation. - fn value_of(&self, _mc: &Mutation<'gc>) -> Result, Error<'gc>> { + fn value_of(&self, _context: &mut StringContext<'gc>) -> Result, Error<'gc>> { Ok(Value::Object((*self).into())) } diff --git a/core/src/avm2/object/date_object.rs b/core/src/avm2/object/date_object.rs index ef0e7c53fa13..31ece20d7bec 100644 --- a/core/src/avm2/object/date_object.rs +++ b/core/src/avm2/object/date_object.rs @@ -3,9 +3,10 @@ use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{ClassObject, Object, ObjectPtr, TObject}; use crate::avm2::value::{Hint, Value}; use crate::avm2::Error; +use crate::string::StringContext; use chrono::{DateTime, Utc}; use core::fmt; -use gc_arena::{Collect, Gc, GcWeak, Mutation}; +use gc_arena::{Collect, Gc, GcWeak}; use std::cell::Cell; /// A class instance allocator that allocates Date objects. @@ -96,7 +97,7 @@ impl<'gc> TObject<'gc> for DateObject<'gc> { Gc::as_ptr(self.0) as *const ObjectPtr } - fn value_of(&self, _mc: &Mutation<'gc>) -> Result, Error<'gc>> { + fn value_of(&self, _context: &mut StringContext<'gc>) -> Result, Error<'gc>> { if let Some(date) = self.date_time() { Ok((date.timestamp_millis() as f64).into()) } else { diff --git a/core/src/avm2/object/dispatch_object.rs b/core/src/avm2/object/dispatch_object.rs index 7171ad5f9f49..f497754a3a12 100644 --- a/core/src/avm2/object/dispatch_object.rs +++ b/core/src/avm2/object/dispatch_object.rs @@ -6,6 +6,7 @@ use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{Object, ObjectPtr, TObject}; use crate::avm2::value::Value; use crate::avm2::Error; +use crate::string::StringContext; use core::fmt; use gc_arena::barrier::unlock; use gc_arena::{lock::RefLock, Collect, Gc, GcWeak, Mutation}; @@ -104,7 +105,7 @@ impl<'gc> TObject<'gc> for DispatchObject<'gc> { Err("Cannot construct internal event dispatcher structures.".into()) } - fn value_of(&self, _mc: &Mutation<'gc>) -> Result, Error<'gc>> { + fn value_of(&self, _context: &mut StringContext<'gc>) -> Result, Error<'gc>> { Err("Cannot subclass internal event dispatcher structures.".into()) } diff --git a/core/src/avm2/object/namespace_object.rs b/core/src/avm2/object/namespace_object.rs index cd8899f1b14e..c0cf2b1dfedd 100644 --- a/core/src/avm2/object/namespace_object.rs +++ b/core/src/avm2/object/namespace_object.rs @@ -6,7 +6,7 @@ use crate::avm2::object::{ClassObject, Object, ObjectPtr, TObject}; use crate::avm2::value::Value; use crate::avm2::Error; use crate::avm2::Namespace; -use crate::string::AvmString; +use crate::string::{AvmString, StringContext}; use core::fmt; use gc_arena::barrier::unlock; use gc_arena::{lock::Lock, Collect, Gc, GcWeak, Mutation}; @@ -123,12 +123,8 @@ impl<'gc> TObject<'gc> for NamespaceObject<'gc> { Gc::as_ptr(self.0) as *const ObjectPtr } - fn value_of(&self, _mc: &Mutation<'gc>) -> Result, Error<'gc>> { - // TODO(moulins): pass in a StringContext so we can call .as_uri() directly. - match self.0.namespace.get().as_uri_opt() { - Some(uri) => Ok(uri.into()), - None => Ok("".into()), - } + fn value_of(&self, context: &mut StringContext<'gc>) -> Result, Error<'gc>> { + Ok(self.0.namespace.get().as_uri(context).into()) } fn as_namespace(&self) -> Option> { diff --git a/core/src/avm2/object/primitive_object.rs b/core/src/avm2/object/primitive_object.rs index 33bd90ed26d9..2673a3b1817f 100644 --- a/core/src/avm2/object/primitive_object.rs +++ b/core/src/avm2/object/primitive_object.rs @@ -8,7 +8,7 @@ use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{ClassObject, Object, ObjectPtr, TObject}; use crate::avm2::value::Value; use crate::avm2::Error; -use crate::string::AvmString; +use crate::string::{AvmString, StringContext}; use gc_arena::barrier::unlock; use gc_arena::{lock::RefLock, Collect, Gc, GcWeak, Mutation}; @@ -142,7 +142,7 @@ impl<'gc> TObject<'gc> for PrimitiveObject<'gc> { } } - fn value_of(&self, _mc: &Mutation<'gc>) -> Result, Error<'gc>> { + fn value_of(&self, _context: &mut StringContext<'gc>) -> Result, Error<'gc>> { Ok(*self.0.primitive.borrow()) } diff --git a/core/src/avm2/object/regexp_object.rs b/core/src/avm2/object/regexp_object.rs index a632175b2f8a..c4f6333b4272 100644 --- a/core/src/avm2/object/regexp_object.rs +++ b/core/src/avm2/object/regexp_object.rs @@ -6,7 +6,7 @@ use crate::avm2::object::{ClassObject, Object, ObjectPtr, TObject}; use crate::avm2::regexp::{RegExp, RegExpFlags}; use crate::avm2::value::Value; use crate::avm2::Error; -use crate::string::{AvmString, WString}; +use crate::string::{AvmString, StringContext, WString}; use core::fmt; use gc_arena::barrier::unlock; use gc_arena::{lock::RefLock, Collect, Gc, GcWeak, Mutation}; @@ -95,7 +95,7 @@ impl<'gc> TObject<'gc> for RegExpObject<'gc> { Gc::as_ptr(self.0) as *const ObjectPtr } - fn value_of(&self, mc: &Mutation<'gc>) -> Result, Error<'gc>> { + fn value_of(&self, context: &mut StringContext<'gc>) -> Result, Error<'gc>> { let regexp = self.0.regexp.borrow(); let mut s = WString::new(); s.push_byte(b'/'); @@ -120,7 +120,7 @@ impl<'gc> TObject<'gc> for RegExpObject<'gc> { s.push_byte(b'x'); } - Ok(AvmString::new(mc, s).into()) + Ok(AvmString::new(context.gc(), s).into()) } /// Unwrap this object as a regexp. diff --git a/core/src/avm2/value.rs b/core/src/avm2/value.rs index 931fd39841e6..95b15d1209f9 100644 --- a/core/src/avm2/value.rs +++ b/core/src/avm2/value.rs @@ -9,8 +9,8 @@ use crate::avm2::Error; use crate::avm2::Multiname; use crate::avm2::Namespace; use crate::ecma_conversions::{f64_to_wrapping_i32, f64_to_wrapping_u32}; -use crate::string::{AvmAtom, AvmString, WStr}; -use gc_arena::{Collect, Mutation}; +use crate::string::{AvmAtom, AvmString, StringContext, WStr}; +use gc_arena::Collect; use num_bigint::BigInt; use num_traits::{ToPrimitive, Zero}; use std::mem::size_of; @@ -556,13 +556,13 @@ impl<'gc> Value<'gc> { /// object methods called. This should only be used if you specifically /// need the behavior of only handling actual numbers; otherwise you should /// use the appropriate `coerce_to_` method. - pub fn as_number(&self, mc: &Mutation<'gc>) -> Result> { + pub fn as_number(&self, context: &mut StringContext<'gc>) -> Result> { match self { // Methods that look for numbers in Flash Player don't seem to care // about user-defined `valueOf` implementations. This code upholds // that limitation as long as `TObject`'s `value_of` method also // does not call user-defined functions. - Value::Object(num) => match num.value_of(mc)? { + Value::Object(num) => match num.value_of(context)? { Value::Number(num) => Ok(num), Value::Integer(num) => Ok(num as f64), _ => Err(format!("Expected Number, int, or uint, found {self:?}").into()), @@ -574,9 +574,9 @@ impl<'gc> Value<'gc> { } /// Like `as_number`, but for `i32` - pub fn as_integer(&self, mc: &Mutation<'gc>) -> Result> { + pub fn as_integer(&self, context: &mut StringContext<'gc>) -> Result> { match self { - Value::Object(num) => match num.value_of(mc)? { + Value::Object(num) => match num.value_of(context)? { Value::Number(num) => Ok(num as i32), Value::Integer(num) => Ok(num), _ => Err(format!("Expected Number, int, or uint, found {self:?}").into()), @@ -588,9 +588,9 @@ impl<'gc> Value<'gc> { } /// Like `as_number`, but for `u32` - pub fn as_u32(&self, mc: &Mutation<'gc>) -> Result> { + pub fn as_u32(&self, context: &mut StringContext<'gc>) -> Result> { match self { - Value::Object(num) => match num.value_of(mc)? { + Value::Object(num) => match num.value_of(context)? { Value::Number(num) => Ok(num as u32), Value::Integer(num) => Ok(num as u32), _ => Err(format!("Expected Number, int, or uint, found {self:?}").into()), @@ -654,7 +654,7 @@ impl<'gc> Value<'gc> { }); match self { - Value::Object(Object::PrimitiveObject(o)) => o.value_of(activation.context.gc_context), + Value::Object(Object::PrimitiveObject(o)) => o.value_of(activation.strings()), Value::Object(o) if hint == Hint::String => { let object = *o; diff --git a/core/src/bitmap/operations.rs b/core/src/bitmap/operations.rs index dc9a1dff1076..1a774442f266 100644 --- a/core/src/bitmap/operations.rs +++ b/core/src/bitmap/operations.rs @@ -1669,7 +1669,7 @@ pub fn set_vector<'gc>( let color = iter .next() .expect("BitmapData.setVector: Expected element") - .as_u32(activation.context.gc_context) + .as_u32(activation.strings()) .expect("BitmapData.setVector: Expected uint vector"); bitmap_data.set_pixel32_raw( x,