tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

animation-trigger-multiple-triggers.tentative.html (7971B)


      1 <!DOCTYPE html>
      2 <html>
      3  <head>
      4    <link rel="help" src="https://drafts.csswg.org/css-animations-2/#animation-trigger">
      5    <script src="/resources/testharness.js"></script>
      6    <script src="/resources/testharnessreport.js"></script>
      7    <script src="/web-animations/testcommon.js"></script>
      8    <script src="/dom/events/scrolling/scroll_support.js"></script>
      9    <script src="support/support.js"></script>
     10  </head>
     11  <body>
     12    <style>
     13      .subject, .target {
     14        height: 50px;
     15        width: 50px;
     16        background-color: red;
     17      }
     18      .scroller {
     19        overflow-y: scroll;
     20        height: 500px;
     21        width: 500px;
     22        border: solid 1px;
     23        position: relative;
     24      }
     25      #space {
     26        width: 50px;
     27        height: 600px;
     28      }
     29    </style>
     30    <div id="wrapper">
     31      <div id="scroller" class="scroller">
     32        <div id="space"></div>
     33        <div id="subject1" class="subject"></div>
     34        <div id="space"></div>
     35        <div id="subject2" class="subject"></div>
     36        <div id="space"></div>
     37      </div>
     38      <div id="target" class="target"></div>
     39    </div>
     40    <script>
     41      // The trigger and exit ranges are the same for this test.
     42      const TRIGGER_START_PX = 150;
     43      const TRIGGER_END_PX = 200;
     44      const scroller = document.getElementById("scroller");
     45      const subject1 = document.getElementById("subject1");
     46      const subject2 = document.getElementById("subject2");
     47      const target = document.getElementById("target");
     48 
     49      function getRangeBoundariesForSubject(subject, scroller) {
     50        const cover_start_offset = subject.offsetTop - scroller.clientHeight;
     51        return getRangeBoundariesForTest(
     52                                    cover_start_offset + TRIGGER_START_PX,
     53                                    cover_start_offset + TRIGGER_END_PX,
     54                                    cover_start_offset + TRIGGER_START_PX,
     55                                    cover_start_offset + TRIGGER_END_PX,
     56                                    scroller);
     57      }
     58      const rangeBoundaries1 = getRangeBoundariesForSubject(subject1,
     59          scroller);
     60      const rangeBoundaries2 = getRangeBoundariesForSubject(subject2,
     61          scroller);
     62 
     63      const ANIMATION_DURATION_MS = 1;
     64      const view_timeline1 = new ViewTimeline({ subject: subject1 });
     65      const view_timeline2 = new ViewTimeline({ subject: subject2 });
     66      function setupAnimation() {
     67        const animation = new Animation(
     68          new KeyframeEffect(
     69            target,
     70            [
     71              { transform: "scaleX(1)", backgroundColor: "pink" },
     72              { transform: "scaleX(5)", backgroundColor: "pink" }
     73            ],
     74            { duration: ANIMATION_DURATION_MS, fill: "both" }
     75          ));
     76        return animation;
     77      }
     78      function setupAnimationTrigger(view_timeline) {
     79        const trigger = new TimelineTrigger({
     80              timeline: view_timeline,
     81              rangeStart: `${TRIGGER_START_PX}px`,
     82              rangeEnd: `${TRIGGER_END_PX}px`
     83            });
     84        return trigger;
     85      }
     86 
     87      promise_test(async (test) => {
     88        const animation = setupAnimation();
     89        const trigger1 = setupAnimationTrigger(view_timeline1);
     90        const trigger2 = setupAnimationTrigger(view_timeline2);
     91 
     92        // Test preconditions.
     93        assert_equals(animation.playState, "idle", "animation is idle");
     94        assert_equals(animation.currentTime, null, "currentTime is null");
     95        assert_equals(scroller.scrollTop, 0, "scroller is not scrolled, i.e. " +
     96          "not within the trigger range");
     97        assert_array_equals(trigger1.getAnimations(), [],
     98          "trigger1 has no animation attached");
     99        assert_array_equals(trigger2.getAnimations(), [],
    100          "trigger2 has no animation attached");
    101 
    102        trigger1.addAnimation(animation, "play-forwards", "reset");
    103        trigger2.addAnimation(animation, "play-forwards", "reset");
    104 
    105        // Test preconditions.
    106        assert_equals(animation.playState, "paused", "animation is idle");
    107        assert_equals(animation.currentTime, 0, "currentTime is 0");
    108        assert_array_equals(trigger1.getAnimations(), [animation],
    109          "trigger1 has animation attached");
    110        assert_array_equals(trigger2.getAnimations(), [animation],
    111          "trigger2 has animation attached");
    112 
    113        await rangeBoundaries1.enterTriggerRange();
    114        await animation.finished;
    115        assert_equals(animation.playState, "finished",
    116          "animation is played by trigger1");
    117        assert_times_equal(animation.currentTime, ANIMATION_DURATION_MS,
    118          `currentTime is ${ANIMATION_DURATION_MS}`);
    119 
    120        await rangeBoundaries1.exitExitRangeBelow();
    121        await waitForNextFrame();
    122        assert_equals(animation.playState, "paused",
    123          "animation should be reset by trigger1");
    124        assert_times_equal(animation.currentTime, 0, "currentTime is 0");
    125 
    126        // animation should be played by trigger2.
    127        rangeBoundaries2.enterTriggerRange();
    128        await animation.finished;
    129        assert_equals(animation.playState, "finished",
    130          "animation is paused, awaiting trigger event");
    131        assert_times_equal(animation.currentTime, ANIMATION_DURATION_MS,
    132          `currentTime is ${ANIMATION_DURATION_MS}`);
    133 
    134        // animation should be reversed by trigger2.
    135        rangeBoundaries2.exitExitRangeBelow();
    136        await waitForNextFrame();
    137        assert_equals(animation.playState, "paused",
    138          "animation is paused, awaiting trigger event");
    139        assert_times_equal(animation.currentTime, 0, `currentTime is 0`);
    140      }, "Triggers on same animation; no conflict.");
    141 
    142      promise_test(async (test) => {
    143        await waitForScrollReset(test, scroller);
    144        const animation = setupAnimation();
    145        const trigger1 = setupAnimationTrigger(view_timeline1);
    146        const trigger2 = setupAnimationTrigger(view_timeline2);
    147 
    148        // Test preconditions.
    149        assert_equals(animation.playState, "idle", "animation is idle");
    150        assert_equals(animation.currentTime, null, "currentTime is null");
    151        assert_equals(scroller.scrollTop, 0, "scroller is not scrolled, i.e. " +
    152          "not within the trigger range");
    153        assert_array_equals(trigger1.getAnimations(), [],
    154          "trigger1 has no animation attached");
    155        assert_array_equals(trigger2.getAnimations(), [],
    156          "trigger2 has no animation attached");
    157 
    158        trigger1.addAnimation(animation, "play-forwards", "reset");
    159        trigger2.addAnimation(animation, "play-forwards", "reset");
    160 
    161        // Test preconditions.
    162        assert_equals(animation.playState, "paused", "animation is paused");
    163        assert_equals(animation.currentTime, 0, "currentTime is null");
    164        assert_array_equals(trigger1.getAnimations(), [animation],
    165          "trigger1 has animation attached");
    166        assert_array_equals(trigger2.getAnimations(), [animation],
    167          "trigger2 has animation attached");
    168 
    169        await rangeBoundaries1.enterTriggerRange();
    170        await animation.finished;
    171        assert_equals(animation.playState, "finished",
    172          "animation is played by trigger1");
    173        assert_times_equal(animation.currentTime, ANIMATION_DURATION_MS,
    174          `currentTime is ${ANIMATION_DURATION_MS}`);
    175 
    176        // Entering trigger2's trigger range exits trigger1's exit range.
    177        // So trigger1 wants to do a reset and trigger2 wants to play the
    178        // animation. As trigger2 was the most recently created, it wins and the
    179        // animation is played.
    180        rangeBoundaries2.enterTriggerRange();
    181        await animation.finished;
    182        assert_equals(animation.playState, "finished",
    183          "animation is paused, awaiting trigger event");
    184        assert_times_equal(animation.currentTime, ANIMATION_DURATION_MS,
    185          `currentTime is ${ANIMATION_DURATION_MS}`);
    186      }, "Triggers on same animation; conflict.");
    187    </script>
    188  </body>
    189 </html>