Title: [281503] trunk
Revision
281503
Author
[email protected]
Date
2021-08-24 11:30:02 -0700 (Tue, 24 Aug 2021)

Log Message

Source/WebCore:
Add support for new pseudo-classes for media from CSS Selectors Level 4.
https://bugs.webkit.org/show_bug.cgi?id=229431

Reviewed by Eric Carlson.

Tests: media/media-css-muted.html
       media/media-css-playing-paused.html
       media/media-css-volume-locked.html
       (Tests for buffering and stalled states are forthcoming, waiting on
       a non-flakey mechanism for inducing network stalls)

Add support for the following new pseudo-classes from CSS Selectors Level 4:
- :playing, :paused, :seeking
- :buffering, :stalled
- :muted, :volume-locked

Ensure CSS styles are invalidated when playback state changes by encapsulating
modifications to HTMLMediaElement::m_paused into a setPaused() function.

Add methods to query for volumeLocked() on HTMLMediaElement, as well as a way
to override the value through Internals.

Invalidate styles when the "muted" attribute changes state.

* css/CSSSelector.cpp:
(WebCore::CSSSelector::selectorText const):
* css/CSSSelector.h:
* css/SelectorChecker.cpp:
(WebCore::SelectorChecker::checkOne const):
* css/SelectorCheckerTestFunctions.h:
(WebCore::matchesPlayingPseudoClass):
(WebCore::matchesPausedPseudoClass):
(WebCore::matchesSeekingPseudoClass):
(WebCore::matchesBufferingPseudoClass):
(WebCore::matchesStalledPseudoClass):
(WebCore::matchesMutedPseudoClass):
(WebCore::matchesVolumeLockedPseudoClass):
* css/SelectorPseudoClassAndCompatibilityElementMap.in:
* cssjit/SelectorCompiler.cpp:
(WebCore::SelectorCompiler::JSC_DEFINE_JIT_OPERATION):
(WebCore::SelectorCompiler::addPseudoClassType):
* html/HTMLMediaElement.cpp:
(WebCore::defaultVolumeLocked):
(WebCore::HTMLMediaElement::HTMLMediaElement):
(WebCore::HTMLMediaElement::parseAttribute):
(WebCore::HTMLMediaElement::prepareForLoad):
(WebCore::HTMLMediaElement::setNetworkState):
(WebCore::HTMLMediaElement::setReadyState):
(WebCore::HTMLMediaElement::setPaused):
(WebCore::HTMLMediaElement::playInternal):
(WebCore::HTMLMediaElement::pauseInternal):
(WebCore::HTMLMediaElement::setMuted):
(WebCore::HTMLMediaElement::setVolumeLocked):
(WebCore::HTMLMediaElement::buffering const):
(WebCore::HTMLMediaElement::stalled const):
(WebCore::HTMLMediaElement::mediaPlayerTimeChanged):
* html/HTMLMediaElement.h:
(WebCore::HTMLMediaElement::volumeLocked const):
* testing/Internals.cpp:
(WebCore::Internals::setMediaElementVolumeLocked):
* testing/Internals.h:
* testing/Internals.idl:

LayoutTests:
Add support for new pseudo-selectors for media from CSS Selectors Level 4.
https://bugs.webkit.org/show_bug.cgi?id=229431

Reviewed by Eric Carlson.

* media/media-css-muted-expected.txt: Added.
* media/media-css-muted.html: Added.
* media/media-css-playing-paused-expected.txt: Added.
* media/media-css-playing-paused.html: Added.
* media/media-css-volume-locked-expected.txt: Added.
* media/media-css-volume-locked.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (281502 => 281503)


--- trunk/LayoutTests/ChangeLog	2021-08-24 18:18:22 UTC (rev 281502)
+++ trunk/LayoutTests/ChangeLog	2021-08-24 18:30:02 UTC (rev 281503)
@@ -1,3 +1,17 @@
+2021-08-24  Jer Noble  <[email protected]>
+
+        Add support for new pseudo-selectors for media from CSS Selectors Level 4.
+        https://bugs.webkit.org/show_bug.cgi?id=229431
+
+        Reviewed by Eric Carlson.
+
+        * media/media-css-muted-expected.txt: Added.
+        * media/media-css-muted.html: Added.
+        * media/media-css-playing-paused-expected.txt: Added.
+        * media/media-css-playing-paused.html: Added.
+        * media/media-css-volume-locked-expected.txt: Added.
+        * media/media-css-volume-locked.html: Added.
+
 2021-08-24  Eric Hutchison  <[email protected]>
 
         [BigSur wk2 Debug x86] http/tests/inspector/network/resource-timing.html is a flaky failure.

Added: trunk/LayoutTests/media/media-css-muted-expected.txt (0 => 281503)


