11//! `MovieClip` display object and support code.
2+ use crate :: avm1:: globals:: AVM_DEPTH_BIAS ;
23use crate :: avm1:: Avm1 ;
34use crate :: avm1:: { Activation as Avm1Activation , ActivationIdentifier } ;
45use crate :: avm1:: { NativeObject as Avm1NativeObject , Object as Avm1Object , Value as Avm1Value } ;
@@ -1567,6 +1568,58 @@ impl<'gc> MovieClip<'gc> {
15671568 }
15681569 let hit_target_frame = self . 0 . current_frame ( ) == frame;
15691570
1571+ fn survives_rewind ( old_object : DisplayObject < ' _ > , new_params : & swf:: PlaceObject ) -> bool {
1572+ if !old_object. movie ( ) . is_action_script_3 ( )
1573+ && old_object. placed_by_avm1_script ( )
1574+ && old_object. depth ( ) < AVM_DEPTH_BIAS
1575+ {
1576+ return false ;
1577+ }
1578+ let id = match new_params. action {
1579+ swf:: PlaceObjectAction :: Place ( id) | swf:: PlaceObjectAction :: Replace ( id) => id,
1580+ _ => 0 ,
1581+ } ;
1582+ let ratio_equals = match new_params. ratio {
1583+ Some ( ratio) => old_object. ratio ( ) == ratio,
1584+ None => true ,
1585+ } ;
1586+
1587+ let clip_depth_equals = match new_params. clip_depth {
1588+ Some ( clip_depth) => old_object. clip_depth ( ) == clip_depth as Depth ,
1589+ None => true ,
1590+ } ;
1591+
1592+ let color_transform_equals = match new_params. color_transform {
1593+ Some ( color_transform) => old_object. base ( ) . color_transform ( ) == color_transform,
1594+ None => true ,
1595+ } ;
1596+
1597+ let base_matrix_equals = match new_params. matrix {
1598+ Some ( matrix) => old_object. base ( ) . matrix ( ) == matrix. into ( ) ,
1599+ None => true ,
1600+ } ;
1601+
1602+ match old_object {
1603+ DisplayObject :: MorphShape ( _)
1604+ | DisplayObject :: Graphic ( _)
1605+ | DisplayObject :: Text ( _) => {
1606+ ratio_equals
1607+ && old_object. id ( ) == id
1608+ && clip_depth_equals
1609+ && base_matrix_equals
1610+ && color_transform_equals
1611+ }
1612+ DisplayObject :: Avm1Button ( _)
1613+ | DisplayObject :: Avm2Button ( _)
1614+ | DisplayObject :: EditText ( _)
1615+ | DisplayObject :: Bitmap ( _)
1616+ | DisplayObject :: Video ( _) => {
1617+ ratio_equals && old_object. id ( ) == id && clip_depth_equals
1618+ }
1619+ _ => ratio_equals,
1620+ }
1621+ }
1622+
15701623 if is_rewind {
15711624 // Remove all display objects that were created after the
15721625 // destination frame.
@@ -1577,10 +1630,29 @@ impl<'gc> MovieClip<'gc> {
15771630 // TODO: We want to do something like self.children.retain here,
15781631 // but BTreeMap::retain does not exist.
15791632 // TODO: Should AS3 children ignore GOTOs?
1633+ let final_placements: std:: collections:: HashMap < Depth , & GotoPlaceObject < ' _ > > =
1634+ goto_commands. iter ( ) . map ( |cmd| ( cmd. depth ( ) , cmd) ) . collect ( ) ;
1635+
15801636 let children: SmallVec < [ _ ; 16 ] > = self
15811637 . iter_render_list ( )
1582- . filter ( |clip| clip. place_frame ( ) > frame)
1638+ . filter ( |child| {
1639+ let is_candidate_for_removal = if self . movie ( ) . is_action_script_3 ( ) {
1640+ child. place_frame ( ) > frame || child. placed_by_script ( )
1641+ } else {
1642+ child. depth ( ) < AVM_DEPTH_BIAS
1643+ } ;
1644+
1645+ if !is_candidate_for_removal && child. as_morph_shape ( ) . is_none ( ) {
1646+ return false ;
1647+ }
1648+ if let Some ( final_placement) = final_placements. get ( & child. depth ( ) ) {
1649+ !survives_rewind ( * child, & final_placement. place_object )
1650+ } else {
1651+ true
1652+ }
1653+ } )
15831654 . collect ( ) ;
1655+
15841656 for child in children {
15851657 if !child. placed_by_script ( ) {
15861658 self . remove_child ( context, child) ;
0 commit comments