|
1 | 1 | //! `MovieClip` display object and support code. |
| 2 | +use crate::avm1::globals::AVM_DEPTH_BIAS; |
2 | 3 | use crate::avm1::Avm1; |
3 | 4 | use crate::avm1::{Activation as Avm1Activation, ActivationIdentifier}; |
4 | 5 | use crate::avm1::{NativeObject as Avm1NativeObject, Object as Avm1Object, Value as Avm1Value}; |
@@ -1562,10 +1563,30 @@ impl<'gc> MovieClip<'gc> { |
1562 | 1563 | // TODO: We want to do something like self.children.retain here, |
1563 | 1564 | // but BTreeMap::retain does not exist. |
1564 | 1565 | // TODO: Should AS3 children ignore GOTOs? |
| 1566 | + |
| 1567 | + let final_placements: HashMap<Depth, &GotoPlaceObject<'_>> = |
| 1568 | + goto_commands.iter().map(|cmd| (cmd.depth(), cmd)).collect(); |
| 1569 | + |
1565 | 1570 | let children: SmallVec<[_; 16]> = self |
1566 | 1571 | .iter_render_list() |
1567 | | - .filter(|clip| clip.place_frame() > frame) |
| 1572 | + .filter(|child| { |
| 1573 | + let is_candidate_for_removal = if self.movie().is_action_script_3() { |
| 1574 | + child.place_frame() > frame || child.placed_by_script() |
| 1575 | + } else { |
| 1576 | + child.depth() < AVM_DEPTH_BIAS |
| 1577 | + }; |
| 1578 | + |
| 1579 | + if !is_candidate_for_removal && child.as_morph_shape().is_none() { |
| 1580 | + return false; |
| 1581 | + } |
| 1582 | + if let Some(final_placement) = final_placements.get(&child.depth()) { |
| 1583 | + !self.survives_rewind(*child, &final_placement.place_object) |
| 1584 | + } else { |
| 1585 | + true |
| 1586 | + } |
| 1587 | + }) |
1568 | 1588 | .collect(); |
| 1589 | + |
1569 | 1590 | for child in children { |
1570 | 1591 | if !child.placed_by_script() { |
1571 | 1592 | self.remove_child(context, child); |
@@ -1690,6 +1711,61 @@ impl<'gc> MovieClip<'gc> { |
1690 | 1711 | self.assert_expected_tag_end(hit_target_frame); |
1691 | 1712 | } |
1692 | 1713 |
|
| 1714 | + fn survives_rewind(self, old_object: DisplayObject<'_>, new_params: &swf::PlaceObject) -> bool { |
| 1715 | + // TODO [KJ] This logic is not 100% tested. It's possible it's a bit |
| 1716 | + // different in reality, but the spirit is there :) |
| 1717 | + |
| 1718 | + if !old_object.movie().is_action_script_3() |
| 1719 | + && old_object.placed_by_avm1_script() |
| 1720 | + && old_object.depth() < AVM_DEPTH_BIAS |
| 1721 | + { |
| 1722 | + return false; |
| 1723 | + } |
| 1724 | + let id_equals = match new_params.action { |
| 1725 | + swf::PlaceObjectAction::Place(id) | swf::PlaceObjectAction::Replace(id) => { |
| 1726 | + old_object.id() == id |
| 1727 | + } |
| 1728 | + _ => false, |
| 1729 | + }; |
| 1730 | + let ratio_equals = match new_params.ratio { |
| 1731 | + Some(ratio) => old_object.ratio() == ratio, |
| 1732 | + None => true, |
| 1733 | + }; |
| 1734 | + |
| 1735 | + let clip_depth_equals = match new_params.clip_depth { |
| 1736 | + Some(clip_depth) => old_object.clip_depth() == clip_depth as Depth, |
| 1737 | + None => true, |
| 1738 | + }; |
| 1739 | + |
| 1740 | + let color_transform_equals = match new_params.color_transform { |
| 1741 | + Some(color_transform) => old_object.base().color_transform() == color_transform, |
| 1742 | + None => true, |
| 1743 | + }; |
| 1744 | + |
| 1745 | + let base_matrix_equals = match new_params.matrix { |
| 1746 | + Some(matrix) => old_object.base().matrix() == matrix.into(), |
| 1747 | + None => true, |
| 1748 | + }; |
| 1749 | + |
| 1750 | + match old_object { |
| 1751 | + DisplayObject::MorphShape(_) | DisplayObject::Graphic(_) | DisplayObject::Text(_) => { |
| 1752 | + ratio_equals |
| 1753 | + && id_equals |
| 1754 | + && clip_depth_equals |
| 1755 | + && base_matrix_equals |
| 1756 | + && color_transform_equals |
| 1757 | + } |
| 1758 | + DisplayObject::Avm1Button(_) |
| 1759 | + | DisplayObject::Avm2Button(_) |
| 1760 | + | DisplayObject::EditText(_) |
| 1761 | + | DisplayObject::Bitmap(_) |
| 1762 | + | DisplayObject::Video(_) => ratio_equals && id_equals && clip_depth_equals, |
| 1763 | + DisplayObject::MovieClip(_) |
| 1764 | + | DisplayObject::Stage(_) |
| 1765 | + | DisplayObject::LoaderDisplay(_) => ratio_equals, |
| 1766 | + } |
| 1767 | + } |
| 1768 | + |
1693 | 1769 | fn construct_as_avm1_object( |
1694 | 1770 | self, |
1695 | 1771 | context: &mut UpdateContext<'gc>, |
|
0 commit comments