--- trunk/LayoutTests/media/media-css-muted-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/media/media-css-muted-expected.txt	2021-08-24 18:30:02 UTC (rev 281503)
@@ -0,0 +1,11 @@
+
+RUN(video.src = "" "content/test"))
+EVENT(canplay)
+EXPECTED (video.muted == 'false') OK
+EXPECTED (document.querySelector("video:muted") == 'null') OK
+EXPECTED (document.querySelector("video:not(:muted)") == '[object HTMLVideoElement]') OK
+RUN(video.muted = true)
+EXPECTED (document.querySelector("video:muted") == '[object HTMLVideoElement]') OK
+EXPECTED (document.querySelector("video:not(:muted)") == 'null') OK
+END OF TEST
+

Added: trunk/LayoutTests/media/media-css-muted.html (0 => 281503)


--- trunk/LayoutTests/media/media-css-muted.html	                        (rev 0)
+++ trunk/LayoutTests/media/media-css-muted.html	2021-08-24 18:30:02 UTC (rev 281503)
@@ -0,0 +1,25 @@
+<!doctype HTML>
+<html>
+<head>
+    <title>media-css-muted</title>
+    <script src=""
+    <script src=""
+    <script>
+    window.addEventListener('load', async event => {
+        findMediaElement();
+        run('video.src = "" "content/test")');
+        await waitFor(video, 'canplay');
+        testExpected('video.muted', false);
+        testExpected('document.querySelector("video:muted")', null);
+        testExpected('document.querySelector("video:not(:muted)")', video);
+        run('video.muted = true');
+        testExpected('document.querySelector("video:muted")', video);
+        testExpected('document.querySelector("video:not(:muted)")', null);
+        endTest();
+    });
+    </script>
+<head>
+<body>
+    <video></video>
+</body>
+</html>

Added: trunk/LayoutTests/media/media-css-playing-paused-expected.txt (0 => 281503)


--- trunk/LayoutTests/media/media-css-playing-paused-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/media/media-css-playing-paused-expected.txt	2021-08-24 18:30:02 UTC (rev 281503)
@@ -0,0 +1,16 @@
+
+RUN(video.src = "" "content/test"))
+EVENT(canplay)
+EXPECTED (video.paused == 'true') OK
+EXPECTED (document.querySelector("video:playing") == 'null') OK
+EXPECTED (document.querySelector("video:not(:playing)") == '[object HTMLVideoElement]') OK
+EXPECTED (document.querySelector("video:paused") == '[object HTMLVideoElement]') OK
+EXPECTED (document.querySelector("video:not(:paused)") == 'null') OK
+RUN(video.play())
+EVENT(playing)
+EXPECTED (document.querySelector("video:playing") == '[object HTMLVideoElement]') OK
+EXPECTED (document.querySelector("video:not(:playing)") == 'null') OK
+EXPECTED (document.querySelector("video:paused") == 'null') OK
+EXPECTED (document.querySelector("video:not(:paused)") == '[object HTMLVideoElement]') OK
+END OF TEST
+

Added: trunk/LayoutTests/media/media-css-playing-paused.html (0 => 281503)


--- trunk/LayoutTests/media/media-css-playing-paused.html	                        (rev 0)
+++ trunk/LayoutTests/media/media-css-playing-paused.html	2021-08-24 18:30:02 UTC (rev 281503)
@@ -0,0 +1,30 @@
+<!doctype HTML>
+<html>
+<head>
+    <title>media-css-playing-paused</title>
+    <script src=""
+    <script src=""
+    <script>
+    window.addEventListener('load', async event => {
+        findMediaElement();
+        run('video.src = "" "content/test")');
+        await waitFor(video, 'canplay');
+        testExpected('video.paused', true);
+        testExpected('document.querySelector("video:playing")', null);
+        testExpected('document.querySelector("video:not(:playing)")', video);
+        testExpected('document.querySelector("video:paused")', video);
+        testExpected('document.querySelector("video:not(:paused)")', null);
+        run('video.play()');
+        await waitFor(video, 'playing');
+        testExpected('document.querySelector("video:playing")', video);
+        testExpected('document.querySelector("video:not(:playing)")', null);
+        testExpected('document.querySelector("video:paused")', null);
+        testExpected('document.querySelector("video:not(:paused)")', video);
+        endTest();
+    });
+    </script>
+<head>
+<body>
+    <video loop></video>
+</body>
+</html>

Added: trunk/LayoutTests/media/media-css-volume-locked-expected.txt (0 => 281503)


