Changeset 244823 in webkit


Ignore:
Timestamp:
May 1, 2019 8:56:34 AM (5 years ago)
Author:
eric.carlson@apple.com
Message:

XMLHttpRequest should propagate user gestures for media playback
https://bugs.webkit.org/show_bug.cgi?id=197428
<rdar://problem/46677392>

Reviewed by Jer Noble.

Source/WebCore:

A user gesture the would allow media state change in effect when XMLHttpRequest.send is
called should be active when the event handlers fire after the transaction completes successfully.

Test: http/tests/media/user-gesture-preserved-across-xmlhttprequest.html

  • dom/UserGestureIndicator.cpp:

(WebCore::UserGestureIndicator::UserGestureIndicator): Add a 'scope' parameter to potentially
limit the scope of the gesture to just media.
(WebCore::UserGestureIndicator::~UserGestureIndicator): Clear the scope.

  • dom/UserGestureIndicator.h:

(WebCore::UserGestureToken::processingUserGesture const):
(WebCore::UserGestureToken::setScope):
(WebCore::UserGestureToken::resetScope):
(WebCore::UserGestureToken::hasExpired const):

  • page/DOMTimer.cpp:

(WebCore::DOMTimerFireState::DOMTimerFireState): Don't need to store the nested timer interval,
UserGestureIndicator knows when it started.
(WebCore::DOMTimer::DOMTimer): Ditto.
(WebCore::DOMTimer::fired): Ditto.
(WebCore::DOMTimerFireState::nestedTimerInterval const): Deleted.
(WebCore::shouldForwardUserGesture): Deleted.
(WebCore::userGestureTokenToForward): Deleted.
(WebCore::currentNestedTimerInterval): Deleted.

  • page/DOMTimer.h:
  • testing/Internals.cpp:

(WebCore::Internals::setXHRMaximumIntervalForUserGestureForwarding): Override the maximum
user gesture interval for testing.

  • testing/Internals.h:
  • testing/Internals.idl:
  • xml/XMLHttpRequest.cpp:

(WebCore::XMLHttpRequest::XMLHttpRequest):
(WebCore::XMLHttpRequest::send): Stash the user gesture token.
(WebCore::XMLHttpRequest::dispatchEvent): Clear user gesture token if it has expired. If still
valid, activate it.

  • xml/XMLHttpRequest.h:

LayoutTests:

  • fast/events/popup-blocking-timers5-expected.txt:
  • fast/events/popup-blocking-timers5.html: Decrease the timer interval from 1000 to 900

because the user gesture is invalidated based on wall clock time.

  • fast/events/popup-blocking-timers6-expected.txt:
  • fast/events/popup-blocking-timers6.html: Increase the timer interval from 1001 to 1100

because the user gesture is invalidated based on wall clock time.

  • http/tests/media/user-gesture-preserved-across-xmlhttprequest-expected.txt: Added.
  • http/tests/media/user-gesture-preserved-across-xmlhttprequest.html: Added.
