diff --git a/core/src/avm1/object/stage_object.rs b/core/src/avm1/object/stage_object.rs index 685b25d7f025..79ee152ff2ad 100644 --- a/core/src/avm1/object/stage_object.rs +++ b/core/src/avm1/object/stage_object.rs @@ -592,7 +592,7 @@ fn set_visible<'gc>( // Because this property dates to the era of Flash 4, this is actually coerced to an integer. // `_visible = "false";` coerces to NaN and has no effect. if let Some(n) = property_coerce_to_number(activation, val)? { - this.set_visible(activation.context.gc_context, n != 0.0); + this.set_visible(&mut activation.context, n != 0.0); } Ok(()) } diff --git a/core/src/avm2/globals/flash/display/display_object.rs b/core/src/avm2/globals/flash/display/display_object.rs index 411d769c59cf..0360933482b9 100644 --- a/core/src/avm2/globals/flash/display/display_object.rs +++ b/core/src/avm2/globals/flash/display/display_object.rs @@ -617,7 +617,7 @@ pub fn set_visible<'gc>( if let Some(dobj) = this.as_display_object() { let new_visible = args.get_bool(0); - dobj.set_visible(activation.context.gc_context, new_visible); + dobj.set_visible(&mut activation.context, new_visible); } Ok(Value::Undefined) diff --git a/core/src/debug_ui/display_object.rs b/core/src/debug_ui/display_object.rs index 458423ed8e55..46b8fc6b0ded 100644 --- a/core/src/debug_ui/display_object.rs +++ b/core/src/debug_ui/display_object.rs @@ -855,7 +855,7 @@ impl DisplayObjectWindow { ui.checkbox(&mut is_visible, "Visible"); ui.end_row(); if is_visible != was_visible { - object.set_visible(context.gc_context, is_visible); + object.set_visible(context, is_visible); } ui.label("Blend mode"); diff --git a/core/src/display_object.rs b/core/src/display_object.rs index 2d93fd2e670c..3f87447db828 100644 --- a/core/src/display_object.rs +++ b/core/src/display_object.rs @@ -1738,11 +1738,18 @@ pub trait TDisplayObject<'gc>: /// Sets whether this display object will be visible. /// Invisible objects are not rendered, but otherwise continue to exist normally. /// Returned by the `_visible`/`visible` ActionScript properties. - fn set_visible(&self, gc_context: &Mutation<'gc>, value: bool) { - if self.base_mut(gc_context).set_visible(value) { + fn set_visible(&self, context: &mut UpdateContext<'_, 'gc>, value: bool) { + if self.base_mut(context.gc()).set_visible(value) { if let Some(parent) = self.parent() { // We don't need to invalidate ourselves, we're just toggling if the bitmap is rendered. - parent.invalidate_cached_bitmap(gc_context); + parent.invalidate_cached_bitmap(context.gc()); + } + } + + if !value { + if let Some(int) = self.as_interactive() { + // The focus is dropped when it's made invisible. + int.drop_focus(context); } } } @@ -2209,7 +2216,7 @@ pub trait TDisplayObject<'gc>: } if self.swf_version() >= 11 { if let Some(visible) = place_object.is_visible { - self.set_visible(context.gc_context, visible); + self.set_visible(context, visible); } if let Some(mut color) = place_object.background_color { let color = if color.a > 0 { diff --git a/core/src/player.rs b/core/src/player.rs index c362256fdf93..f46b88821141 100644 --- a/core/src/player.rs +++ b/core/src/player.rs @@ -1293,14 +1293,14 @@ impl Player { // Turn the dragged object invisible so that we don't pick it. // TODO: This could be handled via adding a `HitTestOptions::SKIP_DRAGGED`. let was_visible = display_object.visible(); - display_object.set_visible(context.gc_context, false); + display_object.set_visible(context, false); // Set `_droptarget` to the object the mouse is hovering over. let drop_target_object = run_mouse_pick(context, false); movie_clip.set_drop_target( context.gc_context, drop_target_object.map(|d| d.as_displayobject()), ); - display_object.set_visible(context.gc_context, was_visible); + display_object.set_visible(context, was_visible); } } } diff --git a/tests/tests/swfs/avm1/focus_remove/output.txt b/tests/tests/swfs/avm1/focus_remove/output.txt index 9dd377cadd30..9bdccba3d028 100644 --- a/tests/tests/swfs/avm1/focus_remove/output.txt +++ b/tests/tests/swfs/avm1/focus_remove/output.txt @@ -4,6 +4,9 @@ Focus changed old: null new: _level0.clip Focus: _level0.clip +Focus changed + old: _level0.clip + new: null Focus: null Focus: null ===== text @@ -12,6 +15,9 @@ Focus changed old: null new: _level0.clip.text Focus: _level0.clip.text +Focus changed + old: _level0.clip.text + new: null Focus: null Focus: null ===== button @@ -20,5 +26,8 @@ Focus changed old: null new: _level0.clip.button Focus: _level0.clip.button +Focus changed + old: _level0.clip.button + new: null Focus: null Focus: null diff --git a/tests/tests/swfs/avm1/focus_remove/test.as b/tests/tests/swfs/avm1/focus_remove/test.as index 31a2e1ae5865..93b18ed387ee 100644 --- a/tests/tests/swfs/avm1/focus_remove/test.as +++ b/tests/tests/swfs/avm1/focus_remove/test.as @@ -1,10 +1,8 @@ var listener = new Object(); listener.onSetFocus = function(oldFocus, newFocus) { - if (newFocus) { - trace("Focus changed"); - trace(" old: " + oldFocus); - trace(" new: " + newFocus); - } + trace("Focus changed"); + trace(" old: " + oldFocus); + trace(" new: " + newFocus); }; Selection.addListener(listener); diff --git a/tests/tests/swfs/avm1/focus_remove/test.swf b/tests/tests/swfs/avm1/focus_remove/test.swf index 74e11ef9d52e..47ecb17ab9ad 100644 Binary files a/tests/tests/swfs/avm1/focus_remove/test.swf and b/tests/tests/swfs/avm1/focus_remove/test.swf differ diff --git a/tests/tests/swfs/avm1/focus_visibility_change/output.txt b/tests/tests/swfs/avm1/focus_visibility_change/output.txt new file mode 100644 index 000000000000..c4f9f3a9a307 --- /dev/null +++ b/tests/tests/swfs/avm1/focus_visibility_change/output.txt @@ -0,0 +1,45 @@ +===== clip +Object: _level0.clip +Made visible +Focus changed + old: null + new: _level0.clip +Focus: _level0.clip +Focus changed + old: _level0.clip + new: null +Made invisible +Focus: null +Made visible +Focus: null +Made invisible +===== text +Object: _level0.text +Made visible +Focus changed + old: null + new: _level0.text +Focus: _level0.text +Focus changed + old: _level0.text + new: null +Made invisible +Focus: null +Made visible +Focus: null +Made invisible +===== button +Object: _level0.button +Made visible +Focus changed + old: null + new: _level0.button +Focus: _level0.button +Focus changed + old: _level0.button + new: null +Made invisible +Focus: null +Made visible +Focus: null +Made invisible diff --git a/tests/tests/swfs/avm1/focus_visibility_change/test.as b/tests/tests/swfs/avm1/focus_visibility_change/test.as new file mode 100644 index 000000000000..ddb37079532c --- /dev/null +++ b/tests/tests/swfs/avm1/focus_visibility_change/test.as @@ -0,0 +1,39 @@ +var listener = new Object(); +listener.onSetFocus = function(oldFocus, newFocus) { + trace("Focus changed"); + trace(" old: " + oldFocus); + trace(" new: " + newFocus); +}; +Selection.addListener(listener); + +function testObject(obj) { + trace("Object: " + obj); + obj._visible = true; + trace("Made visible"); + obj.focusEnabled = true; + Selection.setFocus(obj); + trace("Focus: " + Selection.getFocus()); + obj._visible = false; + trace("Made invisible"); + trace("Focus: " + Selection.getFocus()); + + obj._visible = true; + trace("Made visible"); + trace("Focus: " + Selection.getFocus()); + obj._visible = false; + trace("Made invisible"); +} + +var clip = _root.createEmptyMovieClip("clip", 10); +var text = _root.createTextField("text", 11, 0, 0, 150, 20); +text.type = "input"; +var button = _root.attachMovie("CustomButton", "button", 12); + +trace("===== clip"); +testObject(clip); + +trace("===== text"); +testObject(text); + +trace("===== button"); +testObject(button); diff --git a/tests/tests/swfs/avm1/focus_visibility_change/test.swf b/tests/tests/swfs/avm1/focus_visibility_change/test.swf new file mode 100644 index 000000000000..5bbcdf0bbdd5 Binary files /dev/null and b/tests/tests/swfs/avm1/focus_visibility_change/test.swf differ diff --git a/tests/tests/swfs/avm1/focus_visibility_change/test.toml b/tests/tests/swfs/avm1/focus_visibility_change/test.toml new file mode 100644 index 000000000000..cf6123969a1d --- /dev/null +++ b/tests/tests/swfs/avm1/focus_visibility_change/test.toml @@ -0,0 +1 @@ +num_ticks = 1