--- trunk/LayoutTests/media/media-css-volume-locked-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/media/media-css-volume-locked-expected.txt	2021-08-24 18:30:02 UTC (rev 281503)
@@ -0,0 +1,11 @@
+
+RUN(video.src = "" "content/test"))
+EVENT(canplay)
+RUN(internals.setMediaElementVolumeLocked(video, false))
+EXPECTED (document.querySelector("video:volume-locked") == 'null') OK
+EXPECTED (document.querySelector("video:not(:volume-locked)") == '[object HTMLVideoElement]') OK
+RUN(internals.setMediaElementVolumeLocked(video, true))
+EXPECTED (document.querySelector("video:volume-locked") == '[object HTMLVideoElement]') OK
+EXPECTED (document.querySelector("video:not(:volume-locked)") == 'null') OK
+END OF TEST
+

Added: trunk/LayoutTests/media/media-css-volume-locked.html (0 => 281503)


--- trunk/LayoutTests/media/media-css-volume-locked.html	                        (rev 0)
+++ trunk/LayoutTests/media/media-css-volume-locked.html	2021-08-24 18:30:02 UTC (rev 281503)
@@ -0,0 +1,25 @@
+<!doctype HTML>
+<html>
+<head>
+    <title>media-css-muted</title>
+    <script src=""
+    <script src=""
+    <script>
+    window.addEventListener('load', async event => {
+        findMediaElement();
+        run('video.src = "" "content/test")');
+        await waitFor(video, 'canplay');
+        run('internals.setMediaElementVolumeLocked(video, false)');
+        testExpected('document.querySelector("video:volume-locked")', null);
+        testExpected('document.querySelector("video:not(:volume-locked)")', video);
+        run('internals.setMediaElementVolumeLocked(video, true)');
+        testExpected('document.querySelector("video:volume-locked")', video);
+        testExpected('document.querySelector("video:not(:volume-locked)")', null);
+        endTest();
+    });
+    </script>
+<head>
+<body>
+    <video></video>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (281502 => 281503)


--- trunk/Source/WebCore/ChangeLog	2021-08-24 18:18:22 UTC (rev 281502)
+++ trunk/Source/WebCore/ChangeLog	2021-08-24 18:30:02 UTC (rev 281503)
@@ -1,3 +1,68 @@
+2021-08-24  Jer Noble  <[email protected]>
+
+        Add support for new pseudo-classes for media from CSS Selectors Level 4.
+        https://bugs.webkit.org/show_bug.cgi?id=229431
+
+        Reviewed by Eric Carlson.
+
+        Tests: media/media-css-muted.html
+               media/media-css-playing-paused.html
+               media/media-css-volume-locked.html
+               (Tests for buffering and stalled states are forthcoming, waiting on
+               a non-flakey mechanism for inducing network stalls)
+
+        Add support for the following new pseudo-classes from CSS Selectors Level 4:
+        - :playing, :paused, :seeking
+        - :buffering, :stalled
+        - :muted, :volume-locked
+
+        Ensure CSS styles are invalidated when playback state changes by encapsulating
+        modifications to HTMLMediaElement::m_paused into a setPaused() function.
+
+        Add methods to query for volumeLocked() on HTMLMediaElement, as well as a way
+        to override the value through Internals.
+
+        Invalidate styles when the "muted" attribute changes state.
+
+        * css/CSSSelector.cpp:
+        (WebCore::CSSSelector::selectorText const):
+        * css/CSSSelector.h:
+        * css/SelectorChecker.cpp:
+        (WebCore::SelectorChecker::checkOne const):
+        * css/SelectorCheckerTestFunctions.h:
+        (WebCore::matchesPlayingPseudoClass):
+        (WebCore::matchesPausedPseudoClass):
+        (WebCore::matchesSeekingPseudoClass):
+        (WebCore::matchesBufferingPseudoClass):
+        (WebCore::matchesStalledPseudoClass):
+        (WebCore::matchesMutedPseudoClass):
+        (WebCore::matchesVolumeLockedPseudoClass):
+        * css/SelectorPseudoClassAndCompatibilityElementMap.in:
+        * cssjit/SelectorCompiler.cpp:
+        (WebCore::SelectorCompiler::JSC_DEFINE_JIT_OPERATION):
+        (WebCore::SelectorCompiler::addPseudoClassType):
+        * html/HTMLMediaElement.cpp:
+        (WebCore::defaultVolumeLocked):
+        (WebCore::HTMLMediaElement::HTMLMediaElement):
+        (WebCore::HTMLMediaElement::parseAttribute):
+        (WebCore::HTMLMediaElement::prepareForLoad):
+        (WebCore::HTMLMediaElement::setNetworkState):
+        (WebCore::HTMLMediaElement::setReadyState):
+        (WebCore::HTMLMediaElement::setPaused):
+        (WebCore::HTMLMediaElement::playInternal):
+        (WebCore::HTMLMediaElement::pauseInternal):
+        (WebCore::HTMLMediaElement::setMuted):
+        (WebCore::HTMLMediaElement::setVolumeLocked):
+        (WebCore::HTMLMediaElement::buffering const):
+        (WebCore::HTMLMediaElement::stalled const):
+        (WebCore::HTMLMediaElement::mediaPlayerTimeChanged):
+        * html/HTMLMediaElement.h:
+        (WebCore::HTMLMediaElement::volumeLocked const):
+        * testing/Internals.cpp:
+        (WebCore::Internals::setMediaElementVolumeLocked):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
 2021-08-24  Chris Dumez  <[email protected]>
 
         Fire a load event for <iframe src=""

