diff --git a/core/src/avm1/globals/text_field.rs b/core/src/avm1/globals/text_field.rs index b303b8644..ce09c2ceb 100644 --- a/core/src/avm1/globals/text_field.rs +++ b/core/src/avm1/globals/text_field.rs @@ -208,6 +208,64 @@ macro_rules! with_text_field { }}; } +macro_rules! with_text_field_props { + ($obj:ident, $gc:ident, $fn_proto:ident, $($name:literal => [$get:ident $(, $set:ident)*],)*) => { + $( + $obj.add_property( + $gc, + $name, + with_text_field_props!(getter $gc, $fn_proto, $get), + with_text_field_props!(setter $gc, $fn_proto, $($set),*), + Default::default() + ); + )* + }; + + (getter $gc:ident, $fn_proto:ident, $get:ident) => { + FunctionObject::function( + $gc, + Executable::Native( + |activation: &mut Activation<'_, 'gc, '_>, this, _args| -> Result, Error<'gc>> { + if let Some(display_object) = this.as_display_object() { + if let Some(edit_text) = display_object.as_edit_text() { + return $get(edit_text, activation); + } + } + Ok(Value::Undefined) + } as crate::avm1::function::NativeFunction<'gc> + ), + Some($fn_proto), + $fn_proto + ) + }; + + (setter $gc:ident, $fn_proto:ident, $set:ident) => { + Some(FunctionObject::function( + $gc, + Executable::Native( + |activation: &mut Activation<'_, 'gc, '_>, this, args| -> Result, Error<'gc>> { + if let Some(display_object) = this.as_display_object() { + if let Some(edit_text) = display_object.as_edit_text() { + let value = args + .get(0) + .unwrap_or(&Value::Undefined) + .clone(); + $set(edit_text, activation, value)?; + } + } + Ok(Value::Undefined) + } as crate::avm1::function::NativeFunction<'gc> + ), + Some($fn_proto), + $fn_proto) + ) + }; + + (setter $gc:ident, $fn_proto:ident,) => { + None + }; +} + pub fn text_width<'gc>( activation: &mut Activation<'_, 'gc, '_>, this: Object<'gc>, @@ -452,6 +510,11 @@ pub fn create_proto<'gc>( "replaceText" => replace_text ); + with_text_field_props!( + object, gc_context, fn_proto, + "type" => [get_type, set_type], + ); + object.into() } @@ -770,3 +833,31 @@ fn replace_text<'gc>( Ok(Value::Undefined) } + +pub fn get_type<'gc>( + this: EditText<'gc>, + activation: &mut Activation<'_, 'gc, '_>, +) -> Result, Error<'gc>> { + let tf_type = match this.is_editable() { + true => "input", + false => "dynamic", + }; + Ok(AvmString::new(activation.context.gc_context, tf_type).into()) +} + +pub fn set_type<'gc>( + this: EditText<'gc>, + activation: &mut Activation<'_, 'gc, '_>, + value: Value<'gc>, +) -> Result<(), Error<'gc>> { + match value + .coerce_to_string(activation)? + .to_ascii_lowercase() + .as_str() + { + "input" => this.set_editable(true, &mut activation.context), + "dynamic" => this.set_editable(false, &mut activation.context), + value => log::warn!("Invalid TextField.type: {}", value), + }; + Ok(()) +} diff --git a/core/src/display_object/edit_text.rs b/core/src/display_object/edit_text.rs index c81580051..3a0804b73 100644 --- a/core/src/display_object/edit_text.rs +++ b/core/src/display_object/edit_text.rs @@ -411,6 +411,14 @@ impl<'gc> EditText<'gc> { self.relayout(context); } + pub fn is_editable(self) -> bool { + self.0.read().is_editable + } + + pub fn set_editable(self, is_editable: bool, context: &mut UpdateContext<'_, 'gc, '_>) { + self.0.write(context.gc_context).is_editable = is_editable; + } + pub fn is_multiline(self) -> bool { self.0.read().is_multiline } diff --git a/core/tests/regression_tests.rs b/core/tests/regression_tests.rs index cf7c7d479..68ec71d8f 100644 --- a/core/tests/regression_tests.rs +++ b/core/tests/regression_tests.rs @@ -245,6 +245,7 @@ swf_tests! { #[ignore] (edittext_html_roundtrip, "avm1/edittext_html_roundtrip", 1), (edittext_newline_stripping, "avm1/edittext_newline_stripping", 1), (define_local, "avm1/define_local", 1), + (textfield_properties, "avm1/textfield_properties", 1), (textfield_variable, "avm1/textfield_variable", 8), (error, "avm1/error", 1), (color_transform, "avm1/color_transform", 1), diff --git a/core/tests/swfs/avm1/textfield_properties/output.txt b/core/tests/swfs/avm1/textfield_properties/output.txt new file mode 100644 index 000000000..bdd1e2c9d --- /dev/null +++ b/core/tests/swfs/avm1/textfield_properties/output.txt @@ -0,0 +1,8 @@ +// txt.type: +dynamic +// txt.type = 'input': +input +// txt.type = 'DYNAMIC': +dynamic +// txt.type = 'invalid': +dynamic diff --git a/core/tests/swfs/avm1/textfield_properties/test.fla b/core/tests/swfs/avm1/textfield_properties/test.fla new file mode 100644 index 000000000..0ddcc4fdf Binary files /dev/null and b/core/tests/swfs/avm1/textfield_properties/test.fla differ diff --git a/core/tests/swfs/avm1/textfield_properties/test.swf b/core/tests/swfs/avm1/textfield_properties/test.swf new file mode 100644 index 000000000..cf6aa7e3f Binary files /dev/null and b/core/tests/swfs/avm1/textfield_properties/test.swf differ