Location:
trunk
Files:
2 added
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r244821 r244823  
     12019-05-01  Eric Carlson  <eric.carlson@apple.com>
     2
     3        XMLHttpRequest should propagate user gestures for media playback
     4        https://bugs.webkit.org/show_bug.cgi?id=197428
     5        <rdar://problem/46677392>
     6
     7        Reviewed by Jer Noble.
     8
     9        * fast/events/popup-blocking-timers5-expected.txt:
     10        * fast/events/popup-blocking-timers5.html: Decrease the timer interval from 1000 to 900
     11        because the user gesture is invalidated based on wall clock time.
     12        * fast/events/popup-blocking-timers6-expected.txt:
     13        * fast/events/popup-blocking-timers6.html: Increase the timer interval from 1001 to 1100
     14        because the user gesture is invalidated based on wall clock time.
     15        * http/tests/media/user-gesture-preserved-across-xmlhttprequest-expected.txt: Added.
     16        * http/tests/media/user-gesture-preserved-across-xmlhttprequest.html: Added.
     17
    1182019-04-29  Darin Adler  <darin@apple.com>
    219
  • trunk/LayoutTests/fast/events/popup-blocking-timers5-expected.txt

    r130200 r244823  
    11Click Here
    2 Test calling window.open() with a 1000 ms delay. A popup should be allowed.
     2Test calling window.open() with a 900 ms delay. A popup should be allowed.
    33PASS newWindow is non-null.
    44
  • trunk/LayoutTests/fast/events/popup-blocking-timers5.html

    r155267 r244823  
    1616                newWindow = window.open("about:blank");
    1717                self.focus();
    18                 debug("Test calling window.open() with a 1000 ms delay. A popup should be allowed.")
     18                debug("Test calling window.open() with a 900 ms delay. A popup should be allowed.")
    1919                shouldBeNonNull("newWindow");
    2020                if (window.testRunner)
    2121                    testRunner.notifyDone();
    22             }, 1000);
     22            }, 900);
    2323
    2424            if (window.eventSender)
    25                 eventSender.leapForward(1000);
     25                eventSender.leapForward(900);
    2626        }
    2727       
  • trunk/LayoutTests/fast/events/popup-blocking-timers6-expected.txt

    r206777 r244823  
    11Click Here
    2 Test calling window.open() with a 1001 ms delay. A popup should not be allowed.
     2Test calling window.open() with a 1100 ms delay. A popup should not be allowed.
    33PASS newWindow is null
    44
  • trunk/LayoutTests/fast/events/popup-blocking-timers6.html

    r206777 r244823  
    1616                newWindow = window.open("about:blank");
    1717                self.focus();
    18                 debug("Test calling window.open() with a 1001 ms delay. A popup should not be allowed.")
     18                debug("Test calling window.open() with a 1100 ms delay. A popup should not be allowed.")
    1919                shouldBeNull("newWindow");
    2020
    2121                if (window.testRunner)
    2222                    testRunner.notifyDone();
    23             }, 1001);
     23            }, 1100);
    2424            if (window.eventSender)
    25                 eventSender.leapForward(1001);
     25                eventSender.leapForward(1100);
    2626        }
    2727       
  • trunk/Source/WebCore/ChangeLog

    r244821 r244823  
     12019-05-01  Eric Carlson  <eric.carlson@apple.com>
     2
     3        XMLHttpRequest should propagate user gestures for media playback
     4        https://bugs.webkit.org/show_bug.cgi?id=197428
     5        <rdar://problem/46677392>
     6
     7        Reviewed by Jer Noble.
     8
     9        A user gesture the would allow media state change in effect when XMLHttpRequest.send is
     10        called should be active when the event handlers fire after the transaction completes successfully.
     11
     12        Test: http/tests/media/user-gesture-preserved-across-xmlhttprequest.html
     13
     14        * dom/UserGestureIndicator.cpp:
     15        (WebCore::UserGestureIndicator::UserGestureIndicator): Add a 'scope' parameter to potentially
     16        limit the scope of the gesture to just media.
     17        (WebCore::UserGestureIndicator::~UserGestureIndicator): Clear the scope.
     18        * dom/UserGestureIndicator.h:
     19        (WebCore::UserGestureToken::processingUserGesture const):
     20        (WebCore::UserGestureToken::setScope):
     21        (WebCore::UserGestureToken::resetScope):
     22        (WebCore::UserGestureToken::hasExpired const):
     23
     24        * page/DOMTimer.cpp:
     25        (WebCore::DOMTimerFireState::DOMTimerFireState): Don't need to store the nested timer interval,
     26        UserGestureIndicator knows when it started.
     27        (WebCore::DOMTimer::DOMTimer): Ditto.
     28        (WebCore::DOMTimer::fired): Ditto.
     29        (WebCore::DOMTimerFireState::nestedTimerInterval const): Deleted.
     30        (WebCore::shouldForwardUserGesture): Deleted.
     31        (WebCore::userGestureTokenToForward): Deleted.
     32        (WebCore::currentNestedTimerInterval): Deleted.
     33        * page/DOMTimer.h:
     34
     35        * testing/Internals.cpp:
     36        (WebCore::Internals::setXHRMaximumIntervalForUserGestureForwarding): Override the maximum
     37        user gesture interval for testing.
     38        * testing/Internals.h:
     39        * testing/Internals.idl:
     40
     41        * xml/XMLHttpRequest.cpp:
     42        (WebCore::XMLHttpRequest::XMLHttpRequest):
     43        (WebCore::XMLHttpRequest::send): Stash the user gesture token.
     44        (WebCore::XMLHttpRequest::dispatchEvent): Clear user gesture token if it has expired. If still
     45        valid, activate it.
     46        * xml/XMLHttpRequest.h:
     47
    1482019-04-29  Darin Adler  <darin@apple.com>
    249
  • trunk/Source/WebCore/dom/UserGestureIndicator.cpp

    r242776 r244823  
    7171}
    7272
    73 UserGestureIndicator::UserGestureIndicator(RefPtr<UserGestureToken> token)
     73UserGestureIndicator::UserGestureIndicator(RefPtr<UserGestureToken> token, UserGestureToken::GestureScope scope)
    7474{
    7575    // Silently ignore UserGestureIndicators on non main threads.
     
    8080    m_previousToken = currentToken();
    8181
    82     if (token)
     82    if (token) {
     83        token->setScope(scope);
    8384        currentToken() = token;
     85    }
    8486}
    8587
     
    8991        return;
    9092   
    91     if (auto token = currentToken())
     93    if (auto token = currentToken()) {
    9294        token->resetDOMPasteAccess();
     95        token->resetScope();
     96    }
    9397
    9498    currentToken() = m_previousToken;
  • trunk/Source/WebCore/dom/UserGestureIndicator.h

    r242776 r244823  
    2828#include "DOMPasteAccess.h"
    2929#include <wtf/Function.h>
     30#include <wtf/MonotonicTime.h>
    3031#include <wtf/Noncopyable.h>
    3132#include <wtf/RefCounted.h>
     
    5455
    5556    ProcessingUserGestureState state() const { return m_state; }
    56     bool processingUserGesture() const { return m_state == ProcessingUserGesture; }
     57    bool processingUserGesture() const { return m_scope == GestureScope::All && m_state == ProcessingUserGesture; }
    5758    bool processingUserGestureForMedia() const { return m_state == ProcessingUserGesture || m_state == ProcessingPotentialUserGesture; }
    5859    UserGestureType gestureType() const { return m_gestureType; }
     
    7980    void resetDOMPasteAccess() { m_domPasteAccessPolicy = DOMPasteAccessPolicy::NotRequestedYet; }
    8081
     82    enum class GestureScope { All, MediaOnly };
     83    void setScope(GestureScope scope) { m_scope = scope; }
     84    void resetScope() { m_scope = GestureScope::All; }
     85
     86    bool hasExpired(Seconds expirationInterval) const
     87    {
     88        return m_startTime + expirationInterval < MonotonicTime::now();
     89    }
     90
    8191private:
    8292    UserGestureToken(ProcessingUserGestureState state, UserGestureType gestureType)
     
    90100    UserGestureType m_gestureType;
    91101    DOMPasteAccessPolicy m_domPasteAccessPolicy { DOMPasteAccessPolicy::NotRequestedYet };
     102    GestureScope m_scope { GestureScope::All };
     103    MonotonicTime m_startTime { MonotonicTime::now() };
    92104};
    93105
     
    104116    enum class ProcessInteractionStyle { Immediate, Delayed };
    105117    WEBCORE_EXPORT explicit UserGestureIndicator(Optional<ProcessingUserGestureState>, Document* = nullptr, UserGestureType = UserGestureType::Other, ProcessInteractionStyle = ProcessInteractionStyle::Immediate);
    106     WEBCORE_EXPORT explicit UserGestureIndicator(RefPtr<UserGestureToken>);
     118    WEBCORE_EXPORT explicit UserGestureIndicator(RefPtr<UserGestureToken>, UserGestureToken::GestureScope = UserGestureToken::GestureScope::All);
    107119    WEBCORE_EXPORT ~UserGestureIndicator();
    108120
  • trunk/Source/WebCore/page/DOMTimer.cpp

    r242340 r244823  
    5454class DOMTimerFireState {
    5555public:
    56     DOMTimerFireState(ScriptExecutionContext& context, int nestingLevel, const Seconds& nestedTimerInterval)
     56    DOMTimerFireState(ScriptExecutionContext& context, int nestingLevel)
    5757        : m_context(context)
    58         , m_nestedTimerInterval(nestedTimerInterval)
    5958        , m_contextIsDocument(is<Document>(m_context))
    6059    {
     
    7978    Document* contextDocument() const { return m_contextIsDocument ? &downcast<Document>(m_context) : nullptr; }
    8079
    81     const Seconds& nestedTimerInterval() const { return m_nestedTimerInterval; }
    82 
    8380    void setScriptMadeUserObservableChanges() { m_scriptMadeUserObservableChanges = true; }
    8481    void setScriptMadeNonUserObservableChanges() { m_scriptMadeNonUserObservableChanges = true; }
     
    9996private:
    10097    ScriptExecutionContext& m_context;
    101     Seconds m_nestedTimerInterval;
    10298    uint64_t m_initialDOMTreeVersion;
    10399    DOMTimerFireState* m_previous;
     
    163159
    164160bool NestedTimersMap::isTrackingNestedTimers = false;
    165 
    166 static inline bool shouldForwardUserGesture(Seconds interval)
    167 {
    168     return UserGestureIndicator::processingUserGesture()
    169         && interval <= maxIntervalForUserGestureForwarding;
    170 }
    171 
    172 static inline RefPtr<UserGestureToken> userGestureTokenToForward(Seconds interval)
    173 {
    174     if (!shouldForwardUserGesture(interval))
    175         return nullptr;
    176 
    177     return UserGestureIndicator::currentUserGesture();
    178 }
    179 
    180 static inline Seconds currentNestedTimerInterval()
    181 {
    182     if (DOMTimerFireState::current)
    183         return DOMTimerFireState::current->nestedTimerInterval();
    184     return { };
    185 }
    186161
    187162DOMTimer::DOMTimer(ScriptExecutionContext& context, std::unique_ptr<ScheduledAction> action, Seconds interval, bool singleShot)
     
    192167    , m_throttleState(Undetermined)
    193168    , m_currentTimerInterval(intervalClampedToMinimum())
    194     , m_nestedTimerInterval(currentNestedTimerInterval())
    195     , m_userGestureTokenToForward(userGestureTokenToForward(m_nestedTimerInterval + m_currentTimerInterval))
     169    , m_userGestureTokenToForward(UserGestureIndicator::currentUserGesture())
    196170{
    197171    RefPtr<DOMTimer> reference = adoptRef(this);
     
    311285    ScriptExecutionContext& context = *scriptExecutionContext();
    312286
    313     DOMTimerFireState fireState(context, std::min(m_nestingLevel + 1, maxTimerNestingLevel), m_nestedTimerInterval + m_currentTimerInterval);
     287    DOMTimerFireState fireState(context, std::min(m_nestingLevel + 1, maxTimerNestingLevel));
     288
     289    if (m_userGestureTokenToForward && m_userGestureTokenToForward->hasExpired(maxIntervalForUserGestureForwarding))
     290        m_userGestureTokenToForward = nullptr;
    314291
    315292    ASSERT(!isSuspended());
  • trunk/Source/WebCore/page/DOMTimer.h

    r239427 r244823  
    9393    TimerThrottleState m_throttleState;
    9494    Seconds m_currentTimerInterval;
    95     Seconds m_nestedTimerInterval;
    9695    RefPtr<UserGestureToken> m_userGestureTokenToForward;
    9796};
  • trunk/Source/WebCore/testing/Internals.cpp

    r244749 r244823  
    50335033}
    50345034
     5035void Internals::setXHRMaximumIntervalForUserGestureForwarding(XMLHttpRequest& request, double interval)
     5036{
     5037    request.setMaximumIntervalForUserGestureForwarding(interval);
     5038}
     5039
    50355040} // namespace WebCore
  • trunk/Source/WebCore/testing/Internals.h

    r244749 r244823  
    817817
    818818    void testDictionaryLogging();
    819        
     819
     820    void setXHRMaximumIntervalForUserGestureForwarding(XMLHttpRequest&, double);
     821
    820822private:
    821823    explicit Internals(Document&);
  • trunk/Source/WebCore/testing/Internals.idl

    r244749 r244823  
    748748
    749749    void testDictionaryLogging();
    750 };
     750
     751    void setXHRMaximumIntervalForUserGestureForwarding(XMLHttpRequest xhr, double interval);
     752};
  • trunk/Source/WebCore/xml/XMLHttpRequest.cpp

    r244617 r244823  
    6767namespace WebCore {
    6868
     69static const Seconds maximumIntervalForUserGestureForwarding { 10_s };
     70
    6971WTF_MAKE_ISO_ALLOCATED_IMPL(XMLHttpRequest);
    7072
     
    122124    , m_networkErrorTimer(*this, &XMLHttpRequest::networkErrorTimerFired)
    123125    , m_timeoutTimer(*this, &XMLHttpRequest::didReachTimeout)
     126    , m_maximumIntervalForUserGestureForwarding(maximumIntervalForUserGestureForwarding)
    124127{
    125128#ifndef NDEBUG
     
    437440{
    438441    InspectorInstrumentation::willSendXMLHttpRequest(scriptExecutionContext(), url());
     442    m_userGestureToken = UserGestureIndicator::currentUserGesture();
    439443
    440444    ExceptionOr<void> result;
     
    10901094}
    10911095
     1096void XMLHttpRequest::dispatchEvent(Event& event)
     1097{
     1098    if (m_userGestureToken && m_userGestureToken->hasExpired(m_maximumIntervalForUserGestureForwarding))
     1099        m_userGestureToken = nullptr;
     1100
     1101    if (readyState() != DONE || !m_userGestureToken || !m_userGestureToken->processingUserGesture()) {
     1102        EventTarget::dispatchEvent(event);
     1103        return;
     1104    }
     1105
     1106    UserGestureIndicator gestureIndicator(m_userGestureToken, UserGestureToken::GestureScope::MediaOnly);
     1107    EventTarget::dispatchEvent(event);
     1108}
     1109
    10921110void XMLHttpRequest::dispatchErrorEvents(const AtomicString& type)
    10931111{
     
    11891207}
    11901208
     1209void XMLHttpRequest::setMaximumIntervalForUserGestureForwarding(double interval)
     1210{
     1211    m_maximumIntervalForUserGestureForwarding = Seconds(interval);   
     1212}
     1213
    11911214} // namespace WebCore
  • trunk/Source/WebCore/xml/XMLHttpRequest.h

    r244377 r244823  
    2727#include "ResourceResponse.h"
    2828#include "ThreadableLoaderClient.h"
     29#include "UserGestureIndicator.h"
    2930#include <wtf/URL.h>
    3031#include "XMLHttpRequestEventTarget.h"
     
    128129    size_t memoryCost() const;
    129130
     131    WEBCORE_EXPORT void setMaximumIntervalForUserGestureForwarding(double);
     132
    130133private:
    131134    explicit XMLHttpRequest(ScriptExecutionContext&);
     
    187190
    188191    void dispatchErrorEvents(const AtomicString&);
     192
     193    using EventTarget::dispatchEvent;
     194    void dispatchEvent(Event&) override;
    189195
    190196    void resumeTimerFired();
     
    244250
    245251    Optional<ExceptionCode> m_exceptionCode;
     252    RefPtr<UserGestureToken> m_userGestureToken;
     253    Seconds m_maximumIntervalForUserGestureForwarding;
    246254};
    247255
Note: See TracChangeset for help on using the changeset viewer.