Modified: trunk/Source/WebCore/css/CSSSelector.cpp (281502 => 281503)


--- trunk/Source/WebCore/css/CSSSelector.cpp	2021-08-24 18:18:22 UTC (rev 281502)
+++ trunk/Source/WebCore/css/CSSSelector.cpp	2021-08-24 18:30:02 UTC (rev 281503)
@@ -507,6 +507,27 @@
             case CSSSelector::PseudoClassFuture:
                 builder.append(":future");
                 break;
+            case CSSSelector::PseudoClassPlaying:
+                builder.append(":playing");
+                break;
+            case CSSSelector::PseudoClassPaused:
+                builder.append(":paused");
+                break;
+            case CSSSelector::PseudoClassSeeking:
+                builder.append(":seeking");
+                break;
+            case CSSSelector::PseudoClassBuffering:
+                builder.append(":buffering");
+                break;
+            case CSSSelector::PseudoClassStalled:
+                builder.append(":stalled");
+                break;
+            case CSSSelector::PseudoClassMuted:
+                builder.append(":muted");
+                break;
+            case CSSSelector::PseudoClassVolumeLocked:
+                builder.append(":volume-locked");
+                break;
 #endif
             case CSSSelector::PseudoClassHas:
                 builder.append(":has(");

Modified: trunk/Source/WebCore/css/CSSSelector.h (281502 => 281503)


--- trunk/Source/WebCore/css/CSSSelector.h	2021-08-24 18:18:22 UTC (rev 281502)
+++ trunk/Source/WebCore/css/CSSSelector.h	2021-08-24 18:30:02 UTC (rev 281503)
@@ -166,6 +166,13 @@
 #if ENABLE(VIDEO)
             PseudoClassFuture,
             PseudoClassPast,
+            PseudoClassPlaying,
+            PseudoClassPaused,
+            PseudoClassSeeking,
+            PseudoClassBuffering,
+            PseudoClassStalled,
+            PseudoClassMuted,
+            PseudoClassVolumeLocked,
 #endif
 #if ENABLE(CSS_SELECTORS_LEVEL4)
             PseudoClassDir,

Modified: trunk/Source/WebCore/css/SelectorChecker.cpp (281502 => 281503)


--- trunk/Source/WebCore/css/SelectorChecker.cpp	2021-08-24 18:18:22 UTC (rev 281502)
+++ trunk/Source/WebCore/css/SelectorChecker.cpp	2021-08-24 18:30:02 UTC (rev 281503)
@@ -1063,6 +1063,20 @@
             return matchesFutureCuePseudoClass(element);
         case CSSSelector::PseudoClassPast:
             return matchesPastCuePseudoClass(element);
+        case CSSSelector::PseudoClassPlaying:
+            return matchesPlayingPseudoClass(element);
+        case CSSSelector::PseudoClassPaused:
+            return matchesPausedPseudoClass(element);
+        case CSSSelector::PseudoClassSeeking:
+            return matchesSeekingPseudoClass(element);
+        case CSSSelector::PseudoClassBuffering:
+            return matchesBufferingPseudoClass(element);
+        case CSSSelector::PseudoClassStalled:
+            return matchesStalledPseudoClass(element);
+        case CSSSelector::PseudoClassMuted:
+            return matchesMutedPseudoClass(element);
+        case CSSSelector::PseudoClassVolumeLocked:
+            return matchesVolumeLockedPseudoClass(element);
 #endif
 
         case CSSSelector::PseudoClassScope:

Modified: trunk/Source/WebCore/css/SelectorCheckerTestFunctions.h (281502 => 281503)


--- trunk/Source/WebCore/css/SelectorCheckerTestFunctions.h	2021-08-24 18:18:22 UTC (rev 281502)
+++ trunk/Source/WebCore/css/SelectorCheckerTestFunctions.h	2021-08-24 18:30:02 UTC (rev 281503)
@@ -47,6 +47,7 @@
 #endif
 
 #if ENABLE(VIDEO)
+#include "HTMLMediaElement.h"
 #include "WebVTTElement.h"
 #endif
 
