diff --git a/core/src/avm1/globals/button.rs b/core/src/avm1/globals/button.rs index 18fbc9f200ef..5b81ab785709 100644 --- a/core/src/avm1/globals/button.rs +++ b/core/src/avm1/globals/button.rs @@ -9,7 +9,7 @@ use crate::avm1::ArrayObject; use crate::avm1::{globals, Object, ScriptObject, TObject, Value}; use crate::avm1_stub; use crate::context::GcContext; -use crate::display_object::{Avm1Button, TDisplayObject}; +use crate::display_object::{Avm1Button, TDisplayObject, TInteractiveObject}; use crate::string::AvmString; macro_rules! button_getter { @@ -180,8 +180,8 @@ fn tab_index<'gc>( this: Avm1Button<'gc>, _activation: &mut Activation<'_, 'gc>, ) -> Result, Error<'gc>> { - if let Some(index) = this.tab_index_value() { - Ok(index.into()) + if let Some(index) = this.as_interactive().and_then(|this| this.tab_index()) { + Ok(Value::Number(index as f64)) } else { Ok(Value::Undefined) } @@ -192,19 +192,18 @@ fn set_tab_index<'gc>( activation: &mut Activation<'_, 'gc>, value: Value<'gc>, ) -> Result<(), Error<'gc>> { - match value { - Value::Undefined | Value::Null => { - this.set_tab_index_value(&mut activation.context, None); - } - Value::Bool(_) | Value::Number(_) => { - // FIXME This coercion is not perfect, as it wraps - // instead of falling back to MIN, as FP does - let i32_value = value.coerce_to_i32(activation)?; - this.set_tab_index_value(&mut activation.context, Some(i32_value)); - } - _ => { - this.set_tab_index_value(&mut activation.context, Some(i32::MIN)); - } - }; + if let Some(this) = this.as_interactive() { + let value = match value { + Value::Undefined | Value::Null => None, + Value::Bool(_) | Value::Number(_) => { + // FIXME This coercion is not perfect, as it wraps + // instead of falling back to MIN, as FP does + let i32_value = value.coerce_to_i32(activation)?; + Some(i32_value) + } + _ => Some(i32::MIN), + }; + this.set_tab_index(&mut activation.context, value); + } Ok(()) } diff --git a/core/src/avm1/globals/movie_clip.rs b/core/src/avm1/globals/movie_clip.rs index 797326726758..8dc349147199 100644 --- a/core/src/avm1/globals/movie_clip.rs +++ b/core/src/avm1/globals/movie_clip.rs @@ -9,7 +9,7 @@ use crate::avm1::property_decl::{define_properties_on, Declaration}; use crate::avm1::{self, ArrayObject, Object, ScriptObject, TObject, Value}; use crate::backend::navigator::NavigationMethod; use crate::context::{GcContext, UpdateContext}; -use crate::display_object::{Bitmap, EditText, MovieClip}; +use crate::display_object::{Bitmap, EditText, MovieClip, TInteractiveObject}; use crate::ecma_conversions::f64_to_wrapping_i32; use crate::prelude::*; use crate::string::AvmString; @@ -1828,8 +1828,8 @@ fn tab_index<'gc>( this: MovieClip<'gc>, _activation: &mut Activation<'_, 'gc>, ) -> Result, Error<'gc>> { - if let Some(index) = this.tab_index_value() { - Ok(index.into()) + if let Some(index) = this.as_interactive().and_then(|this| this.tab_index()) { + Ok(Value::Number(index as f64)) } else { Ok(Value::Undefined) } @@ -1840,19 +1840,18 @@ fn set_tab_index<'gc>( activation: &mut Activation<'_, 'gc>, value: Value<'gc>, ) -> Result<(), Error<'gc>> { - match value { - Value::Undefined | Value::Null => { - this.set_tab_index_value(&mut activation.context, None); - } - Value::Bool(_) | Value::Number(_) => { - // FIXME This coercion is not perfect, as it wraps - // instead of falling back to MIN, as FP does - let i32_value = value.coerce_to_i32(activation)?; - this.set_tab_index_value(&mut activation.context, Some(i32_value)); - } - _ => { - this.set_tab_index_value(&mut activation.context, Some(i32::MIN)); - } - }; + if let Some(this) = this.as_interactive() { + let value = match value { + Value::Undefined | Value::Null => None, + Value::Bool(_) | Value::Number(_) => { + // FIXME This coercion is not perfect, as it wraps + // instead of falling back to MIN, as FP does + let i32_value = value.coerce_to_i32(activation)?; + Some(i32_value) + } + _ => Some(i32::MIN), + }; + this.set_tab_index(&mut activation.context, value); + } Ok(()) } diff --git a/core/src/avm1/globals/text_field.rs b/core/src/avm1/globals/text_field.rs index d93d0cae253e..e7d3eb44a4d2 100644 --- a/core/src/avm1/globals/text_field.rs +++ b/core/src/avm1/globals/text_field.rs @@ -5,7 +5,9 @@ use crate::avm1::object::NativeObject; use crate::avm1::property_decl::{define_properties_on, Declaration}; use crate::avm1::{globals, ArrayObject, Object, ScriptObject, TObject, Value}; use crate::context::GcContext; -use crate::display_object::{AutoSizeMode, EditText, TDisplayObject, TextSelection}; +use crate::display_object::{ + AutoSizeMode, EditText, TDisplayObject, TInteractiveObject, TextSelection, +}; use crate::font::round_down_to_pixel; use crate::html::TextFormat; use crate::string::{AvmString, WStr}; @@ -919,8 +921,8 @@ pub fn tab_index<'gc>( this: EditText<'gc>, _activation: &mut Activation<'_, 'gc>, ) -> Result, Error<'gc>> { - if let Some(index) = this.tab_index_value() { - Ok(index.into()) + if let Some(index) = this.as_interactive().and_then(|this| this.tab_index()) { + Ok(Value::Number(index as u32 as f64)) } else { Ok(Value::Undefined) } @@ -931,14 +933,18 @@ pub fn set_tab_index<'gc>( activation: &mut Activation<'_, 'gc>, value: Value<'gc>, ) -> Result<(), Error<'gc>> { - match value { - Value::Undefined | Value::Null => { - this.set_tab_index_value(&mut activation.context, None); - } - _ => { - let u32_value = value.coerce_to_u32(activation)?; - this.set_tab_index_value(&mut activation.context, Some(u32_value)); - } - }; + if let Some(this) = this.as_interactive() { + let value = match value { + Value::Undefined | Value::Null => None, + _ => { + // `tabIndex` is u32 in TextField, compared to i32 in Button and MovieClip, + // but that is only a data representation difference, + // as both are interpreted as i32. + let u32_value = value.coerce_to_u32(activation)?; + Some(u32_value as i32) + } + }; + this.set_tab_index(&mut activation.context, value); + } Ok(()) } diff --git a/core/src/avm2/error.rs b/core/src/avm2/error.rs index 7f5d99b4c81e..0f791bd45040 100644 --- a/core/src/avm2/error.rs +++ b/core/src/avm2/error.rs @@ -427,6 +427,23 @@ pub fn make_error_2008<'gc>(activation: &mut Activation<'_, 'gc>, param_name: &s } } +#[inline(never)] +#[cold] +pub fn make_error_2027<'gc>(activation: &mut Activation<'_, 'gc>, value: i32) -> Error<'gc> { + let err = range_error( + activation, + &format!( + "Error #2027: Parameter tabIndex must be a non-negative number; got {}.", + value + ), + 2027, + ); + match err { + Ok(err) => Error::AvmError(err), + Err(err) => err, + } +} + #[inline(never)] #[cold] pub fn make_error_2037<'gc>(activation: &mut Activation<'_, 'gc>) -> Error<'gc> { diff --git a/core/src/avm2/globals/flash/display/Stage.as b/core/src/avm2/globals/flash/display/Stage.as index a0d6647baf18..21e9a0bac8c7 100644 --- a/core/src/avm2/globals/flash/display/Stage.as +++ b/core/src/avm2/globals/flash/display/Stage.as @@ -149,7 +149,8 @@ package flash.display { } override public function set tabChildren(value:Boolean):void { - super.tabChildren = value; + // Docs say that this operation throws IllegalOperationError, + // but in reality this call is just ignored. } override public function set tabEnabled(value:Boolean):void { diff --git a/core/src/avm2/globals/flash/display/display_object_container.rs b/core/src/avm2/globals/flash/display/display_object_container.rs index 87171d1aa8ca..546ac7817560 100644 --- a/core/src/avm2/globals/flash/display/display_object_container.rs +++ b/core/src/avm2/globals/flash/display/display_object_container.rs @@ -9,10 +9,10 @@ use crate::avm2::object::{Object, TObject}; use crate::avm2::parameters::ParametersExt; use crate::avm2::value::Value; use crate::avm2::{ArrayObject, ArrayStorage, Error}; +use crate::avm2_stub_method; use crate::context::UpdateContext; use crate::display_object::HitTestOptions; use crate::display_object::{DisplayObject, TDisplayObject, TDisplayObjectContainer}; -use crate::{avm2_stub_getter, avm2_stub_method, avm2_stub_setter}; use std::cmp::min; /// Implements `flash.display.DisplayObjectContainer`'s native instance constructor. @@ -637,28 +637,31 @@ pub fn set_mouse_children<'gc>( pub fn get_tab_children<'gc>( activation: &mut Activation<'_, 'gc>, - _this: Object<'gc>, + this: Object<'gc>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - avm2_stub_getter!( - activation, - "flash.display.DisplayObjectContainer", - "tabChildren" - ); - - Ok(true.into()) + if let Some(obj) = this + .as_display_object() + .and_then(|this| this.as_container()) + { + Ok(Value::Bool(obj.is_tab_children(&mut activation.context))) + } else { + Ok(Value::Undefined) + } } pub fn set_tab_children<'gc>( activation: &mut Activation<'_, 'gc>, - _this: Object<'gc>, - _args: &[Value<'gc>], + this: Object<'gc>, + args: &[Value<'gc>], ) -> Result, Error<'gc>> { - avm2_stub_setter!( - activation, - "flash.display.DisplayObjectContainer", - "tabChildren" - ); + if let Some(obj) = this + .as_display_object() + .and_then(|this| this.as_container()) + { + let value = args.get_bool(0); + obj.set_tab_children(&mut activation.context, value); + } Ok(Value::Undefined) } diff --git a/core/src/avm2/globals/flash/display/interactive_object.rs b/core/src/avm2/globals/flash/display/interactive_object.rs index 43d148fc2963..23cd6740d850 100644 --- a/core/src/avm2/globals/flash/display/interactive_object.rs +++ b/core/src/avm2/globals/flash/display/interactive_object.rs @@ -1,6 +1,7 @@ //! `flash.display.InteractiveObject` builtin/prototype use crate::avm2::activation::Activation; +use crate::avm2::error::make_error_2027; use crate::avm2::object::{Object, TObject}; use crate::avm2::parameters::ParametersExt; use crate::avm2::value::Value; @@ -120,40 +121,59 @@ pub fn set_context_menu<'gc>( pub fn get_tab_enabled<'gc>( activation: &mut Activation<'_, 'gc>, - _this: Object<'gc>, + this: Object<'gc>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - avm2_stub_getter!(activation, "flash.display.InteractiveObject", "tabEnabled"); - - Ok(false.into()) + if let Some(obj) = this.as_display_object().and_then(|o| o.as_interactive()) { + Ok(Value::Bool(obj.tab_enabled(&mut activation.context))) + } else { + Ok(Value::Undefined) + } } pub fn set_tab_enabled<'gc>( activation: &mut Activation<'_, 'gc>, - _this: Object<'gc>, - _args: &[Value<'gc>], + this: Object<'gc>, + args: &[Value<'gc>], ) -> Result, Error<'gc>> { - avm2_stub_setter!(activation, "flash.display.InteractiveObject", "tabIndex"); + if let Some(obj) = this + .as_display_object() + .and_then(|this| this.as_interactive()) + { + let value = args.get_bool(0); + obj.set_tab_enabled(&mut activation.context, value); + } Ok(Value::Undefined) } pub fn get_tab_index<'gc>( - activation: &mut Activation<'_, 'gc>, - _this: Object<'gc>, + _activation: &mut Activation<'_, 'gc>, + this: Object<'gc>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - avm2_stub_getter!(activation, "flash.display.InteractiveObject", "tabIndex"); - - Ok((-1).into()) + if let Some(obj) = this + .as_display_object() + .and_then(|this| this.as_interactive()) + { + Ok(Value::Number(obj.tab_index().unwrap_or(-1) as f64)) + } else { + Ok(Value::Undefined) + } } pub fn set_tab_index<'gc>( activation: &mut Activation<'_, 'gc>, - _this: Object<'gc>, - _args: &[Value<'gc>], + this: Object<'gc>, + args: &[Value<'gc>], ) -> Result, Error<'gc>> { - avm2_stub_setter!(activation, "flash.display.InteractiveObject", "tabIndex"); + if let Some(obj) = this.as_display_object().and_then(|o| o.as_interactive()) { + let value = args.get_i32(activation, 0)?; + if value < 0 { + return Err(make_error_2027(activation, value)); + } + obj.set_tab_index(&mut activation.context, Some(value)); + } Ok(Value::Undefined) } diff --git a/core/src/display_object/avm1_button.rs b/core/src/display_object/avm1_button.rs index 654c8bb85786..095ed6a5e323 100644 --- a/core/src/display_object/avm1_button.rs +++ b/core/src/display_object/avm1_button.rs @@ -46,9 +46,6 @@ pub struct Avm1ButtonData<'gc> { object: Lock>>, initialized: Cell, has_focus: Cell, - // TODO Consider moving this to InteractiveObject along with - // TextField's and MovieClip's tab indices after AVM2 analysis - tab_index: Cell>, } #[derive(Clone, Collect)] @@ -102,7 +99,6 @@ impl<'gc> Avm1Button<'gc> { ButtonTracking::Push }), has_focus: Cell::new(false), - tab_index: Cell::new(None), }, )) } @@ -245,18 +241,6 @@ impl<'gc> Avm1Button<'gc> { fn use_hand_cursor(self, context: &mut UpdateContext<'_, 'gc>) -> bool { self.get_boolean_property(context, "useHandCursor", true) } - - /// Get the value of `tabIndex` used in AS. - /// - /// Do not confuse it with `tab_index`, which returns the value used for ordering. - pub fn tab_index_value(&self) -> Option { - self.0.tab_index.get() - } - - /// Set the value of `tabIndex` used in AS. - pub fn set_tab_index_value(&self, _context: &mut UpdateContext<'_, 'gc>, value: Option) { - self.0.tab_index.set(value) - } } impl<'gc> TDisplayObject<'gc> for Avm1Button<'gc> { @@ -634,13 +618,9 @@ impl<'gc> TInteractiveObject<'gc> for Avm1Button<'gc> { self.call_focus_handler(context, focused, other); } - fn is_tabbable(&self, context: &mut UpdateContext<'_, 'gc>) -> bool { + fn tab_enabled_avm1(&self, context: &mut UpdateContext<'_, 'gc>) -> bool { self.get_avm1_boolean_property(context, "tabEnabled", |_| true) } - - fn tab_index(&self) -> Option { - self.0.tab_index.get().map(|i| i as i64) - } } impl<'gc> Avm1ButtonData<'gc> { diff --git a/core/src/display_object/avm2_button.rs b/core/src/display_object/avm2_button.rs index 47e34a86dbe5..07c80bcc8249 100644 --- a/core/src/display_object/avm2_button.rs +++ b/core/src/display_object/avm2_button.rs @@ -826,11 +826,16 @@ impl<'gc> TInteractiveObject<'gc> for Avm2Button<'gc> { fn on_focus_changed( &self, - _context: &mut UpdateContext<'_, 'gc>, + context: &mut UpdateContext<'_, 'gc>, focused: bool, - _other: Option>, + other: Option>, ) { self.0.has_focus.set(focused); + self.call_focus_handler(context, focused, other); + } + + fn tab_enabled_avm2_default(&self, _context: &mut UpdateContext<'_, 'gc>) -> bool { + true } } diff --git a/core/src/display_object/container.rs b/core/src/display_object/container.rs index 1450c807a22d..0e56aefa9e28 100644 --- a/core/src/display_object/container.rs +++ b/core/src/display_object/container.rs @@ -136,7 +136,7 @@ pub trait TDisplayObjectContainer<'gc>: /// Get mutable access to the raw container. fn raw_container_mut(&self, gc_context: &Mutation<'gc>) -> RefMut<'_, ChildContainer<'gc>>; - /// Get a child display object by it's position in the render list. + /// Get a child display object by its position in the render list. /// /// The `index` provided here should not be confused with the `Depth`s used /// to index the depth list. @@ -144,7 +144,7 @@ pub trait TDisplayObjectContainer<'gc>: self.raw_container().get_id(index) } - /// Get a child display object by it's position in the depth list. + /// Get a child display object by its position in the depth list. /// /// The `Depth` provided here should not be confused with the `index`s used /// to index the render list. @@ -152,7 +152,7 @@ pub trait TDisplayObjectContainer<'gc>: self.raw_container().get_depth(depth) } - /// Get a child display object by it's instance/timeline name. + /// Get a child display object by its instance/timeline name. /// /// The `case_sensitive` parameter determines if we should consider /// children with different capitalizations as being distinct names. @@ -477,16 +477,35 @@ pub trait TDisplayObjectContainer<'gc>: RenderIter::from_container(self.into()) } - fn is_tab_children(&self, _context: &mut UpdateContext<'_, 'gc>) -> bool { + fn is_tab_children_avm1(&self, _context: &mut UpdateContext<'_, 'gc>) -> bool { true } + fn is_tab_children(&self, context: &mut UpdateContext<'_, 'gc>) -> bool { + if context.swf.is_action_script_3() { + self.raw_container().tab_children + } else { + self.is_tab_children_avm1(context) + } + } + + fn set_tab_children(&self, context: &mut UpdateContext<'_, 'gc>, value: bool) { + if context.swf.is_action_script_3() { + self.raw_container_mut(context.gc()).tab_children = value; + } else { + tracing::warn!("Trying to set tab_children on an AVM1 object, this has no effect") + } + } + fn fill_tab_order( &self, tab_order: &mut Vec>, context: &mut UpdateContext<'_, 'gc>, ) { if !self.is_tab_children(context) { + // AS3 docs say that objects with custom ordering (tabIndex set) + // are included even when tabChildren is false. + // Do not be fooled for that is untrue! return; } @@ -630,6 +649,9 @@ pub struct ChildContainer<'gc> { /// The movie this ChildContainer belongs to. movie: Arc, + + /// Specifies whether children are present in the tab ordering. + tab_children: bool, } impl<'gc> ChildContainer<'gc> { @@ -640,6 +662,7 @@ impl<'gc> ChildContainer<'gc> { has_pending_removals: false, mouse_children: true, movie, + tab_children: true, } } diff --git a/core/src/display_object/edit_text.rs b/core/src/display_object/edit_text.rs index dcb378f6f6f7..3086dfb86260 100644 --- a/core/src/display_object/edit_text.rs +++ b/core/src/display_object/edit_text.rs @@ -180,11 +180,6 @@ pub struct EditTextData<'gc> { /// Restrict what characters the user may input. #[collect(require_static)] restrict: EditTextRestrict, - - // TODO Consider moving this to InteractiveObject along with - // MovieClip's and Button's tab indices after AVM2 analysis - // NOTE: `tabIndex` is u32 in TextField, compared to i32 in Button and MovieClip - tab_index: Option, } impl<'gc> EditTextData<'gc> { @@ -367,7 +362,6 @@ impl<'gc> EditText<'gc> { mouse_wheel_enabled: true, is_tlf: false, restrict: EditTextRestrict::allow_all(), - tab_index: None, }, )); @@ -2034,18 +2028,6 @@ impl<'gc> EditText<'gc> { .contains(Position::from((position.x, position.y))) }) } - - /// Get the value of `tabIndex` used in AS. - /// - /// Do not confuse it with `tab_index`, which returns the value used for ordering. - pub fn tab_index_value(&self) -> Option { - self.0.read().tab_index - } - - /// Set the value of `tabIndex` used in AS. - pub fn set_tab_index_value(&self, context: &mut UpdateContext<'_, 'gc>, value: Option) { - self.0.write(context.gc()).tab_index = value; - } } impl<'gc> TDisplayObject<'gc> for EditText<'gc> { @@ -2498,11 +2480,15 @@ impl<'gc> TInteractiveObject<'gc> for EditText<'gc> { // Non-editable text fields are never tabbable. return false; } + self.tab_enabled(context) + } + + fn tab_enabled_avm1(&self, context: &mut UpdateContext<'_, 'gc>) -> bool { self.get_avm1_boolean_property(context, "tabEnabled", |_| true) } - fn tab_index(&self) -> Option { - self.0.read().tab_index.map(|i| i as i64) + fn tab_enabled_avm2_default(&self, _context: &mut UpdateContext<'_, 'gc>) -> bool { + self.is_editable() } } diff --git a/core/src/display_object/interactive.rs b/core/src/display_object/interactive.rs index c0a2b6361a0b..20a673952f54 100644 --- a/core/src/display_object/interactive.rs +++ b/core/src/display_object/interactive.rs @@ -94,6 +94,12 @@ pub struct InteractiveObjectBase<'gc> { #[collect(require_static)] last_click: Option, + #[collect(require_static)] + tab_enabled: Option, + + #[collect(require_static)] + tab_index: Option, + /// Specifies whether this object displays a yellow rectangle when focused. focus_rect: Option, } @@ -105,6 +111,8 @@ impl<'gc> Default for InteractiveObjectBase<'gc> { flags: InteractiveObjectFlags::MOUSE_ENABLED, context_menu: Avm2Value::Null, last_click: None, + tab_enabled: None, + tab_index: None, focus_rect: None, } } @@ -593,15 +601,52 @@ pub trait TInteractiveObject<'gc>: } /// Whether this object is included in tab ordering. - fn is_tabbable(&self, _context: &mut UpdateContext<'_, 'gc>) -> bool { + fn is_tabbable(&self, context: &mut UpdateContext<'_, 'gc>) -> bool { + self.tab_enabled(context) + } + + /// Sets whether tab ordering is enabled for this object. + /// + /// Some objects may be excluded from tab ordering + /// even if it's enabled, see [`Self::is_tabbable()`]. + fn tab_enabled(&self, context: &mut UpdateContext<'_, 'gc>) -> bool { + if context.swf.is_action_script_3() { + self.raw_interactive() + .tab_enabled + .unwrap_or_else(|| self.tab_enabled_avm2_default(context)) + } else { + self.tab_enabled_avm1(context) + } + } + + /// Look up the `tabEnabled` property from AVM1. + /// + /// Do not use this directly, use [`Self::is_tabbable()`] or [`Self::tab_enabled()`]. + fn tab_enabled_avm1(&self, _context: &mut UpdateContext<'_, 'gc>) -> bool { + false + } + + fn tab_enabled_avm2_default(&self, _context: &mut UpdateContext<'_, 'gc>) -> bool { false } + fn set_tab_enabled(&self, context: &mut UpdateContext<'_, 'gc>, value: bool) { + if context.swf.is_action_script_3() { + self.raw_interactive_mut(context.gc()).tab_enabled = Some(value) + } else { + tracing::warn!("Trying to set tab_enabled on an AVM1 object, this has no effect") + } + } + /// Used to customize tab ordering. /// When not `None`, a custom ordering is used, and /// objects are ordered according to this value. - fn tab_index(&self) -> Option { - None + fn tab_index(&self) -> Option { + self.raw_interactive().tab_index + } + + fn set_tab_index(&self, context: &mut UpdateContext<'_, 'gc>, value: Option) { + self.raw_interactive_mut(context.gc()).tab_index = value } } diff --git a/core/src/display_object/movie_clip.rs b/core/src/display_object/movie_clip.rs index c4fb23d9611a..2462863720d9 100644 --- a/core/src/display_object/movie_clip.rs +++ b/core/src/display_object/movie_clip.rs @@ -189,10 +189,6 @@ pub struct MovieClipData<'gc> { /// Attached audio (AVM1) attached_audio: Option>, - - // TODO Consider moving this to InteractiveObject along with - // TextField's and Button's tab indices after AVM2 analysis - tab_index: Option, } impl<'gc> MovieClip<'gc> { @@ -230,7 +226,6 @@ impl<'gc> MovieClip<'gc> { tag_frame_boundaries: Default::default(), queued_tags: HashMap::new(), attached_audio: None, - tab_index: None, }, )) } @@ -274,7 +269,6 @@ impl<'gc> MovieClip<'gc> { tag_frame_boundaries: Default::default(), queued_tags: HashMap::new(), attached_audio: None, - tab_index: None, }, )) } @@ -319,7 +313,6 @@ impl<'gc> MovieClip<'gc> { tag_frame_boundaries: Default::default(), queued_tags: HashMap::new(), attached_audio: None, - tab_index: None, }, )) } @@ -389,7 +382,6 @@ impl<'gc> MovieClip<'gc> { tag_frame_boundaries: Default::default(), queued_tags: HashMap::new(), attached_audio: None, - tab_index: None, }, )); @@ -2562,18 +2554,6 @@ impl<'gc> MovieClip<'gc> { } } } - - /// Get the value of `tabIndex` used in AS. - /// - /// Do not confuse it with `tab_index`, which returns the value used for ordering. - pub fn tab_index_value(&self) -> Option { - self.0.read().tab_index - } - - /// Set the value of `tabIndex` used in AS. - pub fn set_tab_index_value(&self, context: &mut UpdateContext<'_, 'gc>, value: Option) { - self.0.write(context.gc()).tab_index = value; - } } impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> { @@ -3027,7 +3007,7 @@ impl<'gc> TDisplayObjectContainer<'gc> for MovieClip<'gc> { /// _NOTE:_ /// According to the AS2 documentation, it should affect only automatic tab ordering. /// However, that does not seem to be the case, as it also affects custom ordering. - fn is_tab_children(&self, context: &mut UpdateContext<'_, 'gc>) -> bool { + fn is_tab_children_avm1(&self, context: &mut UpdateContext<'_, 'gc>) -> bool { self.get_avm1_boolean_property(context, "tabChildren", |_| true) } } @@ -3416,14 +3396,14 @@ impl<'gc> TInteractiveObject<'gc> for MovieClip<'gc> { self.call_focus_handler(context, focused, other); } - fn is_tabbable(&self, context: &mut UpdateContext<'_, 'gc>) -> bool { + fn tab_enabled_avm1(&self, context: &mut UpdateContext<'_, 'gc>) -> bool { self.get_avm1_boolean_property(context, "tabEnabled", |context| { self.tab_index().is_some() || self.is_button_mode(context) }) } - fn tab_index(&self) -> Option { - self.0.read().tab_index.map(|i| i as i64) + fn tab_enabled_avm2_default(&self, context: &mut UpdateContext<'_, 'gc>) -> bool { + self.is_button_mode(context) } } diff --git a/tests/tests/swfs/avm1/tab_ordering_custom_i32_vs_u32/input.json b/tests/tests/swfs/avm1/tab_ordering_custom_i32_vs_u32/input.json new file mode 100644 index 000000000000..581d6063cd89 --- /dev/null +++ b/tests/tests/swfs/avm1/tab_ordering_custom_i32_vs_u32/input.json @@ -0,0 +1,7 @@ +[ + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 } +] diff --git a/tests/tests/swfs/avm1/tab_ordering_custom_i32_vs_u32/output.txt b/tests/tests/swfs/avm1/tab_ordering_custom_i32_vs_u32/output.txt new file mode 100644 index 000000000000..42fd5201413a --- /dev/null +++ b/tests/tests/swfs/avm1/tab_ordering_custom_i32_vs_u32/output.txt @@ -0,0 +1,12 @@ +Focus changed + old: null + new: _level0.text +Focus changed + old: _level0.text + new: _level0.text2 +Focus changed + old: _level0.text2 + new: _level0.button +Focus changed + old: _level0.button + new: _level0.text diff --git a/tests/tests/swfs/avm1/tab_ordering_custom_i32_vs_u32/test.as b/tests/tests/swfs/avm1/tab_ordering_custom_i32_vs_u32/test.as new file mode 100644 index 000000000000..6ffe1bf2274f --- /dev/null +++ b/tests/tests/swfs/avm1/tab_ordering_custom_i32_vs_u32/test.as @@ -0,0 +1,18 @@ +var counter = 0; +var listener = new Object(); +listener.onSetFocus = function(oldFocus, newFocus) { + ++counter; + if (counter > 4) { + return; + } + if (newFocus) { + trace("Focus changed"); + trace(" old: " + oldFocus); + trace(" new: " + newFocus); + } +}; +Selection.addListener(listener); + +text.tabIndex = 4294967293; +text2.tabIndex = -2; +button.tabIndex = 0; diff --git a/tests/tests/swfs/avm1/tab_ordering_custom_i32_vs_u32/test.swf b/tests/tests/swfs/avm1/tab_ordering_custom_i32_vs_u32/test.swf new file mode 100644 index 000000000000..ebc7b4aeb6f0 Binary files /dev/null and b/tests/tests/swfs/avm1/tab_ordering_custom_i32_vs_u32/test.swf differ diff --git a/tests/tests/swfs/avm1/tab_ordering_custom_i32_vs_u32/test.toml b/tests/tests/swfs/avm1/tab_ordering_custom_i32_vs_u32/test.toml new file mode 100644 index 000000000000..cf6123969a1d --- /dev/null +++ b/tests/tests/swfs/avm1/tab_ordering_custom_i32_vs_u32/test.toml @@ -0,0 +1 @@ +num_ticks = 1 diff --git a/tests/tests/swfs/avm1/tab_ordering_properties/output.txt b/tests/tests/swfs/avm1/tab_ordering_properties/output.txt index fad8532031ac..dc7ba2c50f5f 100644 --- a/tests/tests/swfs/avm1/tab_ordering_properties/output.txt +++ b/tests/tests/swfs/avm1/tab_ordering_properties/output.txt @@ -74,6 +74,82 @@ enumerated tabEnabled enumerated tabIndex enumerated tabChildren +===== non-editable text ===== + default + tabEnabled = undefined + tabIndex = undefined + tabChildren = undefined + enumerated tabIndex + after set 1 + tabEnabled = true + tabIndex = 0 + tabChildren = true + enumerated tabEnabled + enumerated tabIndex + enumerated tabChildren + after set 2 + tabEnabled = false + tabIndex = 4 + tabChildren = false + enumerated tabEnabled + enumerated tabIndex + enumerated tabChildren + after set 3 + tabEnabled = undefined + tabIndex = undefined + tabChildren = undefined + enumerated tabEnabled + enumerated tabIndex + enumerated tabChildren + after set 4 + tabEnabled = -4 + tabIndex = 4294967292 + tabChildren = -4 + enumerated tabEnabled + enumerated tabIndex + enumerated tabChildren + after set 5 + tabEnabled = 2147483647 + tabIndex = 2147483647 + tabChildren = 2147483647 + enumerated tabEnabled + enumerated tabIndex + enumerated tabChildren + after set 6 + tabEnabled = 2147483648 + tabIndex = 2147483648 + tabChildren = 2147483648 + enumerated tabEnabled + enumerated tabIndex + enumerated tabChildren + after set 7 + tabEnabled = x + tabIndex = 0 + tabChildren = x + enumerated tabEnabled + enumerated tabIndex + enumerated tabChildren + after set 8 + tabEnabled = -2147483648 + tabIndex = 2147483648 + tabChildren = -2147483648 + enumerated tabEnabled + enumerated tabIndex + enumerated tabChildren + after set 9 + tabEnabled = [object Object] + tabIndex = 0 + tabChildren = [object Object] + enumerated tabEnabled + enumerated tabIndex + enumerated tabChildren + after set 10 + tabEnabled = 1.1 + tabIndex = 1 + tabChildren = 1.1 + enumerated tabEnabled + enumerated tabIndex + enumerated tabChildren ===== button ===== default tabEnabled = undefined diff --git a/tests/tests/swfs/avm1/tab_ordering_properties/test.as b/tests/tests/swfs/avm1/tab_ordering_properties/test.as index c5cc27f57cd3..99fb7bc6df67 100644 --- a/tests/tests/swfs/avm1/tab_ordering_properties/test.as +++ b/tests/tests/swfs/avm1/tab_ordering_properties/test.as @@ -96,6 +96,9 @@ function testProperties(obj) { trace('===== text ====='); testProperties(text); +trace('===== non-editable text ====='); +text2.type = "dynamic"; +testProperties(text2); trace('===== button ====='); testProperties(button); trace('===== movie clip ====='); diff --git a/tests/tests/swfs/avm1/tab_ordering_properties/test.swf b/tests/tests/swfs/avm1/tab_ordering_properties/test.swf index 0ca6be93745f..577a71be1c24 100644 Binary files a/tests/tests/swfs/avm1/tab_ordering_properties/test.swf and b/tests/tests/swfs/avm1/tab_ordering_properties/test.swf differ diff --git a/tests/tests/swfs/avm1/tab_ordering_tabbable/input.json b/tests/tests/swfs/avm1/tab_ordering_tabbable/input.json index 15b865ca2e94..30955fa002ee 100644 --- a/tests/tests/swfs/avm1/tab_ordering_tabbable/input.json +++ b/tests/tests/swfs/avm1/tab_ordering_tabbable/input.json @@ -11,6 +11,8 @@ { "type": "KeyDown", "key_code": 9 }, { "type": "KeyDown", "key_code": 9 }, { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, { "type": "KeyDown", "key_code": 27 }, { "type": "KeyDown", "key_code": 9 }, { "type": "KeyDown", "key_code": 9 }, @@ -24,6 +26,8 @@ { "type": "KeyDown", "key_code": 9 }, { "type": "KeyDown", "key_code": 9 }, { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, { "type": "KeyDown", "key_code": 27 }, { "type": "KeyDown", "key_code": 9 }, { "type": "KeyDown", "key_code": 9 }, @@ -37,5 +41,7 @@ { "type": "KeyDown", "key_code": 9 }, { "type": "KeyDown", "key_code": 9 }, { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, { "type": "KeyDown", "key_code": 27 } ] diff --git a/tests/tests/swfs/avm1/tab_ordering_tabbable/output.txt b/tests/tests/swfs/avm1/tab_ordering_tabbable/output.txt index 339952d7d10f..5204c5e91cfa 100644 --- a/tests/tests/swfs/avm1/tab_ordering_tabbable/output.txt +++ b/tests/tests/swfs/avm1/tab_ordering_tabbable/output.txt @@ -1,4 +1,5 @@ Tabbable elements: + _level0.text12: false _level0.button11: false _level0.button10: true _level0.clip9.text: false @@ -14,6 +15,7 @@ Tabbable elements: _level0.text1: false Enabling tab Tabbable elements: + _level0.text12: false _level0.button11: false _level0.button10: true _level0.clip9.text: false @@ -29,6 +31,7 @@ Tabbable elements: _level0.text1: false Setting custom order Tabbable elements: + _level0.text12: false _level0.button11: false _level0.button10: true _level0.clip9.text: false diff --git a/tests/tests/swfs/avm1/tab_ordering_tabbable/test.as b/tests/tests/swfs/avm1/tab_ordering_tabbable/test.as index c4fda1ed7e18..0c16eb74c477 100644 --- a/tests/tests/swfs/avm1/tab_ordering_tabbable/test.as +++ b/tests/tests/swfs/avm1/tab_ordering_tabbable/test.as @@ -12,6 +12,8 @@ text3._visible = false; text6.selectable = false; clip9._visible = false; button11._visible = false; +text12.type = "dynamic"; +text12.tabEnabled = true; var objects = [ text1, @@ -26,7 +28,8 @@ var objects = [ clip9, clip9.text, button10, - button11 + button11, + text12 ]; var tabbedObjects = []; diff --git a/tests/tests/swfs/avm1/tab_ordering_tabbable/test.swf b/tests/tests/swfs/avm1/tab_ordering_tabbable/test.swf index 9248c4afdcf2..3675eb3edb72 100644 Binary files a/tests/tests/swfs/avm1/tab_ordering_tabbable/test.swf and b/tests/tests/swfs/avm1/tab_ordering_tabbable/test.swf differ diff --git a/tests/tests/swfs/avm2/tab_ordering_automatic_basic/Test.as b/tests/tests/swfs/avm2/tab_ordering_automatic_basic/Test.as new file mode 100644 index 000000000000..200292577f7e --- /dev/null +++ b/tests/tests/swfs/avm2/tab_ordering_automatic_basic/Test.as @@ -0,0 +1,79 @@ +package { + +import flash.display.DisplayObject; +import flash.display.InteractiveObject; +import flash.events.KeyboardEvent; +import flash.text.TextField; +import flash.display.Sprite; +import flash.display.SimpleButton; +import flash.display.MovieClip; +import flash.events.Event; +import flash.events.FocusEvent; + +public class Test extends MovieClip { + var text1:TextField; + var text2:TextField; + var text3:TextField; + var text4:TextField; + var testStage:int = 0; + + public function Test() { + super(); + + text1 = this.newTextField(1); + text2 = this.newTextField(2); + text3 = this.newTextField(3); + text4 = this.newTextField(4); + + this.stage.focus = text1; + + var test:Test = this; + for each (var obj in [text1, text2, text3, text4]) { + obj.addEventListener("focusIn", function (evt:FocusEvent):void { + trace("Focus changed: " + evt.relatedObject.name + " -> " + evt.target.name); + }); + this.stage.addChild(obj); + } + + this.stage.addEventListener("keyDown", function(evt:KeyboardEvent) { + if (evt.keyCode == 27) { + test.testStage += 1; + trace("Escape pressed, moving to stage " + test.testStage); + test.setUpTestStage(); + } else if (evt.keyCode == 9) { + trace("Tab pressed"); + } + }); + } + + function setUpTestStage() { + if (this.testStage == 0) { + // already set up + } + if (this.testStage == 1) { + this.stage.focus = text4; + } + if (this.testStage == 2) { + this.stage.focus = text1; + text2.tabEnabled = false; + } + if (this.testStage == 3) { + this.stage.focus = text1; + text1.tabEnabled = false; + text2.tabEnabled = true; + } + } + + function newTextField(i:int):TextField { + var tf:TextField = new TextField(); + tf.type = "input"; + tf.name = "text" + i; + tf.border = true; + tf.x = 0; + tf.y = i * 20; + tf.height = 20; + tf.width = 100; + return tf; + } +} +} diff --git a/tests/tests/swfs/avm2/tab_ordering_automatic_basic/input.json b/tests/tests/swfs/avm2/tab_ordering_automatic_basic/input.json new file mode 100644 index 000000000000..5c9b519f883a --- /dev/null +++ b/tests/tests/swfs/avm2/tab_ordering_automatic_basic/input.json @@ -0,0 +1,25 @@ +[ + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 27 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 27 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 27 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 } +] diff --git a/tests/tests/swfs/avm2/tab_ordering_automatic_basic/output.txt b/tests/tests/swfs/avm2/tab_ordering_automatic_basic/output.txt new file mode 100644 index 000000000000..cc4882d844a9 --- /dev/null +++ b/tests/tests/swfs/avm2/tab_ordering_automatic_basic/output.txt @@ -0,0 +1,45 @@ +Tab pressed +Focus changed: text1 -> text2 +Tab pressed +Focus changed: text2 -> text3 +Tab pressed +Focus changed: text3 -> text4 +Tab pressed +Focus changed: text4 -> text1 +Tab pressed +Focus changed: text1 -> text2 +Escape pressed, moving to stage 1 +Focus changed: text2 -> text4 +Tab pressed +Focus changed: text4 -> text1 +Tab pressed +Focus changed: text1 -> text2 +Tab pressed +Focus changed: text2 -> text3 +Tab pressed +Focus changed: text3 -> text4 +Tab pressed +Focus changed: text4 -> text1 +Escape pressed, moving to stage 2 +Tab pressed +Focus changed: text1 -> text3 +Tab pressed +Focus changed: text3 -> text4 +Tab pressed +Focus changed: text4 -> text1 +Tab pressed +Focus changed: text1 -> text3 +Tab pressed +Focus changed: text3 -> text4 +Escape pressed, moving to stage 3 +Focus changed: text4 -> text1 +Tab pressed +Focus changed: text1 -> text2 +Tab pressed +Focus changed: text2 -> text3 +Tab pressed +Focus changed: text3 -> text4 +Tab pressed +Focus changed: text4 -> text2 +Tab pressed +Focus changed: text2 -> text3 diff --git a/tests/tests/swfs/avm2/tab_ordering_automatic_basic/test.swf b/tests/tests/swfs/avm2/tab_ordering_automatic_basic/test.swf new file mode 100644 index 000000000000..7b666fcc1146 Binary files /dev/null and b/tests/tests/swfs/avm2/tab_ordering_automatic_basic/test.swf differ diff --git a/tests/tests/swfs/avm2/tab_ordering_automatic_basic/test.toml b/tests/tests/swfs/avm2/tab_ordering_automatic_basic/test.toml new file mode 100644 index 000000000000..cf6123969a1d --- /dev/null +++ b/tests/tests/swfs/avm2/tab_ordering_automatic_basic/test.toml @@ -0,0 +1 @@ +num_ticks = 1 diff --git a/tests/tests/swfs/avm2/tab_ordering_children/Test.as b/tests/tests/swfs/avm2/tab_ordering_children/Test.as new file mode 100644 index 000000000000..9de1e0c8869a --- /dev/null +++ b/tests/tests/swfs/avm2/tab_ordering_children/Test.as @@ -0,0 +1,157 @@ +package { + +import flash.display.DisplayObject; +import flash.display.InteractiveObject; +import flash.display.Sprite; +import flash.events.KeyboardEvent; +import flash.text.TextField; +import flash.display.Sprite; +import flash.display.SimpleButton; +import flash.display.MovieClip; +import flash.events.Event; +import flash.events.FocusEvent; + +public class Test extends MovieClip { + var text1:TextField; + var text2:TextField; + var clipOuter:Sprite; + var text3:TextField; + var text4:TextField; + var clipInner:Sprite; + var text5:TextField; + var text6:TextField; + + var testStage:int = 0; + + public function Test() { + super(); + + this.text1 = this.newTextField(0); + this.text1.name = "text1"; + this.text2 = this.newTextField(1); + this.text2.name = "text2"; + this.text3 = this.newTextField(0); + this.text3.name = "text3"; + this.text4 = this.newTextField(1); + this.text4.name = "text4"; + this.text5 = this.newTextField(0); + this.text5.name = "text5"; + this.text6 = this.newTextField(1); + this.text6.name = "text6"; + + this.clipInner = this.newMovieClip(2); + this.clipInner.name = "clipInner"; + this.clipInner.addChild(this.text5); + this.clipInner.addChild(this.text6); + this.clipInner.width = 100; + this.clipInner.height = 40; + this.clipInner.y = 40; + + this.clipOuter = this.newMovieClip(2); + this.clipOuter.name = "clipOuter"; + this.clipOuter.addChild(this.text3); + this.clipOuter.addChild(this.text4); + this.clipOuter.addChild(this.clipInner); + this.clipOuter.width = 100; + this.clipOuter.height = 80; + this.clipOuter.y = 40; + + this.stage.addChild(this.text1); + this.stage.addChild(this.text2); + this.stage.addChild(this.clipOuter); + + var test:Test = this; + this.stage.addEventListener("keyDown", function(evt:KeyboardEvent) { + if (evt.keyCode == 27) { + ++test.testStage; + trace("===== Escape pressed, moving to stage " + test.testStage); + test.setUpTestStage(); + } else if (evt.keyCode == 9) { + trace("Tab pressed"); + } + }); + + this.stage.focus = this.text1; + } + + function newTextField(i:int):TextField { + var tf:TextField = new TextField(); + tf.type = "input"; + tf.border = true; + tf.addEventListener("focusIn", function(obj) { + return function (evt: FocusEvent): void { + if (evt.relatedObject != null && evt.target != null) { + trace("Focus changed at " + obj.name + ": " + evt.relatedObject.name + " -> " + evt.target.name); + } + }; + }(tf)); + this.setupObject(tf, i); + return tf; + } + + function newMovieClip(i:int):Sprite { + var mc:Sprite = new Sprite(); + mc.addEventListener("focusIn", function(obj) { + return function (evt:FocusEvent):void { + if (evt.relatedObject != null && evt.target != null) { + trace("Focus changed at " + obj.name + ": " + evt.relatedObject.name + " -> " + evt.target.name); + } + }; + }(mc)); + mc.height = 40; + return mc; + } + + function setupObject(o:DisplayObject, i:int):void { + o.x = 0; + o.y = i * 20; + o.height = 20; + o.width = 100; + } + + function setUpTestStage():void { + if (this.testStage == 0) { + // already set up + } + if (this.testStage == 1) { + this.clipOuter.tabChildren = true; + this.clipInner.tabChildren = true; + } + if (this.testStage == 2) { + this.clipOuter.tabChildren = false; + this.clipInner.tabChildren = true; + } + if (this.testStage == 3) { + this.clipOuter.tabChildren = true; + this.clipInner.tabChildren = false; + } + if (this.testStage == 4) { + this.clipOuter.tabChildren = false; + this.clipOuter.tabEnabled = false; + this.clipInner.tabChildren = true; + } + if (this.testStage == 5) { + this.clipOuter.tabChildren = false; + this.clipOuter.tabEnabled = true; + this.clipInner.tabChildren = true; + } + if (this.testStage == 6) { + this.clipOuter.tabChildren = false; + this.clipOuter.tabEnabled = undefined; + this.clipInner.tabChildren = true; + + this.text1.tabIndex = 3; + this.text3.tabIndex = 1; + this.text5.tabIndex = 2; + } + if (this.testStage == 7) { + this.clipOuter.tabChildren = true; + this.clipInner.tabChildren = false; + + this.text1.tabIndex = 3; + this.text3.tabIndex = 1; + this.text5.tabIndex = 2; + } + } +} +} diff --git a/tests/tests/swfs/avm2/tab_ordering_children/input.json b/tests/tests/swfs/avm2/tab_ordering_children/input.json new file mode 100644 index 000000000000..5d544fa72781 --- /dev/null +++ b/tests/tests/swfs/avm2/tab_ordering_children/input.json @@ -0,0 +1,57 @@ +[ + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 27 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 27 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 27 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 27 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 27 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 27 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 27 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 } +] diff --git a/tests/tests/swfs/avm2/tab_ordering_children/output.txt b/tests/tests/swfs/avm2/tab_ordering_children/output.txt new file mode 100644 index 000000000000..36a3528f4a06 --- /dev/null +++ b/tests/tests/swfs/avm2/tab_ordering_children/output.txt @@ -0,0 +1,116 @@ +Tab pressed +Focus changed at text2: text1 -> text2 +Tab pressed +Focus changed at text3: text2 -> text3 +Focus changed at clipOuter: text2 -> text3 +Tab pressed +Focus changed at text4: text3 -> text4 +Focus changed at clipOuter: text3 -> text4 +Tab pressed +Focus changed at text5: text4 -> text5 +Focus changed at clipInner: text4 -> text5 +Focus changed at clipOuter: text4 -> text5 +Tab pressed +Focus changed at text6: text5 -> text6 +Focus changed at clipInner: text5 -> text6 +Focus changed at clipOuter: text5 -> text6 +Tab pressed +Focus changed at text1: text6 -> text1 +===== Escape pressed, moving to stage 1 +Tab pressed +Focus changed at text2: text1 -> text2 +Tab pressed +Focus changed at text3: text2 -> text3 +Focus changed at clipOuter: text2 -> text3 +Tab pressed +Focus changed at text4: text3 -> text4 +Focus changed at clipOuter: text3 -> text4 +Tab pressed +Focus changed at text5: text4 -> text5 +Focus changed at clipInner: text4 -> text5 +Focus changed at clipOuter: text4 -> text5 +Tab pressed +Focus changed at text6: text5 -> text6 +Focus changed at clipInner: text5 -> text6 +Focus changed at clipOuter: text5 -> text6 +Tab pressed +Focus changed at text1: text6 -> text1 +===== Escape pressed, moving to stage 2 +Tab pressed +Focus changed at text2: text1 -> text2 +Tab pressed +Focus changed at text1: text2 -> text1 +Tab pressed +Focus changed at text2: text1 -> text2 +Tab pressed +Focus changed at text1: text2 -> text1 +Tab pressed +Focus changed at text2: text1 -> text2 +Tab pressed +Focus changed at text1: text2 -> text1 +===== Escape pressed, moving to stage 3 +Tab pressed +Focus changed at text2: text1 -> text2 +Tab pressed +Focus changed at text3: text2 -> text3 +Focus changed at clipOuter: text2 -> text3 +Tab pressed +Focus changed at text4: text3 -> text4 +Focus changed at clipOuter: text3 -> text4 +Tab pressed +Focus changed at text1: text4 -> text1 +Tab pressed +Focus changed at text2: text1 -> text2 +Tab pressed +Focus changed at text3: text2 -> text3 +Focus changed at clipOuter: text2 -> text3 +===== Escape pressed, moving to stage 4 +Tab pressed +Focus changed at text1: text3 -> text1 +Tab pressed +Focus changed at text2: text1 -> text2 +Tab pressed +Focus changed at text1: text2 -> text1 +Tab pressed +Focus changed at text2: text1 -> text2 +Tab pressed +Focus changed at text1: text2 -> text1 +Tab pressed +Focus changed at text2: text1 -> text2 +===== Escape pressed, moving to stage 5 +Tab pressed +Focus changed at clipOuter: text2 -> clipOuter +Tab pressed +Focus changed at text1: clipOuter -> text1 +Tab pressed +Focus changed at text2: text1 -> text2 +Tab pressed +Focus changed at clipOuter: text2 -> clipOuter +Tab pressed +Focus changed at text1: clipOuter -> text1 +Tab pressed +Focus changed at text2: text1 -> text2 +===== Escape pressed, moving to stage 6 +Tab pressed +Focus changed at text1: text2 -> text1 +Tab pressed +Tab pressed +Tab pressed +Tab pressed +Tab pressed +===== Escape pressed, moving to stage 7 +Tab pressed +Focus changed at text3: text1 -> text3 +Focus changed at clipOuter: text1 -> text3 +Tab pressed +Focus changed at text1: text3 -> text1 +Tab pressed +Focus changed at text3: text1 -> text3 +Focus changed at clipOuter: text1 -> text3 +Tab pressed +Focus changed at text1: text3 -> text1 +Tab pressed +Focus changed at text3: text1 -> text3 +Focus changed at clipOuter: text1 -> text3 +Tab pressed +Focus changed at text1: text3 -> text1 diff --git a/tests/tests/swfs/avm2/tab_ordering_children/test.swf b/tests/tests/swfs/avm2/tab_ordering_children/test.swf new file mode 100644 index 000000000000..4319d5b2753a Binary files /dev/null and b/tests/tests/swfs/avm2/tab_ordering_children/test.swf differ diff --git a/tests/tests/swfs/avm2/tab_ordering_children/test.toml b/tests/tests/swfs/avm2/tab_ordering_children/test.toml new file mode 100644 index 000000000000..cf6123969a1d --- /dev/null +++ b/tests/tests/swfs/avm2/tab_ordering_children/test.toml @@ -0,0 +1 @@ +num_ticks = 1 diff --git a/tests/tests/swfs/avm2/tab_ordering_custom_basic/Test.as b/tests/tests/swfs/avm2/tab_ordering_custom_basic/Test.as new file mode 100644 index 000000000000..0d301750de71 --- /dev/null +++ b/tests/tests/swfs/avm2/tab_ordering_custom_basic/Test.as @@ -0,0 +1,70 @@ +package { + +import flash.display.DisplayObject; +import flash.display.InteractiveObject; +import flash.events.KeyboardEvent; +import flash.text.TextField; +import flash.display.Sprite; +import flash.display.SimpleButton; +import flash.display.MovieClip; +import flash.events.Event; +import flash.events.FocusEvent; + +public class Test extends MovieClip { + var text1:TextField; + var text2:TextField; + var text3:TextField; + var text4:TextField; + var text5:TextField; + var text6:TextField; + + public function Test() { + super(); + + text1 = this.newTextField(1); + text2 = this.newTextField(2); + text3 = this.newTextField(3); + text4 = this.newTextField(4); + text5 = this.newTextField(5); + text6 = this.newTextField(6); + + text2.tabIndex = 2; + text3.tabIndex = 1; + text4.tabIndex = 4; + text4.tabEnabled = false; + text5.tabIndex = 3; + text6.tabIndex = 5; + + this.stage.focus = text1; + + var test:Test = this; + for each (var obj in [text1, text2, text3, text4, text5, text6]) { + obj.addEventListener("focusIn", function (evt:FocusEvent):void { + trace("Focus changed: " + evt.relatedObject.name + " -> " + evt.target.name); + }); + this.stage.addChild(obj); + } + + this.stage.addEventListener("keyDown", function(evt:KeyboardEvent) { + if (evt.keyCode == 27) { + trace("Escape pressed"); + test.stage.focus = test.text5; + } else if (evt.keyCode == 9) { + trace("Tab pressed"); + } + }); + } + + function newTextField(i:int):TextField { + var tf:TextField = new TextField(); + tf.type = "input"; + tf.name = "text" + i; + tf.border = true; + tf.x = 0; + tf.y = i * 20; + tf.height = 20; + tf.width = 100; + return tf; + } +} +} diff --git a/tests/tests/swfs/avm2/tab_ordering_custom_basic/input.json b/tests/tests/swfs/avm2/tab_ordering_custom_basic/input.json new file mode 100644 index 000000000000..7c7d8c3fbc71 --- /dev/null +++ b/tests/tests/swfs/avm2/tab_ordering_custom_basic/input.json @@ -0,0 +1,19 @@ +[ + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 27 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 } +] diff --git a/tests/tests/swfs/avm2/tab_ordering_custom_basic/output.txt b/tests/tests/swfs/avm2/tab_ordering_custom_basic/output.txt new file mode 100644 index 000000000000..e0513b3aa9c1 --- /dev/null +++ b/tests/tests/swfs/avm2/tab_ordering_custom_basic/output.txt @@ -0,0 +1,34 @@ +Tab pressed +Focus changed: text1 -> text3 +Tab pressed +Focus changed: text3 -> text2 +Tab pressed +Focus changed: text2 -> text5 +Tab pressed +Focus changed: text5 -> text6 +Tab pressed +Focus changed: text6 -> text3 +Tab pressed +Focus changed: text3 -> text2 +Tab pressed +Focus changed: text2 -> text5 +Tab pressed +Focus changed: text5 -> text6 +Escape pressed +Focus changed: text6 -> text5 +Tab pressed +Focus changed: text5 -> text6 +Tab pressed +Focus changed: text6 -> text3 +Tab pressed +Focus changed: text3 -> text2 +Tab pressed +Focus changed: text2 -> text5 +Tab pressed +Focus changed: text5 -> text6 +Tab pressed +Focus changed: text6 -> text3 +Tab pressed +Focus changed: text3 -> text2 +Tab pressed +Focus changed: text2 -> text5 diff --git a/tests/tests/swfs/avm2/tab_ordering_custom_basic/test.swf b/tests/tests/swfs/avm2/tab_ordering_custom_basic/test.swf new file mode 100644 index 000000000000..54dff789563c Binary files /dev/null and b/tests/tests/swfs/avm2/tab_ordering_custom_basic/test.swf differ diff --git a/tests/tests/swfs/avm2/tab_ordering_custom_basic/test.toml b/tests/tests/swfs/avm2/tab_ordering_custom_basic/test.toml new file mode 100644 index 000000000000..cf6123969a1d --- /dev/null +++ b/tests/tests/swfs/avm2/tab_ordering_custom_basic/test.toml @@ -0,0 +1 @@ +num_ticks = 1 diff --git a/tests/tests/swfs/avm2/tab_ordering_properties/Test.as b/tests/tests/swfs/avm2/tab_ordering_properties/Test.as new file mode 100644 index 000000000000..4120b6de227a --- /dev/null +++ b/tests/tests/swfs/avm2/tab_ordering_properties/Test.as @@ -0,0 +1,240 @@ +package { +import flash.display.MovieClip; +import flash.text.TextField; +import flash.display.SimpleButton; +import flash.display.Sprite; +import flash.display.MovieClip; +public class Test extends MovieClip { + public function Test() { + super(); + + var text:TextField = new TextField(); + var text2:TextField = new TextField(); + text2.type = "input"; + var button:SimpleButton = new SimpleButton(); + var mc:MovieClip = new MovieClip(); + var mc2:MovieClip = new MovieClip(); + mc2.buttonMode = true; + var mc3:MovieClip = new MovieClip(); + var sprite:Sprite = new Sprite(); + + trace('===== stage ====='); + this.testProperties(this.stage); + trace('===== text ====='); + this.testProperties(text); + trace('===== text type input ====='); + this.testProperties(text2); + trace('===== button ====='); + this.testProperties(button); + trace('===== movie clip ====='); + this.testProperties(mc); + trace('===== movie clip button mode true ====='); + this.testProperties(mc2); + trace('===== movie clip with index ====='); + mc3.tabIndex = 4; + this.testProperties(mc3); + trace('===== sprite ====='); + this.testProperties(sprite); + } + + function logError(f:*):void { + try { + f(); + } catch (error:Error) { + trace(' Error: ' + error); + } + } + + function printProperties(obj:*):void { + this.logError(function():void { + trace(' tabEnabled = ' + obj.tabEnabled); + }); + this.logError(function():void { + trace(' tabIndex = ' + obj.tabIndex); + }); + this.logError(function():void { + trace(' tabChildren = ' + obj.tabChildren); + }); + for (var i:String in obj) { + if (i == 'tabEnabled') { + trace(' enumerated tabEnabled'); + } + } + for (i in obj) { + if (i == 'tabIndex') { + trace(' enumerated tabIndex'); + } + } + for (i in obj) { + if (i == 'tabChildren') { + trace(' enumerated tabChildren'); + } + } + } + + function testProperties(obj:*):void { + trace(' default'); + this.printProperties(obj); + + this.logError(function():void { + trace(' set tabEnabled'); + obj.tabEnabled = true; + }); + this.logError(function():void { + trace(' set tabIndex'); + obj.tabIndex = 0; + }); + this.logError(function():void { + trace(' set tabChildren'); + obj.tabChildren = true; + }); + + trace(' after set 1'); + this.printProperties(obj); + + this.logError(function():void { + trace(' set tabEnabled'); + obj.tabEnabled = false; + }); + this.logError(function():void { + trace(' set tabIndex'); + obj.tabIndex = 4; + }); + this.logError(function():void { + trace(' set tabChildren'); + obj.tabChildren = false; + }); + + trace(' after set 2'); + this.printProperties(obj); + + this.logError(function():void { + trace(' set tabEnabled'); + obj.tabEnabled = undefined; + }); + this.logError(function():void { + trace(' set tabIndex'); + obj.tabIndex = undefined; + }); + this.logError(function():void { + trace(' set tabChildren'); + obj.tabChildren = undefined; + }); + + trace(' after set 3'); + this.printProperties(obj); + + this.logError(function():void { + trace(' set tabEnabled'); + obj.tabEnabled = -4; + }); + this.logError(function():void { + trace(' set tabIndex'); + obj.tabIndex = -4; + }); + this.logError(function():void { + trace(' set tabChildren'); + obj.tabChildren = -4; + }); + + trace(' after set 4'); + this.printProperties(obj); + + this.logError(function():void { + trace(' set tabEnabled'); + obj.tabEnabled = 2147483647; + }); + this.logError(function():void { + trace(' set tabIndex'); + obj.tabIndex = 2147483647; + }); + this.logError(function():void { + trace(' set tabChildren'); + obj.tabChildren = 2147483647; + }); + + trace(' after set 5'); + this.printProperties(obj); + + this.logError(function():void { + trace(' set tabEnabled'); + obj.tabEnabled = 2147483648; + }); + this.logError(function():void { + trace(' set tabIndex'); + obj.tabIndex = 2147483648; + }); + this.logError(function():void { + trace(' set tabChildren'); + obj.tabChildren = 2147483648; + }); + + trace(' after set 6'); + this.printProperties(obj); + + this.logError(function():void { + trace(' set tabEnabled'); + obj.tabEnabled = 'x'; + }); + this.logError(function():void { + trace(' set tabIndex'); + obj.tabIndex = 'x'; + }); + this.logError(function():void { + trace(' set tabChildren'); + obj.tabChildren = 'x'; + }); + + trace(' after set 7'); + this.printProperties(obj); + + this.logError(function():void { + trace(' set tabEnabled'); + obj.tabEnabled = -2147483648; + }); + this.logError(function():void { + trace(' set tabIndex'); + obj.tabIndex = -2147483648; + }); + this.logError(function():void { + trace(' set tabChildren'); + obj.tabChildren = -2147483648; + }); + + trace(' after set 8'); + this.printProperties(obj); + + this.logError(function():void { + trace(' set tabEnabled'); + obj.tabEnabled = new Object(); + }); + this.logError(function():void { + trace(' set tabIndex'); + obj.tabIndex = new Object(); + }); + this.logError(function():void { + trace(' set tabChildren'); + obj.tabChildren = new Object(); + }); + + trace(' after set 9'); + this.printProperties(obj); + + this.logError(function():void { + trace(' set tabEnabled'); + obj.tabEnabled = 1.1; + }); + this.logError(function():void { + trace(' set tabIndex'); + obj.tabIndex = 1.1; + }); + this.logError(function():void { + trace(' set tabChildren'); + obj.tabChildren = 1.1; + }); + + trace(' after set 10'); + this.printProperties(obj); + } +} +} diff --git a/tests/tests/swfs/avm2/tab_ordering_properties/output.txt b/tests/tests/swfs/avm2/tab_ordering_properties/output.txt new file mode 100644 index 000000000000..051cb9c32be1 --- /dev/null +++ b/tests/tests/swfs/avm2/tab_ordering_properties/output.txt @@ -0,0 +1,671 @@ +===== stage ===== + default + tabEnabled = false + tabIndex = -1 + tabChildren = true + set tabEnabled + Error: Error: Error #2071: The Stage class does not implement this property or method. + set tabIndex + Error: Error: Error #2071: The Stage class does not implement this property or method. + set tabChildren + after set 1 + tabEnabled = false + tabIndex = -1 + tabChildren = true + set tabEnabled + Error: Error: Error #2071: The Stage class does not implement this property or method. + set tabIndex + Error: Error: Error #2071: The Stage class does not implement this property or method. + set tabChildren + after set 2 + tabEnabled = false + tabIndex = -1 + tabChildren = true + set tabEnabled + Error: Error: Error #2071: The Stage class does not implement this property or method. + set tabIndex + Error: Error: Error #2071: The Stage class does not implement this property or method. + set tabChildren + after set 3 + tabEnabled = false + tabIndex = -1 + tabChildren = true + set tabEnabled + Error: Error: Error #2071: The Stage class does not implement this property or method. + set tabIndex + Error: Error: Error #2071: The Stage class does not implement this property or method. + set tabChildren + after set 4 + tabEnabled = false + tabIndex = -1 + tabChildren = true + set tabEnabled + Error: Error: Error #2071: The Stage class does not implement this property or method. + set tabIndex + Error: Error: Error #2071: The Stage class does not implement this property or method. + set tabChildren + after set 5 + tabEnabled = false + tabIndex = -1 + tabChildren = true + set tabEnabled + Error: Error: Error #2071: The Stage class does not implement this property or method. + set tabIndex + Error: Error: Error #2071: The Stage class does not implement this property or method. + set tabChildren + after set 6 + tabEnabled = false + tabIndex = -1 + tabChildren = true + set tabEnabled + Error: Error: Error #2071: The Stage class does not implement this property or method. + set tabIndex + Error: Error: Error #2071: The Stage class does not implement this property or method. + set tabChildren + after set 7 + tabEnabled = false + tabIndex = -1 + tabChildren = true + set tabEnabled + Error: Error: Error #2071: The Stage class does not implement this property or method. + set tabIndex + Error: Error: Error #2071: The Stage class does not implement this property or method. + set tabChildren + after set 8 + tabEnabled = false + tabIndex = -1 + tabChildren = true + set tabEnabled + Error: Error: Error #2071: The Stage class does not implement this property or method. + set tabIndex + Error: Error: Error #2071: The Stage class does not implement this property or method. + set tabChildren + after set 9 + tabEnabled = false + tabIndex = -1 + tabChildren = true + set tabEnabled + Error: Error: Error #2071: The Stage class does not implement this property or method. + set tabIndex + Error: Error: Error #2071: The Stage class does not implement this property or method. + set tabChildren + after set 10 + tabEnabled = false + tabIndex = -1 + tabChildren = true +===== text ===== + default + tabEnabled = false + tabIndex = -1 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.text.TextField and there is no default value. + set tabEnabled + set tabIndex + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.text.TextField. + after set 1 + tabEnabled = true + tabIndex = 0 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.text.TextField and there is no default value. + set tabEnabled + set tabIndex + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.text.TextField. + after set 2 + tabEnabled = false + tabIndex = 4 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.text.TextField and there is no default value. + set tabEnabled + set tabIndex + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.text.TextField. + after set 3 + tabEnabled = false + tabIndex = 0 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.text.TextField and there is no default value. + set tabEnabled + set tabIndex + Error: RangeError: Error #2027: Parameter tabIndex must be a non-negative number; got -4. + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.text.TextField. + after set 4 + tabEnabled = true + tabIndex = 0 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.text.TextField and there is no default value. + set tabEnabled + set tabIndex + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.text.TextField. + after set 5 + tabEnabled = true + tabIndex = 2147483647 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.text.TextField and there is no default value. + set tabEnabled + set tabIndex + Error: RangeError: Error #2027: Parameter tabIndex must be a non-negative number; got -2147483648. + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.text.TextField. + after set 6 + tabEnabled = true + tabIndex = 2147483647 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.text.TextField and there is no default value. + set tabEnabled + set tabIndex + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.text.TextField. + after set 7 + tabEnabled = true + tabIndex = 0 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.text.TextField and there is no default value. + set tabEnabled + set tabIndex + Error: RangeError: Error #2027: Parameter tabIndex must be a non-negative number; got -2147483648. + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.text.TextField. + after set 8 + tabEnabled = true + tabIndex = 0 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.text.TextField and there is no default value. + set tabEnabled + set tabIndex + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.text.TextField. + after set 9 + tabEnabled = true + tabIndex = 0 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.text.TextField and there is no default value. + set tabEnabled + set tabIndex + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.text.TextField. + after set 10 + tabEnabled = true + tabIndex = 1 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.text.TextField and there is no default value. +===== text type input ===== + default + tabEnabled = true + tabIndex = -1 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.text.TextField and there is no default value. + set tabEnabled + set tabIndex + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.text.TextField. + after set 1 + tabEnabled = true + tabIndex = 0 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.text.TextField and there is no default value. + set tabEnabled + set tabIndex + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.text.TextField. + after set 2 + tabEnabled = false + tabIndex = 4 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.text.TextField and there is no default value. + set tabEnabled + set tabIndex + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.text.TextField. + after set 3 + tabEnabled = false + tabIndex = 0 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.text.TextField and there is no default value. + set tabEnabled + set tabIndex + Error: RangeError: Error #2027: Parameter tabIndex must be a non-negative number; got -4. + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.text.TextField. + after set 4 + tabEnabled = true + tabIndex = 0 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.text.TextField and there is no default value. + set tabEnabled + set tabIndex + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.text.TextField. + after set 5 + tabEnabled = true + tabIndex = 2147483647 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.text.TextField and there is no default value. + set tabEnabled + set tabIndex + Error: RangeError: Error #2027: Parameter tabIndex must be a non-negative number; got -2147483648. + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.text.TextField. + after set 6 + tabEnabled = true + tabIndex = 2147483647 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.text.TextField and there is no default value. + set tabEnabled + set tabIndex + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.text.TextField. + after set 7 + tabEnabled = true + tabIndex = 0 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.text.TextField and there is no default value. + set tabEnabled + set tabIndex + Error: RangeError: Error #2027: Parameter tabIndex must be a non-negative number; got -2147483648. + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.text.TextField. + after set 8 + tabEnabled = true + tabIndex = 0 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.text.TextField and there is no default value. + set tabEnabled + set tabIndex + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.text.TextField. + after set 9 + tabEnabled = true + tabIndex = 0 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.text.TextField and there is no default value. + set tabEnabled + set tabIndex + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.text.TextField. + after set 10 + tabEnabled = true + tabIndex = 1 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.text.TextField and there is no default value. +===== button ===== + default + tabEnabled = true + tabIndex = -1 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.display.SimpleButton and there is no default value. + set tabEnabled + set tabIndex + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.display.SimpleButton. + after set 1 + tabEnabled = true + tabIndex = 0 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.display.SimpleButton and there is no default value. + set tabEnabled + set tabIndex + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.display.SimpleButton. + after set 2 + tabEnabled = false + tabIndex = 4 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.display.SimpleButton and there is no default value. + set tabEnabled + set tabIndex + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.display.SimpleButton. + after set 3 + tabEnabled = false + tabIndex = 0 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.display.SimpleButton and there is no default value. + set tabEnabled + set tabIndex + Error: RangeError: Error #2027: Parameter tabIndex must be a non-negative number; got -4. + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.display.SimpleButton. + after set 4 + tabEnabled = true + tabIndex = 0 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.display.SimpleButton and there is no default value. + set tabEnabled + set tabIndex + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.display.SimpleButton. + after set 5 + tabEnabled = true + tabIndex = 2147483647 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.display.SimpleButton and there is no default value. + set tabEnabled + set tabIndex + Error: RangeError: Error #2027: Parameter tabIndex must be a non-negative number; got -2147483648. + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.display.SimpleButton. + after set 6 + tabEnabled = true + tabIndex = 2147483647 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.display.SimpleButton and there is no default value. + set tabEnabled + set tabIndex + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.display.SimpleButton. + after set 7 + tabEnabled = true + tabIndex = 0 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.display.SimpleButton and there is no default value. + set tabEnabled + set tabIndex + Error: RangeError: Error #2027: Parameter tabIndex must be a non-negative number; got -2147483648. + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.display.SimpleButton. + after set 8 + tabEnabled = true + tabIndex = 0 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.display.SimpleButton and there is no default value. + set tabEnabled + set tabIndex + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.display.SimpleButton. + after set 9 + tabEnabled = true + tabIndex = 0 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.display.SimpleButton and there is no default value. + set tabEnabled + set tabIndex + set tabChildren + Error: ReferenceError: Error #1056: Cannot create property tabChildren on flash.display.SimpleButton. + after set 10 + tabEnabled = true + tabIndex = 1 + Error: ReferenceError: Error #1069: Property tabChildren not found on flash.display.SimpleButton and there is no default value. +===== movie clip ===== + default + tabEnabled = false + tabIndex = -1 + tabChildren = true + set tabEnabled + set tabIndex + set tabChildren + after set 1 + tabEnabled = true + tabIndex = 0 + tabChildren = true + set tabEnabled + set tabIndex + set tabChildren + after set 2 + tabEnabled = false + tabIndex = 4 + tabChildren = false + set tabEnabled + set tabIndex + set tabChildren + after set 3 + tabEnabled = false + tabIndex = 0 + tabChildren = false + set tabEnabled + set tabIndex + Error: RangeError: Error #2027: Parameter tabIndex must be a non-negative number; got -4. + set tabChildren + after set 4 + tabEnabled = true + tabIndex = 0 + tabChildren = true + set tabEnabled + set tabIndex + set tabChildren + after set 5 + tabEnabled = true + tabIndex = 2147483647 + tabChildren = true + set tabEnabled + set tabIndex + Error: RangeError: Error #2027: Parameter tabIndex must be a non-negative number; got -2147483648. + set tabChildren + after set 6 + tabEnabled = true + tabIndex = 2147483647 + tabChildren = true + set tabEnabled + set tabIndex + set tabChildren + after set 7 + tabEnabled = true + tabIndex = 0 + tabChildren = true + set tabEnabled + set tabIndex + Error: RangeError: Error #2027: Parameter tabIndex must be a non-negative number; got -2147483648. + set tabChildren + after set 8 + tabEnabled = true + tabIndex = 0 + tabChildren = true + set tabEnabled + set tabIndex + set tabChildren + after set 9 + tabEnabled = true + tabIndex = 0 + tabChildren = true + set tabEnabled + set tabIndex + set tabChildren + after set 10 + tabEnabled = true + tabIndex = 1 + tabChildren = true +===== movie clip button mode true ===== + default + tabEnabled = true + tabIndex = -1 + tabChildren = true + set tabEnabled + set tabIndex + set tabChildren + after set 1 + tabEnabled = true + tabIndex = 0 + tabChildren = true + set tabEnabled + set tabIndex + set tabChildren + after set 2 + tabEnabled = false + tabIndex = 4 + tabChildren = false + set tabEnabled + set tabIndex + set tabChildren + after set 3 + tabEnabled = false + tabIndex = 0 + tabChildren = false + set tabEnabled + set tabIndex + Error: RangeError: Error #2027: Parameter tabIndex must be a non-negative number; got -4. + set tabChildren + after set 4 + tabEnabled = true + tabIndex = 0 + tabChildren = true + set tabEnabled + set tabIndex + set tabChildren + after set 5 + tabEnabled = true + tabIndex = 2147483647 + tabChildren = true + set tabEnabled + set tabIndex + Error: RangeError: Error #2027: Parameter tabIndex must be a non-negative number; got -2147483648. + set tabChildren + after set 6 + tabEnabled = true + tabIndex = 2147483647 + tabChildren = true + set tabEnabled + set tabIndex + set tabChildren + after set 7 + tabEnabled = true + tabIndex = 0 + tabChildren = true + set tabEnabled + set tabIndex + Error: RangeError: Error #2027: Parameter tabIndex must be a non-negative number; got -2147483648. + set tabChildren + after set 8 + tabEnabled = true + tabIndex = 0 + tabChildren = true + set tabEnabled + set tabIndex + set tabChildren + after set 9 + tabEnabled = true + tabIndex = 0 + tabChildren = true + set tabEnabled + set tabIndex + set tabChildren + after set 10 + tabEnabled = true + tabIndex = 1 + tabChildren = true +===== movie clip with index ===== + default + tabEnabled = false + tabIndex = 4 + tabChildren = true + set tabEnabled + set tabIndex + set tabChildren + after set 1 + tabEnabled = true + tabIndex = 0 + tabChildren = true + set tabEnabled + set tabIndex + set tabChildren + after set 2 + tabEnabled = false + tabIndex = 4 + tabChildren = false + set tabEnabled + set tabIndex + set tabChildren + after set 3 + tabEnabled = false + tabIndex = 0 + tabChildren = false + set tabEnabled + set tabIndex + Error: RangeError: Error #2027: Parameter tabIndex must be a non-negative number; got -4. + set tabChildren + after set 4 + tabEnabled = true + tabIndex = 0 + tabChildren = true + set tabEnabled + set tabIndex + set tabChildren + after set 5 + tabEnabled = true + tabIndex = 2147483647 + tabChildren = true + set tabEnabled + set tabIndex + Error: RangeError: Error #2027: Parameter tabIndex must be a non-negative number; got -2147483648. + set tabChildren + after set 6 + tabEnabled = true + tabIndex = 2147483647 + tabChildren = true + set tabEnabled + set tabIndex + set tabChildren + after set 7 + tabEnabled = true + tabIndex = 0 + tabChildren = true + set tabEnabled + set tabIndex + Error: RangeError: Error #2027: Parameter tabIndex must be a non-negative number; got -2147483648. + set tabChildren + after set 8 + tabEnabled = true + tabIndex = 0 + tabChildren = true + set tabEnabled + set tabIndex + set tabChildren + after set 9 + tabEnabled = true + tabIndex = 0 + tabChildren = true + set tabEnabled + set tabIndex + set tabChildren + after set 10 + tabEnabled = true + tabIndex = 1 + tabChildren = true +===== sprite ===== + default + tabEnabled = false + tabIndex = -1 + tabChildren = true + set tabEnabled + set tabIndex + set tabChildren + after set 1 + tabEnabled = true + tabIndex = 0 + tabChildren = true + set tabEnabled + set tabIndex + set tabChildren + after set 2 + tabEnabled = false + tabIndex = 4 + tabChildren = false + set tabEnabled + set tabIndex + set tabChildren + after set 3 + tabEnabled = false + tabIndex = 0 + tabChildren = false + set tabEnabled + set tabIndex + Error: RangeError: Error #2027: Parameter tabIndex must be a non-negative number; got -4. + set tabChildren + after set 4 + tabEnabled = true + tabIndex = 0 + tabChildren = true + set tabEnabled + set tabIndex + set tabChildren + after set 5 + tabEnabled = true + tabIndex = 2147483647 + tabChildren = true + set tabEnabled + set tabIndex + Error: RangeError: Error #2027: Parameter tabIndex must be a non-negative number; got -2147483648. + set tabChildren + after set 6 + tabEnabled = true + tabIndex = 2147483647 + tabChildren = true + set tabEnabled + set tabIndex + set tabChildren + after set 7 + tabEnabled = true + tabIndex = 0 + tabChildren = true + set tabEnabled + set tabIndex + Error: RangeError: Error #2027: Parameter tabIndex must be a non-negative number; got -2147483648. + set tabChildren + after set 8 + tabEnabled = true + tabIndex = 0 + tabChildren = true + set tabEnabled + set tabIndex + set tabChildren + after set 9 + tabEnabled = true + tabIndex = 0 + tabChildren = true + set tabEnabled + set tabIndex + set tabChildren + after set 10 + tabEnabled = true + tabIndex = 1 + tabChildren = true diff --git a/tests/tests/swfs/avm2/tab_ordering_properties/test.swf b/tests/tests/swfs/avm2/tab_ordering_properties/test.swf new file mode 100644 index 000000000000..6e274895536c Binary files /dev/null and b/tests/tests/swfs/avm2/tab_ordering_properties/test.swf differ diff --git a/tests/tests/swfs/avm2/tab_ordering_properties/test.toml b/tests/tests/swfs/avm2/tab_ordering_properties/test.toml new file mode 100644 index 000000000000..cf6123969a1d --- /dev/null +++ b/tests/tests/swfs/avm2/tab_ordering_properties/test.toml @@ -0,0 +1 @@ +num_ticks = 1 diff --git a/tests/tests/swfs/avm2/tab_ordering_tabbable/Test.as b/tests/tests/swfs/avm2/tab_ordering_tabbable/Test.as new file mode 100644 index 000000000000..a70b8fb05674 --- /dev/null +++ b/tests/tests/swfs/avm2/tab_ordering_tabbable/Test.as @@ -0,0 +1,144 @@ +package { + +import flash.display.DisplayObject; +import flash.display.InteractiveObject; +import flash.events.KeyboardEvent; +import flash.text.TextField; +import flash.display.Sprite; +import flash.display.SimpleButton; +import flash.display.MovieClip; +import flash.events.Event; + +public class Test extends MovieClip { + var objects:Array; + var tabbedObjects:Array = []; + var testStage:int = 0; + + public function Test() { + super(); + + var text1:TextField = this.newTextField(1); + text1.type = "dynamic"; + + var text2:TextField = this.newTextField(2); + text2.maxChars = 0; + + var text3:TextField = this.newTextField(3); + text3.visible = false; + + var text4:TextField = this.newTextField(4); + text4.x = -400; + text4.y = -400; + + var text5:TextField = this.newTextField(5); + + var text6:TextField = this.newTextField(6); + text6.selectable = false; + + var text7:TextField = this.newTextField(7); + text7.width = 0; + text7.height = 0; + + var clip8:MovieClip = this.newMovieClip(8); + + var clip9:MovieClip = this.newMovieClip(9); + clip9.visible = false; + + var button10:SimpleButton = new SimpleButton(); + button10.name = "button10"; + setupObject(button10, 10); + + var button11:SimpleButton = new SimpleButton(); + button11.name = "button11"; + setupObject(button11, 11); + button11.visible = false; + + var text12:TextField = this.newTextField(12); + text12.tabEnabled = true; + text12.type = "dynamic"; + + this.objects = [ + text1, + text2, + text3, + text4, + text5, + text6, + text7, + clip8, + clip8.getChildByName("clip8.text"), + clip9, + clip9.getChildByName("clip9.text"), + button10, + button11, + text12 + ]; + + var test:Test = this; + for each (var obj in objects) { + obj.addEventListener("focusIn", function(obj) { + return function (evt:Event):void { + test.tabbedObjects.push(obj.name); + } + }(obj)); + this.stage.addChild(obj); + } + + this.stage.addEventListener("keyDown", function(evt:KeyboardEvent) { + if (evt.keyCode == 27) { + trace("Tabbable elements:"); + for each (var obj in objects) { + var exists = false; + for each (var name in tabbedObjects) { + if (obj.name == name) { + exists = true; + } + } + trace(" " + obj.name + ": " + exists); + } + + ++test.testStage; + if (test.testStage == 1) { + trace("Enabling tab"); + for each (var obj in objects) { + obj.tabEnabled = true; + } + } else if (test.testStage == 2) { + trace("Setting custom order"); + for (var i in objects) { + objects[i].tabIndex = i; + } + } + } + }); + } + + function newTextField(i:int):TextField { + var tf:TextField = new TextField(); + tf.type = "input"; + tf.name = "text" + i; + tf.border = true; + this.setupObject(tf, i); + return tf; + } + + function newMovieClip(i:int):MovieClip { + var mc:MovieClip = new MovieClip(); + mc.name = "clip" + i; + this.setupObject(mc, i); + + var tf:TextField = this.newTextField(0); + tf.name = mc.name + ".text"; + + mc.addChild(tf); + return mc; + } + + function setupObject(o:DisplayObject, i:int):void { + o.x = 0; + o.y = i * 20; + o.height = 20; + o.width = 100; + } +} +} diff --git a/tests/tests/swfs/avm2/tab_ordering_tabbable/input.json b/tests/tests/swfs/avm2/tab_ordering_tabbable/input.json new file mode 100644 index 000000000000..30955fa002ee --- /dev/null +++ b/tests/tests/swfs/avm2/tab_ordering_tabbable/input.json @@ -0,0 +1,47 @@ +[ + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 27 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 27 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 9 }, + { "type": "KeyDown", "key_code": 27 } +] diff --git a/tests/tests/swfs/avm2/tab_ordering_tabbable/output.txt b/tests/tests/swfs/avm2/tab_ordering_tabbable/output.txt new file mode 100644 index 000000000000..a4c0425f1980 --- /dev/null +++ b/tests/tests/swfs/avm2/tab_ordering_tabbable/output.txt @@ -0,0 +1,47 @@ +Tabbable elements: + text1: false + text2: true + text3: false + text4: true + text5: true + text6: true + text7: true + clip8: false + clip8.text: true + clip9: false + clip9.text: false + button10: true + button11: false + text12: false +Enabling tab +Tabbable elements: + text1: false + text2: true + text3: false + text4: true + text5: true + text6: true + text7: true + clip8: true + clip8.text: true + clip9: false + clip9.text: false + button10: true + button11: false + text12: false +Setting custom order +Tabbable elements: + text1: false + text2: true + text3: false + text4: true + text5: true + text6: true + text7: true + clip8: true + clip8.text: true + clip9: false + clip9.text: true + button10: true + button11: false + text12: false diff --git a/tests/tests/swfs/avm2/tab_ordering_tabbable/test.swf b/tests/tests/swfs/avm2/tab_ordering_tabbable/test.swf new file mode 100644 index 000000000000..d025eeeaa315 Binary files /dev/null and b/tests/tests/swfs/avm2/tab_ordering_tabbable/test.swf differ diff --git a/tests/tests/swfs/avm2/tab_ordering_tabbable/test.toml b/tests/tests/swfs/avm2/tab_ordering_tabbable/test.toml new file mode 100644 index 000000000000..cf6123969a1d --- /dev/null +++ b/tests/tests/swfs/avm2/tab_ordering_tabbable/test.toml @@ -0,0 +1 @@ +num_ticks = 1