Skip to content

Commit cc33a6a

Browse files
jarca0123Herschelkjarosh
authored andcommitted
core: Adjust clip removal logic for rewinds
Co-authored-by: Mike Welsh <mwelsh@gmail.com> Co-authored-by: Kamil Jarosz <kjarosh256@gmail.com>
1 parent 86425a3 commit cc33a6a

File tree

6 files changed

+77
-7
lines changed

6 files changed

+77
-7
lines changed

core/src/display_object/movie_clip.rs

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! `MovieClip` display object and support code.
2+
use crate::avm1::globals::AVM_DEPTH_BIAS;
23
use crate::avm1::Avm1;
34
use crate::avm1::{Activation as Avm1Activation, ActivationIdentifier};
45
use crate::avm1::{NativeObject as Avm1NativeObject, Object as Avm1Object, Value as Avm1Value};
@@ -1562,10 +1563,30 @@ impl<'gc> MovieClip<'gc> {
15621563
// TODO: We want to do something like self.children.retain here,
15631564
// but BTreeMap::retain does not exist.
15641565
// 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+
15651570
let children: SmallVec<[_; 16]> = self
15661571
.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+
})
15681588
.collect();
1589+
15691590
for child in children {
15701591
if !child.placed_by_script() {
15711592
self.remove_child(context, child);
@@ -1690,6 +1711,61 @@ impl<'gc> MovieClip<'gc> {
16901711
self.assert_expected_tag_end(hit_target_frame);
16911712
}
16921713

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+
16931769
fn construct_as_avm1_object(
16941770
self,
16951771
context: &mut UpdateContext<'gc>,
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1 @@
11
num_frames = 6
2-
# FIXME - Ruffle doesn't handle AVM1 'goto's correctly
3-
known_failure = true
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
# Test adapted from Shumway at https://github.com/mozilla/shumway/tree/master/test/swfs/avm1/duplicatemovieclip
22

33
num_frames = 4
4-
known_failure = true # https://github.com/ruffle-rs/ruffle/issues/12270
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
# Test adapted from Shumway at https://github.com/mozilla/shumway/tree/master/test/swfs/timeline/nav
22

33
num_frames = 3
4-
known_failure = true # https://github.com/ruffle-rs/ruffle/issues/12143
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
# Test adapted from Shumway at https://github.com/mozilla/shumway/tree/master/test/swfs/timeline/nav
22

33
num_frames = 3
4-
known_failure = true # https://github.com/ruffle-rs/ruffle/issues/12144
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
# Test adapted from Shumway at https://github.com/mozilla/shumway/tree/master/test/swfs/timeline/nav
22

33
num_frames = 3
4-
known_failure = true # https://github.com/ruffle-rs/ruffle/issues/12145

0 commit comments

Comments
 (0)