@@ -442,6 +443,40 @@
     return is<WebVTTElement>(element) && downcast<WebVTTElement>(element).isPastNode();
 }
 
+ALWAYS_INLINE bool matchesPlayingPseudoClass(const Element& element)
+{
+    return is<HTMLMediaElement>(element) && !downcast<HTMLMediaElement>(element).paused();
+}
+
+ALWAYS_INLINE bool matchesPausedPseudoClass(const Element& element)
+{
+    return is<HTMLMediaElement>(element) && downcast<HTMLMediaElement>(element).paused();
+}
+
+ALWAYS_INLINE bool matchesSeekingPseudoClass(const Element& element)
+{
+    return is<HTMLMediaElement>(element) && downcast<HTMLMediaElement>(element).seeking();
+}
+
+ALWAYS_INLINE bool matchesBufferingPseudoClass(const Element& element)
+{
+    return is<HTMLMediaElement>(element) && downcast<HTMLMediaElement>(element).buffering();
+}
+
+ALWAYS_INLINE bool matchesStalledPseudoClass(const Element& element)
+{
+    return is<HTMLMediaElement>(element) && downcast<HTMLMediaElement>(element).stalled();
+}
+
+ALWAYS_INLINE bool matchesMutedPseudoClass(const Element& element)
+{
+    return is<HTMLMediaElement>(element) && downcast<HTMLMediaElement>(element).muted();
+}
+
+ALWAYS_INLINE bool matchesVolumeLockedPseudoClass(const Element& element)
+{
+    return is<HTMLMediaElement>(element) && downcast<HTMLMediaElement>(element).volumeLocked();
+}
 #endif
 
 ALWAYS_INLINE bool isFrameFocused(const Element& element)

Modified: trunk/Source/WebCore/css/SelectorPseudoClassAndCompatibilityElementMap.in (281502 => 281503)


--- trunk/Source/WebCore/css/SelectorPseudoClassAndCompatibilityElementMap.in	2021-08-24 18:18:22 UTC (rev 281502)
+++ trunk/Source/WebCore/css/SelectorPseudoClassAndCompatibilityElementMap.in	2021-08-24 18:30:02 UTC (rev 281503)
@@ -93,5 +93,12 @@
 #if ENABLE(VIDEO)
 future
 past
+playing
+paused
+seeking
+buffering
+stalled
+muted
+volume-locked
 #endif
 

Modified: trunk/Source/WebCore/cssjit/SelectorCompiler.cpp (281502 => 281503)


--- trunk/Source/WebCore/cssjit/SelectorCompiler.cpp	2021-08-24 18:18:22 UTC (rev 281502)
+++ trunk/Source/WebCore/cssjit/SelectorCompiler.cpp	2021-08-24 18:30:02 UTC (rev 281503)
@@ -111,6 +111,13 @@
 #if ENABLE(VIDEO)
 static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(operationMatchesFutureCuePseudoClass, bool, (const Element&));
 static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(operationMatchesPastCuePseudoClass, bool, (const Element&));
+static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(operationMatchesPlayingPseudoClass, bool, (const Element&));
+static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(operationMatchesPausedPseudoClass, bool, (const Element&));
+static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(operationMatchesSeekingPseudoClass, bool, (const Element&));
+static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(operationMatchesBufferingPseudoClass, bool, (const Element&));
+static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(operationMatchesStalledPseudoClass, bool, (const Element&));
+static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(operationMatchesMutedPseudoClass, bool, (const Element&));
+static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(operationMatchesVolumeLockedPseudoClass, bool, (const Element&));
 #endif
 #if ENABLE(ATTACHMENT_ELEMENT)
 static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(operationHasAttachment, bool, (const Element&));
@@ -741,6 +748,41 @@
 {
     return matchesPastCuePseudoClass(element);
 }
+
+JSC_DEFINE_JIT_OPERATION(operationMatchesPlayingPseudoClass, bool, (const Element& element))
+{
+    return matchesPlayingPseudoClass(element);
+}
+
+JSC_DEFINE_JIT_OPERATION(operationMatchesPausedPseudoClass, bool, (const Element& element))
+{
+    return matchesPausedPseudoClass(element);
+}
+
+JSC_DEFINE_JIT_OPERATION(operationMatchesSeekingPseudoClass, bool, (const Element& element))
+{
+    return matchesSeekingPseudoClass(element);
+}
+
+JSC_DEFINE_JIT_OPERATION(operationMatchesBufferingPseudoClass, bool, (const Element& element))
+{
+    return matchesBufferingPseudoClass(element);
+}
+
+JSC_DEFINE_JIT_OPERATION(operationMatchesStalledPseudoClass, bool, (const Element& element))
+{
+    return matchesStalledPseudoClass(element);
+}
+
+JSC_DEFINE_JIT_OPERATION(operationMatchesMutedPseudoClass, bool, (const Element& element))
+{
+    return matchesMutedPseudoClass(element);
+}
+
+JSC_DEFINE_JIT_OPERATION(operationMatchesVolumeLockedPseudoClass, bool, (const Element& element))
+{
+    return matchesVolumeLockedPseudoClass(element);
+}
 #endif
 
 #if ENABLE(ATTACHMENT_ELEMENT)
