diff --git a/src/opentimelineio/composition.cpp b/src/opentimelineio/composition.cpp index 57e3733800..01fe6b9ded 100644 --- a/src/opentimelineio/composition.cpp +++ b/src/opentimelineio/composition.cpp @@ -397,6 +397,7 @@ Composition::trimmed_range_of_child( result_range = TimeRange( result_range->start_time() + parent_range.start_time(), result_range->duration()); + current = parent; } if (!source_range()) diff --git a/tests/test_composition.cpp b/tests/test_composition.cpp index a0a085d688..66a134ce31 100644 --- a/tests/test_composition.cpp +++ b/tests/test_composition.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -54,6 +55,28 @@ main(int argc, char** argv) assertEqual(items[0].value, clip.value); }); + tests.add_test("test_trimmed_range_of_nested_child", [] { + SerializableObject::Retainer root = new Stack; + SerializableObject::Retainer track = new Track; + SerializableObject::Retainer stack = new Stack; + SerializableObject::Retainer clip = new Clip; + + clip->set_source_range( + TimeRange(RationalTime(100, 24), RationalTime(50, 24))); + root->append_child(track); + track->append_child(new Gap(RationalTime(10, 24))); + track->append_child(stack); + stack->append_child(clip); + + OTIO_NS::ErrorStatus err; + auto range = root->trimmed_range_of_child(clip, &err); + assertFalse(is_error(err)); + assertTrue(range.has_value()); + assertEqual( + *range, + TimeRange(RationalTime(10, 24), RationalTime(50, 24))); + }); + tests.run(argc, argv); return 0; } diff --git a/tests/test_composition.py b/tests/test_composition.py index a3e56feb3f..1c99d37e8b 100755 --- a/tests/test_composition.py +++ b/tests/test_composition.py @@ -16,6 +16,41 @@ class CompositionTests(unittest.TestCase, otio_test_utils.OTIOAssertions): + def test_trimmed_range_of_nested_child(self): + rt = otio.opentime.RationalTime + tr = otio.opentime.TimeRange + clip = otio.schema.Clip(source_range=tr(rt(100, 24), rt(50, 24))) + track = otio.schema.Track(children=[ + otio.schema.Gap(duration=rt(10, 24)), clip + ]) + stack = otio.schema.Stack(children=[track]) + outer_track = otio.schema.Track(children=[ + otio.schema.Gap(duration=rt(20, 24)), stack + ]) + timeline = otio.schema.Timeline(tracks=[outer_track]) + + for ancestor, start in ( + (track, 10), + (stack, 10), + (outer_track, 30), + (timeline.tracks, 30), + ): + with self.subTest(ancestor=type(ancestor).__name__, start=start): + self.assertEqual( + ancestor.trimmed_range_of_child(clip), + tr(rt(start, 24), rt(50, 24)), + ) + + # A source range on the outermost stack still clips the result. + timeline.tracks.source_range = tr(rt(0, 24), rt(40, 24)) + self.assertEqual( + timeline.tracks.trimmed_range_of_child(clip), + tr(rt(30, 24), rt(10, 24)), + ) + + timeline.tracks.source_range = tr(rt(0, 24), rt(20, 24)) + self.assertIsNone(timeline.tracks.trimmed_range_of_child(clip)) + def test_cons(self): it = otio.core.Item() co = otio.core.Composition(name="test", children=[it])