Title: [278497] trunk/Source/WebCore
Revision
278497
Author
da...@apple.com
Date
2021-06-04 14:04:14 -0700 (Fri, 04 Jun 2021)

Log Message

Move from WebCore::SuccessOr to WTF::Expected
https://bugs.webkit.org/show_bug.cgi?id=226614

Reviewed by Sam Weinig.

The upcoming std::expected is designed for cases like the ones we
are using SuccessOr for, using void for the expected type in a case like
this where it's success or failure. Our WTF::Expected is for our use
while waiting for compilers with std::expected. It was straightforward
to port our uses of SuccessOr to instead use Expected.

* Headers.cmake: Removed SuccessOr.h.
* WebCore.xcodeproj/project.pbxproj: Ditto.

* dom/SuccessOr.h: Emptied out this file for now; delete later.

* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::canTransitionFromAutoplayToPlay const): Use
Expected for the return type and call makeUnexpected as needed. Also
updated the check of the result from playbackStateChangePermitted to
call Expected::error instead of SuccessOr::value.
(WebCore::HTMLMediaElement::setReadyState): Use Expected::error
instead of SuccessOr::value, and updated local variable name for
greater clarity. Also fixed one call site that had the success check
backwards: The symptom is that it would never log "Autoplay blocked"
in that case, but otherwise seems harmless.
(WebCore::HTMLMediaElement::play): Ditto.

* html/HTMLMediaElement.h: Use Expected for the return type of
canTransitionFromAutoplayToPlay.

* html/MediaElementSession.cpp:
(WebCore::MediaElementSession::playbackStateChangePermitted const): Use
Expected for the return type and call makeUnexpected as needed.

* html/MediaElementSession.h: Removed include of SuccessOr.h, and
tweaked coding style a bit. Use Expected for the return type of
playbackStateChangePermitted.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (278496 => 278497)


--- trunk/Source/WebCore/ChangeLog	2021-06-04 20:41:45 UTC (rev 278496)
+++ trunk/Source/WebCore/ChangeLog	2021-06-04 21:04:14 UTC (rev 278497)
@@ -1,3 +1,44 @@
+2021-06-03  Darin Adler  <da...@apple.com>
+
+        Move from WebCore::SuccessOr to WTF::Expected
+        https://bugs.webkit.org/show_bug.cgi?id=226614
+
+        Reviewed by Sam Weinig.
+
+        The upcoming std::expected is designed for cases like the ones we
+        are using SuccessOr for, using void for the expected type in a case like
+        this where it's success or failure. Our WTF::Expected is for our use
+        while waiting for compilers with std::expected. It was straightforward
+        to port our uses of SuccessOr to instead use Expected.
+
+        * Headers.cmake: Removed SuccessOr.h.
+        * WebCore.xcodeproj/project.pbxproj: Ditto.
+
+        * dom/SuccessOr.h: Emptied out this file for now; delete later.
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::canTransitionFromAutoplayToPlay const): Use
+        Expected for the return type and call makeUnexpected as needed. Also
+        updated the check of the result from playbackStateChangePermitted to
+        call Expected::error instead of SuccessOr::value.
+        (WebCore::HTMLMediaElement::setReadyState): Use Expected::error
+        instead of SuccessOr::value, and updated local variable name for
+        greater clarity. Also fixed one call site that had the success check
+        backwards: The symptom is that it would never log "Autoplay blocked"
+        in that case, but otherwise seems harmless.
+        (WebCore::HTMLMediaElement::play): Ditto.
+
+        * html/HTMLMediaElement.h: Use Expected for the return type of
+        canTransitionFromAutoplayToPlay.
+
+        * html/MediaElementSession.cpp:
+        (WebCore::MediaElementSession::playbackStateChangePermitted const): Use
+        Expected for the return type and call makeUnexpected as needed.
+
+        * html/MediaElementSession.h: Removed include of SuccessOr.h, and
+        tweaked coding style a bit. Use Expected for the return type of
+        playbackStateChangePermitted.
+
 2021-06-04  Ryosuke Niwa  <rn...@webkit.org>
 
         Store MediaPlayer using WeakPtr in MediaPlayerPrivateRemote