@@ -867,6 +909,27 @@
     case CSSSelector::PseudoClassPast:
         fragment.unoptimizedPseudoClasses.append(JSC::FunctionPtr<JSC::OperationPtrTag>(operationMatchesPastCuePseudoClass));
         return FunctionType::SimpleSelectorChecker;
+    case CSSSelector::PseudoClassPlaying:
+        fragment.unoptimizedPseudoClasses.append(JSC::FunctionPtr<JSC::OperationPtrTag>(operationMatchesPlayingPseudoClass));
+        return FunctionType::SimpleSelectorChecker;
+    case CSSSelector::PseudoClassPaused:
+        fragment.unoptimizedPseudoClasses.append(JSC::FunctionPtr<JSC::OperationPtrTag>(operationMatchesPausedPseudoClass));
+        return FunctionType::SimpleSelectorChecker;
+    case CSSSelector::PseudoClassSeeking:
+        fragment.unoptimizedPseudoClasses.append(JSC::FunctionPtr<JSC::OperationPtrTag>(operationMatchesSeekingPseudoClass));
+        return FunctionType::SimpleSelectorChecker;
+    case CSSSelector::PseudoClassBuffering:
+        fragment.unoptimizedPseudoClasses.append(JSC::FunctionPtr<JSC::OperationPtrTag>(operationMatchesBufferingPseudoClass));
+        return FunctionType::SimpleSelectorChecker;
+    case CSSSelector::PseudoClassStalled:
+        fragment.unoptimizedPseudoClasses.append(JSC::FunctionPtr<JSC::OperationPtrTag>(operationMatchesStalledPseudoClass));
+        return FunctionType::SimpleSelectorChecker;
+    case CSSSelector::PseudoClassMuted:
+        fragment.unoptimizedPseudoClasses.append(JSC::FunctionPtr<JSC::OperationPtrTag>(operationMatchesMutedPseudoClass));
+        return FunctionType::SimpleSelectorChecker;
+    case CSSSelector::PseudoClassVolumeLocked:
+        fragment.unoptimizedPseudoClasses.append(JSC::FunctionPtr<JSC::OperationPtrTag>(operationMatchesVolumeLockedPseudoClass));
+        return FunctionType::SimpleSelectorChecker;
 #endif
 
 #if ENABLE(ATTACHMENT_ELEMENT)

Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (281502 => 281503)


--- trunk/Source/WebCore/html/HTMLMediaElement.cpp	2021-08-24 18:18:22 UTC (rev 281502)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp	2021-08-24 18:30:02 UTC (rev 281503)
@@ -392,6 +392,15 @@
     return true;
 }
 
+static bool defaultVolumeLocked()
+{
+#if PLATFORM(IOS)
+    return true;
+#else
+    return false;
+#endif
+}
+
 HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document& document, bool createdByParser)
     : HTMLElement(tagName, document)
     , ActiveDOMObject(document)
@@ -439,6 +448,7 @@
     , m_processingPreferenceChange(false)
     , m_shouldAudioPlaybackRequireUserGesture(document.topDocument().audioPlaybackRequiresUserGesture() && !processingUserGestureForMedia())
     , m_shouldVideoPlaybackRequireUserGesture(document.topDocument().videoPlaybackRequiresUserGesture() && !processingUserGestureForMedia())
+    , m_volumeLocked(defaultVolumeLocked())
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
     , m_remote(RemotePlayback::create(*this))
 #endif
@@ -750,6 +760,10 @@
     }
     else
         HTMLElement::parseAttribute(name, value);
+
+    // Changing the "muted" attribue could affect ":muted"
+    if (name == mutedAttr)
+        invalidateStyle();
 }
 
 void HTMLMediaElement::finishParsingChildren()
@@ -1177,7 +1191,7 @@
         m_readyStateMaximum = HAVE_NOTHING;
 
         // 6.6 - If the paused attribute is false, then set it to true.
-        m_paused = true;
+        setPaused(true);
 
         // 6.7 - If seeking is true, set it to false.
         clearSeeking();
@@ -2243,6 +2257,7 @@
     if (state == MediaPlayer::NetworkState::Empty) {
         // Just update the cached state and leave, we can't do anything.
         m_networkState = NETWORK_EMPTY;
+        invalidateStyle();
         return;
     }
 
