core: `root` and `stage` should yield `None` if an inactive state child of an `Avm2Button` is involved in the parent chain.

This commit is contained in:
David Wendt 2021-05-06 20:00:58 -04:00 committed by Mike Welsh
parent 169a99397a
commit cfd95e3b3b
2 changed files with 36 additions and 14 deletions

View File

@ -1256,14 +1256,27 @@ pub trait TDisplayObject<'gc>:
/// version, see `avm1_root`. /// version, see `avm1_root`.
fn avm2_root(&self, context: &mut UpdateContext<'_, 'gc, '_>) -> Option<DisplayObject<'gc>> { fn avm2_root(&self, context: &mut UpdateContext<'_, 'gc, '_>) -> Option<DisplayObject<'gc>> {
let mut parent = Some((*self).into()); let mut parent = Some((*self).into());
if self.as_stage().is_some() {
return parent;
}
while let Some(p) = parent { while let Some(p) = parent {
let grandparent = p.avm2_parent(); let grandparent = p.parent();
if grandparent.is_none() { if grandparent.is_none() {
break; break;
} }
if let Some(gp_btn) = grandparent.and_then(|gp| gp.as_avm2_button()) {
let active_state = gp_btn.get_state_child(gp_btn.state().into());
if active_state
.map(|state| !DisplayObject::ptr_eq(state, p))
.unwrap_or(true)
{
return None;
}
}
if let Some(gp) = grandparent { if let Some(gp) = grandparent {
if gp.as_stage().is_some() { if gp.as_stage().is_some() {
break; break;
@ -1273,16 +1286,12 @@ pub trait TDisplayObject<'gc>:
parent = grandparent; parent = grandparent;
} }
if let Some(parent) = parent {
if !parent.is_on_stage(context) {
return None;
}
}
parent.or_else(|| {
let movie = self.movie()?; let movie = self.movie()?;
context.library.library_for_movie_mut(movie).root() context
}) .library
.library_for_movie_mut(movie)
.root()
.or_else(|| parent.filter(|p| p.is_on_stage(context)))
} }
/// Obtain the root of the display tree hierarchy, if a suitable object /// Obtain the root of the display tree hierarchy, if a suitable object
@ -1296,14 +1305,22 @@ pub trait TDisplayObject<'gc>:
let mut parent = Some((*self).into()); let mut parent = Some((*self).into());
while let Some(p) = parent { while let Some(p) = parent {
p.as_container()?; let grandparent = p.parent();
let grandparent = p.avm2_parent();
if grandparent.is_none() { if grandparent.is_none() {
break; break;
} }
if let Some(gp_btn) = grandparent.and_then(|gp| gp.as_avm2_button()) {
let active_state = gp_btn.get_state_child(gp_btn.state().into());
if active_state
.map(|state| !DisplayObject::ptr_eq(state, p))
.unwrap_or(true)
{
return None;
}
}
parent = grandparent; parent = grandparent;
} }

View File

@ -256,6 +256,11 @@ impl<'gc> Avm2Button<'gc> {
} }
} }
/// Get the rendered state of the button.
pub fn state(self) -> ButtonState {
self.0.read().state
}
/// Change the rendered state of the button. /// Change the rendered state of the button.
pub fn set_state(self, context: &mut UpdateContext<'_, 'gc, '_>, state: ButtonState) { pub fn set_state(self, context: &mut UpdateContext<'_, 'gc, '_>, state: ButtonState) {
self.0.write(context.gc_context).state = state; self.0.write(context.gc_context).state = state;