Modified: trunk/Source/WebCore/Headers.cmake (278496 => 278497)


--- trunk/Source/WebCore/Headers.cmake	2021-06-04 20:41:45 UTC (rev 278496)
+++ trunk/Source/WebCore/Headers.cmake	2021-06-04 21:04:14 UTC (rev 278497)
@@ -525,7 +525,6 @@
     dom/SpaceSplitString.h
     dom/StaticRange.h
     dom/StyledElement.h
-    dom/SuccessOr.h
     dom/TaskSource.h
     dom/Text.h
     dom/TextEvent.h

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (278496 => 278497)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-06-04 20:41:45 UTC (rev 278496)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-06-04 21:04:14 UTC (rev 278497)
@@ -4297,7 +4297,6 @@
 		C6F0900A14327B6100685849 /* MutationCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = C6F0900114327B6100685849 /* MutationCallback.h */; };
 		C6F0900F14327B6100685849 /* MutationObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = C6F0900614327B6100685849 /* MutationObserver.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		C6F0902D14327D4F00685849 /* JSMutationObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = C6F0902514327D4F00685849 /* JSMutationObserver.h */; };
-		C99058131E32C75F0073BDDA /* SuccessOr.h in Headers */ = {isa = PBXBuildFile; fileRef = C99058121E32B7340073BDDA /* SuccessOr.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		C9D467051E60C465008195FB /* AutoplayEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = C9D467041E60C3EB008195FB /* AutoplayEvent.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		CA3A4AAF25416E40006CDAE2 /* ImageResolution.h in Headers */ = {isa = PBXBuildFile; fileRef = CA3A4AAD25416E3E006CDAE2 /* ImageResolution.h */; };
 		CA3BF67E10D99BAE00E6CE53 /* ScrollAnimator.h in Headers */ = {isa = PBXBuildFile; fileRef = CA3BF67D10D99BAE00E6CE53 /* ScrollAnimator.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -14848,7 +14847,6 @@
 		C6F0902414327D4F00685849 /* JSMutationObserver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSMutationObserver.cpp; sourceTree = "<group>"; };
 		C6F0902514327D4F00685849 /* JSMutationObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSMutationObserver.h; sourceTree = "<group>"; };
 		C6F0917E143A2BB900685849 /* JSMutationObserverCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSMutationObserverCustom.cpp; sourceTree = "<group>"; };
-		C99058121E32B7340073BDDA /* SuccessOr.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SuccessOr.h; sourceTree = "<group>"; };
 		C9D467041E60C3EB008195FB /* AutoplayEvent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AutoplayEvent.h; sourceTree = "<group>"; };
 		CA091D8623CF907800AD4346 /* StyleImageSet.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = StyleImageSet.cpp; sourceTree = "<group>"; };
 		CA091D8923CF908800AD4346 /* StyleImageSet.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StyleImageSet.h; sourceTree = "<group>"; };
@@ -30911,7 +30909,6 @@
 				81AC6C34131C57C20009A7E0 /* StringCallback.idl */,
 				A8C4A7EC09D563270003AC8D /* StyledElement.cpp */,
 				A8C4A7EB09D563270003AC8D /* StyledElement.h */,
-				C99058121E32B7340073BDDA /* SuccessOr.h */,
 				463EB6201B8789CB0096ED51 /* TagCollection.cpp */,
 				463EB6211B8789CB0096ED51 /* TagCollection.h */,
 				9B0ABCAC236BB40A00B45085 /* TaskSource.h */,
@@ -35455,7 +35452,6 @@
 				659A7D130B6DB4D9001155B3 /* SubstituteData.h in Headers */,
 				1A8F6B020DB53006001DB794 /* SubstituteResource.h in Headers */,
 				5778BD821DA4806C009E3009 /* SubtleCrypto.h in Headers */,
-				C99058131E32C75F0073BDDA /* SuccessOr.h in Headers */,
 				93B2D8160F9920D2006AE6B2 /* SuddenTermination.h in Headers */,
 				97C078501165D5BE003A32EF /* SuffixTree.h in Headers */,
 				97627B9814FB5424002CDCA1 /* Supplementable.h in Headers */,

Modified: trunk/Source/WebCore/dom/SuccessOr.h (278496 => 278497)


--- trunk/Source/WebCore/dom/SuccessOr.h	2021-06-04 20:41:45 UTC (rev 278496)
+++ trunk/Source/WebCore/dom/SuccessOr.h	2021-06-04 21:04:14 UTC (rev 278497)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -25,17 +25,4 @@
 
 #pragma once
 
-#include <optional>
-
-namespace WebCore {
-
-// FIXME: This is used in two places. We should switch them to WTF::Expected and delete this.
-template<typename T> class SuccessOr : public std::optional<T> {
-public:
-    SuccessOr() : std::optional<T>() { }
-    SuccessOr(T&& error) : std::optional<T>(error) { }
-
-    explicit constexpr operator bool() const { return !std::optional<T>::operator bool(); }
-};
-
-} // namespace WebCore
+// Nothing here any more. No need to include it. We plan to delete this header.

Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (278496 => 278497)


--- trunk/Source/WebCore/html/HTMLMediaElement.cpp	2021-06-04 20:41:45 UTC (rev 278496)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp	2021-06-04 21:04:14 UTC (rev 278497)
@@ -2321,41 +2321,41 @@
     endProcessingMediaPlayerCallback();
 }
 
-SuccessOr<MediaPlaybackDenialReason> HTMLMediaElement::canTransitionFromAutoplayToPlay() const
+Expected<void, MediaPlaybackDenialReason> HTMLMediaElement::canTransitionFromAutoplayToPlay() const
 {
     if (m_readyState != HAVE_ENOUGH_DATA) {
         ALWAYS_LOG(LOGIDENTIFIER, "m_readyState != HAVE_ENOUGH_DATA");
-        return MediaPlaybackDenialReason::PageConsentRequired;
+        return makeUnexpected(MediaPlaybackDenialReason::PageConsentRequired);
     }
     if (!isAutoplaying()) {
         ALWAYS_LOG(LOGIDENTIFIER, "!isAutoplaying");
-        return MediaPlaybackDenialReason::PageConsentRequired;
+        return makeUnexpected(MediaPlaybackDenialReason::PageConsentRequired);
     }
     if (!mediaSession().autoplayPermitted()) {
         ALWAYS_LOG(LOGIDENTIFIER, "!mediaSession().autoplayPermitted");
-        return MediaPlaybackDenialReason::PageConsentRequired;
+        return makeUnexpected(MediaPlaybackDenialReason::PageConsentRequired);
     }
     if (!paused()) {
         ALWAYS_LOG(LOGIDENTIFIER, "!paused");
-        return MediaPlaybackDenialReason::PageConsentRequired;
+        return makeUnexpected(MediaPlaybackDenialReason::PageConsentRequired);
     }
     if (!autoplay()) {
         ALWAYS_LOG(LOGIDENTIFIER, "!autoplay");
-        return MediaPlaybackDenialReason::PageConsentRequired;
+        return makeUnexpected(MediaPlaybackDenialReason::PageConsentRequired);
     }
     if (pausedForUserInteraction()) {
         ALWAYS_LOG(LOGIDENTIFIER, "pausedForUserInteraction");
-        return MediaPlaybackDenialReason::PageConsentRequired;
+        return makeUnexpected(MediaPlaybackDenialReason::PageConsentRequired);
     }
     if (document().isSandboxed(SandboxAutomaticFeatures)) {
         ALWAYS_LOG(LOGIDENTIFIER, "isSandboxed");
-        return MediaPlaybackDenialReason::PageConsentRequired;
+        return makeUnexpected(MediaPlaybackDenialReason::PageConsentRequired);
     }
 
     auto permitted = mediaSession().playbackStateChangePermitted(MediaPlaybackState::Playing);
 #if !RELEASE_LOG_DISABLED
     if (!permitted)
-        ALWAYS_LOG(LOGIDENTIFIER, permitted.value());
+        ALWAYS_LOG(LOGIDENTIFIER, permitted.error());
     else
         ALWAYS_LOG(LOGIDENTIFIER, "can transition!");
 #endif
@@ -2470,8 +2470,8 @@
 
         scheduleEvent(eventNames().canplaythroughEvent);
 
-        auto success = canTransitionFromAutoplayToPlay();
-        if (success) {
+        auto canTransition = canTransitionFromAutoplayToPlay();
+        if (canTransition) {
             m_paused = false;
             setShowPosterFlag(false);
             invalidateCachedTime();
@@ -2478,7 +2478,7 @@
             setAutoplayEventPlaybackState(AutoplayEventPlaybackState::StartedWithoutUserGesture);
             m_playbackStartedTime = currentMediaTime().toDouble();
             scheduleEvent(eventNames().playEvent);
-        } else if (success.value() == MediaPlaybackDenialReason::UserGestureRequired) {
+        } else if (canTransition.error() == MediaPlaybackDenialReason::UserGestureRequired) {
             ALWAYS_LOG(LOGIDENTIFIER, "Autoplay blocked, user gesture required");
             setAutoplayEventPlaybackState(AutoplayEventPlaybackState::PreventedAutoplay);
         }
@@ -2488,7 +2488,7 @@
     // honoring any playback denial reasons such as the requirement of a user gesture.
     if (m_readyState == HAVE_FUTURE_DATA && oldState < HAVE_FUTURE_DATA && potentiallyPlaying() && !mediaSession().playbackStateChangePermitted(MediaPlaybackState::Playing)) {
         auto canTransition = canTransitionFromAutoplayToPlay();
-        if (canTransition && canTransition.value() == MediaPlaybackDenialReason::UserGestureRequired)
+        if (!canTransition && canTransition.error() == MediaPlaybackDenialReason::UserGestureRequired)
             ALWAYS_LOG(LOGIDENTIFIER, "Autoplay blocked, user gesture required");
 
         pauseInternal();
@@ -3475,11 +3475,11 @@
 {
     ALWAYS_LOG(LOGIDENTIFIER);
 
-    auto success = mediaSession().playbackStateChangePermitted(MediaPlaybackState::Playing);
-    if (!success) {
-        if (success.value() == MediaPlaybackDenialReason::UserGestureRequired)
+    auto permitted = mediaSession().playbackStateChangePermitted(MediaPlaybackState::Playing);
+    if (!permitted) {
+        if (permitted.error() == MediaPlaybackDenialReason::UserGestureRequired)
             setAutoplayEventPlaybackState(AutoplayEventPlaybackState::PreventedAutoplay);
-        ERROR_LOG(LOGIDENTIFIER, "rejecting promise: ", success.value());
+        ERROR_LOG(LOGIDENTIFIER, "rejecting promise: ", permitted.error());
         promise.reject(NotAllowedError);
         return;
     }
@@ -3501,10 +3501,10 @@
 {
     ALWAYS_LOG(LOGIDENTIFIER);
 
-    auto success = mediaSession().playbackStateChangePermitted(MediaPlaybackState::Playing);
-    if (!success) {
-        ERROR_LOG(LOGIDENTIFIER, "playback not permitted: ", success.value());
-        if (success.value() == MediaPlaybackDenialReason::UserGestureRequired)
+    auto permitted = mediaSession().playbackStateChangePermitted(MediaPlaybackState::Playing);
+    if (!permitted) {
+        ERROR_LOG(LOGIDENTIFIER, "playback not permitted: ", permitted.error());
+        if (permitted.error() == MediaPlaybackDenialReason::UserGestureRequired)
             setAutoplayEventPlaybackState(AutoplayEventPlaybackState::PreventedAutoplay);
         return;
     }

Modified: trunk/Source/WebCore/html/HTMLMediaElement.h (278496 => 278497)


--- trunk/Source/WebCore/html/HTMLMediaElement.h	2021-06-04 20:41:45 UTC (rev 278496)
+++ trunk/Source/WebCore/html/HTMLMediaElement.h	2021-06-04 21:04:14 UTC (rev 278497)
@@ -818,7 +818,7 @@
     bool pausedForUserInteraction() const;
     bool couldPlayIfEnoughData() const;
     void dispatchPlayPauseEventsIfNeedsQuirks();
-    SuccessOr<MediaPlaybackDenialReason> canTransitionFromAutoplayToPlay() const;
+    Expected<void, MediaPlaybackDenialReason> canTransitionFromAutoplayToPlay() const;
 
     void setAutoplayEventPlaybackState(AutoplayEventPlaybackState);
     void userDidInterfereWithAutoplay();

Modified: trunk/Source/WebCore/html/MediaElementSession.cpp (278496 => 278497)


--- trunk/Source/WebCore/html/MediaElementSession.cpp	2021-06-04 20:41:45 UTC (rev 278496)
+++ trunk/Source/WebCore/html/MediaElementSession.cpp	2021-06-04 21:04:14 UTC (rev 278497)
@@ -327,12 +327,12 @@
     m_restrictions &= ~restriction;
 }
 
-SuccessOr<MediaPlaybackDenialReason> MediaElementSession::playbackStateChangePermitted(MediaPlaybackState state) const
+Expected<void, MediaPlaybackDenialReason> MediaElementSession::playbackStateChangePermitted(MediaPlaybackState state) const
 {
     INFO_LOG(LOGIDENTIFIER, "state = ", state);
     if (m_element.isSuspended()) {
         ALWAYS_LOG(LOGIDENTIFIER, "Returning FALSE because element is suspended");
-        return MediaPlaybackDenialReason::InvalidState;
+        return makeUnexpected(MediaPlaybackDenialReason::InvalidState);
     }
 
     auto& document = m_element.document();
@@ -339,7 +339,7 @@
     auto* page = document.page();
     if (!page || page->mediaPlaybackIsSuspended()) {
         ALWAYS_LOG(LOGIDENTIFIER, "Returning FALSE because media playback is suspended");
-        return MediaPlaybackDenialReason::PageConsentRequired;
+        return makeUnexpected(MediaPlaybackDenialReason::PageConsentRequired);
     }
 
     if (document.isMediaDocument() && !document.ownerElement())
@@ -350,7 +350,7 @@
 
     if (requiresFullscreenForVideoPlayback() && !fullscreenPermitted()) {
         ALWAYS_LOG(LOGIDENTIFIER, "Returning FALSE because of fullscreen restriction");
-        return MediaPlaybackDenialReason::FullscreenRequired;
+        return makeUnexpected(MediaPlaybackDenialReason::FullscreenRequired);
     }
 
     if (m_restrictions & OverrideUserGestureRequirementForMainContent && updateIsMainContent())
@@ -372,7 +372,7 @@
         && !m_element.paused() && state == MediaPlaybackState::Paused
         && !document.processingUserGestureForMedia()) {
         ALWAYS_LOG(LOGIDENTIFIER, "Returning FALSE because a quirk requires a user gesture to pause while in Picture-in-Picture");
-        return MediaPlaybackDenialReason::UserGestureRequired;
+        return makeUnexpected(MediaPlaybackDenialReason::UserGestureRequired);
     }
 
     if (topDocument.mediaState() & MediaProducer::MediaState::HasUserInteractedWithMediaElement && topDocument.quirks().needsPerDocumentAutoplayBehavior())
@@ -383,17 +383,17 @@
 
     if (m_restrictions & RequireUserGestureForVideoRateChange && m_element.isVideo() && !document.processingUserGestureForMedia()) {
         ALWAYS_LOG(LOGIDENTIFIER, "Returning FALSE because a user gesture is required for video rate change restriction");
-        return MediaPlaybackDenialReason::UserGestureRequired;
+        return makeUnexpected(MediaPlaybackDenialReason::UserGestureRequired);
     }
 
     if (m_restrictions & RequireUserGestureForAudioRateChange && (!m_element.isVideo() || m_element.hasAudio()) && !m_element.muted() && m_element.volume() && !document.processingUserGestureForMedia()) {
         ALWAYS_LOG(LOGIDENTIFIER, "Returning FALSE because a user gesture is required for audio rate change restriction");
-        return MediaPlaybackDenialReason::UserGestureRequired;
+        return makeUnexpected(MediaPlaybackDenialReason::UserGestureRequired);
     }
 
     if (m_restrictions & RequireUserGestureForVideoDueToLowPowerMode && m_element.isVideo() && !document.processingUserGestureForMedia()) {
         ALWAYS_LOG(LOGIDENTIFIER, "Returning FALSE because of video low power mode restriction");
-        return MediaPlaybackDenialReason::UserGestureRequired;
+        return makeUnexpected(MediaPlaybackDenialReason::UserGestureRequired);
     }
 
     return { };

Modified: trunk/Source/WebCore/html/MediaElementSession.h (278496 => 278497)


--- trunk/Source/WebCore/html/MediaElementSession.h	2021-06-04 20:41:45 UTC (rev 278496)
+++ trunk/Source/WebCore/html/MediaElementSession.h	2021-06-04 21:04:14 UTC (rev 278497)
@@ -31,26 +31,15 @@
 #include "MediaProducer.h"
 #include "MediaUsageInfo.h"
 #include "PlatformMediaSession.h"
-#include "SuccessOr.h"
 #include "Timer.h"
+#include <memory>
 #include <wtf/TypeCasts.h>
 
-#if ENABLE(MEDIA_SESSION)
-#include <memory>
-#endif
-
 namespace WebCore {
 
-enum class MediaSessionMainContentPurpose {
-    MediaControls,
-    Autoplay
-};
+enum class MediaSessionMainContentPurpose { MediaControls, Autoplay };
+enum class MediaPlaybackState { Playing, Paused };
 
-enum class MediaPlaybackState {
-    Playing,
-    Paused
-};
-
 enum class MediaPlaybackDenialReason {
     UserGestureRequired,
     FullscreenRequired,
@@ -61,14 +50,15 @@
 class Document;
 class HTMLMediaElement;
 class MediaMetadata;
-struct MediaPositionState;
 class MediaSession;
 class MediaSessionObserver;
 class SourceBuffer;
+
+struct MediaPositionState;
+
 enum class MediaSessionPlaybackState : uint8_t;
 
-class MediaElementSession final : public PlatformMediaSession
-{
+class MediaElementSession final : public PlatformMediaSession {
     WTF_MAKE_FAST_ALLOCATED;
 public:
     explicit MediaElementSession(HTMLMediaElement&);
@@ -85,7 +75,7 @@
     void isVisibleInViewportChanged();
     void inActiveDocumentChanged();
 
-    SuccessOr<MediaPlaybackDenialReason> playbackStateChangePermitted(MediaPlaybackState) const;
+    Expected<void, MediaPlaybackDenialReason> playbackStateChangePermitted(MediaPlaybackState) const;
     bool autoplayPermitted() const;
     bool dataLoadingPermitted() const;
     MediaPlayer::BufferingPolicy preferredBufferingPolicy() const;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to