@@ -2271,6 +2286,8 @@
             changeNetworkStateFromLoadingToIdle();
         m_completelyLoaded = true;
     }
+
+    invalidateStyle();
 }
 
 void HTMLMediaElement::changeNetworkStateFromLoadingToIdle()
@@ -2489,7 +2506,7 @@
             // Notify about playing for the element.
             auto canTransition = canTransitionFromAutoplayToPlay();
             if (canTransition) {
-                m_paused = false;
+                setPaused(false);
                 setShowPosterFlag(false);
                 invalidateCachedTime();
                 setAutoplayEventPlaybackState(AutoplayEventPlaybackState::StartedWithoutUserGesture);
@@ -2517,6 +2534,8 @@
     updatePlayState();
     updateMediaController();
     updateActiveTextTrackCues(currentMediaTime());
+
+    invalidateStyle();
 }
 
 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
@@ -2857,11 +2876,15 @@
         if (progress) {
             scheduleEvent(eventNames().progressEvent);
             m_previousProgressTime = time;
-            m_sentStalledEvent = false;
+            if (m_sentStalledEvent) {
+                m_sentStalledEvent = false;
+                invalidateStyle();
+            }
             updateRenderer();
         } else if (timedelta > 3_s && !m_sentStalledEvent) {
             scheduleEvent(eventNames().stalledEvent);
             m_sentStalledEvent = true;
+            invalidateStyle();
             setShouldDelayLoadEvent(false);
         }
     });
@@ -3338,6 +3361,14 @@
     return m_paused;
 }
 
+void HTMLMediaElement::setPaused(bool paused)
+{
+    if (m_paused == paused)
+        return;
+    m_paused = paused;
+    invalidateStyle();
+}
+
 double HTMLMediaElement::defaultPlaybackRate() const
 {
 #if ENABLE(MEDIA_STREAM)
@@ -3574,7 +3605,7 @@
         m_mediaController->bringElementUpToSpeed(*this);
 
     if (m_paused) {
-        m_paused = false;
+        setPaused(false);
         setShowPosterFlag(false);
         invalidateCachedTime();
 
@@ -3665,7 +3696,7 @@
     setAutoplayEventPlaybackState(AutoplayEventPlaybackState::None);
 
     if (!m_paused && !m_pausedInternal) {
-        m_paused = true;
+        setPaused(true);
         scheduleTimeupdateEvent(false);
         scheduleEvent(eventNames().pauseEvent);
         scheduleRejectPendingPlayPromises(DOMException::create(AbortError));
@@ -3802,11 +3833,51 @@
 #endif
         mediaSession().canProduceAudioChanged();
         updateSleepDisabling();
+
+        invalidateStyle();
     }
 
     schedulePlaybackControlsManagerUpdate();
 }
 
+void HTMLMediaElement::setVolumeLocked(bool locked)
+{
+    if (m_volumeLocked == locked)
+        return;
+
+    m_volumeLocked = locked;
+    invalidateStyle();
+}
+
+bool HTMLMediaElement::buffering() const
+{
+    // CSS Selectors Level 4; Editor's Draft, 2 July 2021
+    // <https://drafts.csswg.org/selectors/>
+    // 11.2. Media Loading State: the :buffering and :stalled pseudo-classes
+    //
+    // The :buffering pseudo-class represents an element that is capable of being “played” or “paused”,
+    // when that element cannot continue playing because it is actively attempting to obtain media data
+    // but has not yet obtained enough data to resume playback. (Note that the element is still considered
+    // to be “playing” when it is “buffering”. Whenever :buffering matches an element, :playing also
+    // matches the element.)
+    return !paused() && m_networkState == NETWORK_LOADING && m_readyState <= HAVE_CURRENT_DATA;
+}
+
+bool HTMLMediaElement::stalled() const
+{
+    // CSS Selectors Level 4; Editor's Draft, 2 July 2021
+    // <https://drafts.csswg.org/selectors/>
+    // 11.2. Media Loading State: the :buffering and :stalled pseudo-classes
+    //
+    // The :stalled pseudo-class represents an element when that element cannot continue playing because
+    // it is actively attempting to obtain media data but it has failed to receive any data for some
+    // amount of time. For the audio and video elements of HTML, this amount of time is the media element
+    // stall timeout. [HTML] (Note that, like with the :buffering pseudo-class, the element is still
+    // considered to be “playing” when it is “stalled”. Whenever :stalled matches an element, :playing
+    // also matches the element.)
+    return !paused() && m_networkState == NETWORK_LOADING && m_readyState <= HAVE_CURRENT_DATA && m_sentStalledEvent;
+}
+
 #if USE(AUDIO_SESSION) && PLATFORM(MAC)
 void HTMLMediaElement::hardwareMutedStateDidChange(const AudioSession& session)
 {
@@ -4849,7 +4920,7 @@
             // has still ended playback and paused is false,
             if (!m_mediaController && !m_paused) {
                 // changes paused to true and fires a simple event named pause at the media element.
-                m_paused = true;
+                setPaused(true);
                 scheduleEvent(eventNames().pauseEvent);
                 mediaSession().clientWillPausePlayback();
             }
@@ -4883,7 +4954,7 @@
                 scheduleEvent(eventNames().endedEvent);
                 if (!wasSeeking)
                     addBehaviorRestrictionsOnEndIfNecessary();
-                m_paused = true;
+                setPaused(true);
                 setPlaying(false);
             }
         } else

Modified: trunk/Source/WebCore/html/HTMLMediaElement.h (281502 => 281503)


--- trunk/Source/WebCore/html/HTMLMediaElement.h	2021-08-24 18:18:22 UTC (rev 281502)
+++ trunk/Source/WebCore/html/HTMLMediaElement.h	2021-08-24 18:30:02 UTC (rev 281503)
@@ -235,6 +235,7 @@
     WEBCORE_EXPORT double getStartDate() const;
     WEBCORE_EXPORT double duration() const override;
     WEBCORE_EXPORT bool paused() const override;
+    void setPaused(bool);
     double defaultPlaybackRate() const override;
     void setDefaultPlaybackRate(double) override;
     WEBCORE_EXPORT double playbackRate() const override;
@@ -318,6 +319,11 @@
     WEBCORE_EXPORT bool muted() const override;
     WEBCORE_EXPORT void setMuted(bool) override;
 
+    bool volumeLocked() const { return m_volumeLocked; }
+    WEBCORE_EXPORT void setVolumeLocked(bool);
+    bool buffering() const;
+    bool stalled() const;
+
     WEBCORE_EXPORT void togglePlayState();
     WEBCORE_EXPORT void beginScrubbing() override;
     WEBCORE_EXPORT void endScrubbing() override;
@@ -1108,6 +1114,7 @@
     bool m_processingPreferenceChange : 1;
     bool m_shouldAudioPlaybackRequireUserGesture : 1;
     bool m_shouldVideoPlaybackRequireUserGesture : 1;
+    bool m_volumeLocked : 1;
 
     AutoplayEventPlaybackState m_autoplayEventPlaybackState { AutoplayEventPlaybackState::None };
 

Modified: trunk/Source/WebCore/testing/Internals.cpp (281502 => 281503)


--- trunk/Source/WebCore/testing/Internals.cpp	2021-08-24 18:18:22 UTC (rev 281502)
+++ trunk/Source/WebCore/testing/Internals.cpp	2021-08-24 18:30:02 UTC (rev 281503)
@@ -4561,6 +4561,11 @@
 {
     return HTMLMediaElement::allMediaElements().size();
 }
+
+void Internals::setMediaElementVolumeLocked(HTMLMediaElement& element, bool volumeLocked)
+{
+    element.setVolumeLocked(volumeLocked);
+}
 #endif
 
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)

Modified: trunk/Source/WebCore/testing/Internals.h (281502 => 281503)


--- trunk/Source/WebCore/testing/Internals.h	2021-08-24 18:18:22 UTC (rev 281502)
+++ trunk/Source/WebCore/testing/Internals.h	2021-08-24 18:30:02 UTC (rev 281503)
@@ -981,6 +981,8 @@
     MediaSessionState mediaSessionState(HTMLMediaElement&);
 
     size_t mediaElementCount() const;
+
+    void setMediaElementVolumeLocked(HTMLMediaElement&, bool);
 #endif
 
     void setCaptureExtraNetworkLoadMetricsEnabled(bool);

Modified: trunk/Source/WebCore/testing/Internals.idl (281502 => 281503)


--- trunk/Source/WebCore/testing/Internals.idl	2021-08-24 18:18:22 UTC (rev 281502)
+++ trunk/Source/WebCore/testing/Internals.idl	2021-08-24 18:30:02 UTC (rev 281503)
@@ -957,6 +957,7 @@
     [Conditional=VIDEO] MediaUsageState mediaUsageState(HTMLMediaElement element);
     [Conditional=VIDEO] boolean elementShouldDisplayPosterImage(HTMLVideoElement element);
     [Conditional=VIDEO] readonly attribute unsigned long mediaElementCount;
+    [Conditional=VIDEO] undefined setMediaElementVolumeLocked(HTMLMediaElement element, boolean volumeLocked);
 
     DOMString ongoingLoadsDescriptions();
     undefined setCaptureExtraNetworkLoadMetricsEnabled(boolean value);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to